farm_asset.module in farmOS 7
Farm asset - A farm asset entity type.
File
modules/farm/farm_asset/farm_asset.moduleView source
<?php
/**
* @file
* Farm asset - A farm asset entity type.
*/
/****************************************************************
* Drupal hooks
* **************************************************************/
/**
* Implements hook_init().
*/
function farm_asset_init() {
global $conf;
// If the pathauto_entity module is enabled, ensure that farm_asset entities
// are enabled in it.
if (module_exists('pathauto_entity')) {
if (empty($conf['pathauto_entity_available_entity_types'])) {
$conf['pathauto_entity_available_entity_types'] = array();
}
$conf['pathauto_entity_available_entity_types']['farm_asset'] = 'farm_asset';
}
}
/**
* Implements hook_permission().
*/
function farm_asset_permission() {
$perms = array(
'administer farm_asset module' => array(
'title' => t('Administer farm asset module'),
'description' => t('Gives full access to everything in the farm asset module.'),
'restrict access' => TRUE,
),
'administer farm_asset types' => array(
'title' => t('Administer farm asset types'),
'restrict access' => TRUE,
),
'view farm assets' => array(
'title' => t('View farm assets'),
'description' => t('Allows users to view the full list of farm assets.'),
),
);
// Add permissions for each farm_asset type.
foreach (farm_asset_types() as $farm_asset_type) {
$type = $farm_asset_type->type;
$ops = array(
'view',
'edit',
'delete',
);
$scopes = array(
'any',
'own',
);
$perms += array(
"create {$type} farm assets" => array(
'title' => t('Create new %type_name farm assets', array(
'%type_name' => $farm_asset_type->label,
)),
),
);
foreach ($ops as $op) {
foreach ($scopes as $scope) {
$perms += array(
"{$op} {$scope} {$type} farm assets" => array(
'title' => drupal_ucfirst($op) . ' ' . $scope . ' ' . t('%type_name farm assets', array(
'%type_name' => $farm_asset_type->label,
)),
),
);
}
}
}
return $perms;
}
/**
* Implements hook_menu().
*/
function farm_asset_menu() {
$items = array();
$items['farm/asset/add'] = array(
'title' => 'Add asset',
'page callback' => 'farm_asset_add_types_page',
'access callback' => 'farm_asset_add_access',
'file' => 'farm_asset.pages.inc',
);
foreach (farm_asset_types() as $type => $info) {
$items['farm/asset/add/' . $type] = array(
'title' => 'Add ' . $info->label,
'page callback' => 'farm_asset_add',
'page arguments' => array(
3,
),
'access callback' => 'farm_asset_access',
'access arguments' => array(
'create',
3,
),
'file' => 'farm_asset.pages.inc',
);
}
$farm_asset_uri = 'farm/asset/%farm_asset';
$farm_asset_uri_argument_position = 2;
$items[$farm_asset_uri] = array(
'title callback' => 'entity_label',
'title arguments' => array(
'farm_asset',
$farm_asset_uri_argument_position,
),
'page callback' => 'farm_asset_view',
'page arguments' => array(
$farm_asset_uri_argument_position,
),
'access callback' => 'farm_asset_access',
'access arguments' => array(
'view',
$farm_asset_uri_argument_position,
),
'file' => 'farm_asset.pages.inc',
);
$items[$farm_asset_uri . '/view'] = array(
'title' => 'View',
'type' => MENU_DEFAULT_LOCAL_TASK,
'weight' => -10,
);
$items[$farm_asset_uri . '/delete'] = array(
'title' => 'Delete asset',
'title callback' => 'farm_asset_label',
'title arguments' => array(
$farm_asset_uri_argument_position,
),
'page callback' => 'drupal_get_form',
'page arguments' => array(
'farm_asset_delete_form',
$farm_asset_uri_argument_position,
),
'access callback' => 'farm_asset_access',
'access arguments' => array(
'update',
$farm_asset_uri_argument_position,
),
'file' => 'farm_asset.pages.inc',
);
$items[$farm_asset_uri . '/edit'] = array(
'title' => 'Edit',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'farm_asset_form',
$farm_asset_uri_argument_position,
),
'access callback' => 'farm_asset_access',
'access arguments' => array(
'update',
$farm_asset_uri_argument_position,
),
'file' => 'farm_asset.pages.inc',
'type' => MENU_LOCAL_TASK,
'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
);
// Asset type delete form.
$items['admin/config/farm/asset-types/%farm_asset_type/delete'] = array(
'title' => 'Delete',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'farm_asset_type_form_delete_confirm',
4,
),
'access arguments' => array(
'administer farm_asset types',
),
'weight' => 1,
'type' => MENU_NORMAL_ITEM,
'file' => 'farm_asset.admin.inc',
);
// Asset autocomplete path.
$items['farm_asset/autocomplete/%/%'] = array(
'title' => 'Autocomplete for farm assets',
'page callback' => 'farm_asset_autocomplete',
'page arguments' => array(
2,
3,
),
'access callback' => 'farm_asset_autocomplete_access',
'access arguments' => array(
2,
),
'type' => MENU_CALLBACK,
);
return $items;
}
/**
* Implements hook_entity_info().
*/
function farm_asset_entity_info() {
$return = array(
'farm_asset' => array(
'label' => t('Farm asset'),
'entity class' => 'FarmAsset',
'controller class' => 'FarmAssetController',
'base table' => 'farm_asset',
'fieldable' => TRUE,
'entity keys' => array(
'id' => 'id',
'bundle' => 'type',
'label' => 'name',
),
'bundle keys' => array(
'bundle' => 'type',
),
'bundles' => array(),
'load hook' => 'farm_asset_load',
'view modes' => array(
'full' => array(
'label' => t('Default'),
'custom settings' => FALSE,
),
),
'label callback' => 'entity_class_label',
'uri callback' => 'entity_class_uri',
'module' => 'farm_asset',
'access callback' => 'farm_asset_access',
),
);
$return['farm_asset_type'] = array(
'label' => t('Farm asset type'),
'entity class' => 'FarmAssetType',
'controller class' => 'FarmAssetTypeController',
'base table' => 'farm_asset_type',
'fieldable' => FALSE,
'bundle of' => 'farm_asset',
'exportable' => TRUE,
'entity keys' => array(
'id' => 'id',
'name' => 'type',
'label' => 'label',
),
'module' => 'farm_asset',
// Enable the entity API admin UI.
'admin ui' => array(
'path' => 'admin/config/farm/asset-types',
'file' => 'farm_asset.admin.inc',
'controller class' => 'FarmAssetTypeUIController',
),
'access callback' => 'farm_asset_type_access',
);
return $return;
}
/**
* Implements hook_entity_info_alter().
*/
function farm_asset_entity_info_alter(&$entity_info) {
foreach (farm_asset_types() as $type => $info) {
$entity_info['farm_asset']['bundles'][$type] = array(
'label' => $info->label,
'admin' => array(
'path' => 'admin/config/farm/asset-types/manage/%farm_asset_type',
'real path' => 'admin/config/farm/asset-types/manage/' . $type,
'bundle argument' => 5,
),
);
}
}
/**
* Implements hook_entity_property_info_alter().
*/
function farm_asset_entity_property_info_alter(&$info) {
$properties =& $info['farm_asset']['properties'];
$properties['name'] = array(
'label' => t('Name'),
'description' => t('The name of the asset.'),
'setter callback' => 'entity_property_verbatim_set',
'schema field' => 'name',
);
$properties['type'] = array(
'label' => t('Farm asset type'),
'type' => 'token',
'description' => t('The farm asset type.'),
'setter callback' => 'entity_property_verbatim_set',
'access callback' => 'farm_asset_properties_access',
'options list' => 'farm_asset_type_get_names',
'required' => TRUE,
'schema field' => 'type',
);
$properties['uid'] = array(
'label' => t('Author'),
'type' => 'user',
'description' => t('The author of the asset.'),
'setter callback' => 'entity_property_verbatim_set',
'access callback' => 'farm_asset_properties_access',
'required' => TRUE,
'schema field' => 'uid',
);
$properties['created'] = array(
'label' => t('Created'),
'type' => 'date',
'description' => t('The timestamp when the asset was created.'),
'setter callback' => 'entity_property_verbatim_set',
'access callback' => 'farm_asset_properties_access',
'required' => TRUE,
'schema field' => 'created',
);
$properties['changed'] = array(
'label' => t('Changed'),
'type' => 'date',
'description' => t('The timestamp when the asset was last modified.'),
'setter callback' => 'entity_property_verbatim_set',
'access callback' => 'farm_asset_properties_access',
'required' => TRUE,
'schema field' => 'changed',
);
$properties['archived'] = array(
'label' => t('Archived'),
'type' => 'date',
'description' => t('The timestamp when the asset was archived.'),
'setter callback' => 'entity_property_verbatim_set',
'access callback' => 'farm_asset_properties_access',
'schema field' => 'archived',
);
}
/**
* Implements hook_field_extra_fields().
*/
function farm_asset_field_extra_fields() {
$farm_asset_types = farm_asset_types();
$extra_fields = array(
'farm_asset' => array(),
);
foreach ($farm_asset_types as $type) {
$extra_fields['farm_asset'][$type->type] = array(
'form' => array(
// Add asset name field to field UI.
'name' => array(
'label' => t('Name'),
'description' => t('The name of the asset.'),
'weight' => -10,
),
),
);
}
return $extra_fields;
}
/**
* Implements hook_entity_view().
*/
function farm_asset_entity_view($entity, $type, $view_mode, $langcode) {
// If the entity is not a farm_asset, bail.
if ($type != 'farm_asset') {
return;
}
// Add the asset type.
$asset_types = farm_asset_type_get_names();
if (!empty($asset_types[$entity->type])) {
$entity->content['type'] = array(
'#markup' => '<div><strong>' . t('Asset type:') . '</strong> ' . $asset_types[$entity->type] . '</div>',
'#weight' => -102,
);
}
// Add the asset ID.
if (!empty($entity->id)) {
$entity->content['id'] = array(
'#markup' => '<div><strong>' . t('Asset ID:') . '</strong> ' . $entity->id . '</div>',
'#weight' => -101,
);
}
// If the asset is archived, display a message and the archived date.
if (!empty($entity->archived)) {
drupal_set_message(t('This asset is archived. Archived assets should not be edited or deleted unless they contain information that is incorrect.'), 'warning');
$date = format_date($entity->archived);
$entity->content['archived'] = array(
'#markup' => '<div><strong>' . t('Archived') . ':</strong> ' . $date . '</div>',
'#weight' => -100,
);
}
}
/**
* Implements hook_entity_presave().
*/
function farm_asset_entity_presave($entity, $type) {
// Only operate on farm_asset entities.
if ($type != 'farm_asset') {
return;
}
// Update "changed" value if there was a value mapped to that.
if (isset($entity->feeds_item->asset_changed)) {
$entity->changed = $entity->feeds_item->asset_changed;
}
}
/**
* Implements hook_action_info().
*/
function farm_asset_action_info() {
return array(
'farm_asset_archive_action' => array(
'type' => 'farm_asset',
'label' => t('Archive'),
'configurable' => FALSE,
'triggers' => array(
'any',
),
),
'farm_asset_unarchive_action' => array(
'type' => 'farm_asset',
'label' => t('Unarchive'),
'configurable' => FALSE,
'triggers' => array(
'any',
),
),
'farm_asset_clone_action' => array(
'type' => 'farm_asset',
'label' => t('Clone'),
'configurable' => FALSE,
'triggers' => array(
'any',
),
),
);
}
/***************************************************************
* Asset action callbacks
* *************************************************************/
/**
* Action function for farm_asset_archive_action.
*
* Archives an asset.
*
* @param FarmAsset $asset
* The asset entity object.
* @param array $context
* Array with parameters for this action.
*/
function farm_asset_archive_action(FarmAsset $asset, $context = array()) {
// Only proceed if the asset is not already archived.
if (!empty($asset->archived)) {
return;
}
// Archive the asset.
$asset->archived = REQUEST_TIME;
// Save the asset.
farm_asset_save($asset);
}
/**
* Action function for farm_asset_unarchive_action.
*
* Un-archives an asset.
*
* @param FarmAsset $asset
* The asset entity object.
* @param array $context
* Array with parameters for this action.
*/
function farm_asset_unarchive_action(FarmAsset $asset, $context = array()) {
// Only proceed if the asset is already archived.
if (empty($asset->archived)) {
return;
}
// Un-archive the asset..
$asset->archived = 0;
// Save the asset.
farm_asset_save($asset);
}
/**
* Action function for farm_asset_clone_action.
*
* Clones an asset.
*
* @param FarmAsset $asset
* The asset entity object.
* @param array $context
* Array with parameters for this action.
*/
function farm_asset_clone_action(FarmAsset $asset, $context = array()) {
// Remember the asset ID.
$asset_id = $asset->id;
// Add "(clone of asset #[asset-id])" to the end of the asset's name.
$asset->name = $asset->name . ' ' . t('(clone of asset #@id)', array(
'@id' => $asset_id,
));
// Clear the asset ID.
unset($asset->id);
// Set the created and changed timestamps to now.
$asset->created = REQUEST_TIME;
$asset->changed = REQUEST_TIME;
// Save the asset.
farm_asset_save($asset);
// Set a message with a link to the new asset.
$asset_uri = entity_uri('farm_asset', $asset);
$asset_label = entity_label('farm_asset', $asset);
$message = t('Asset saved: <a href="@uri">%title</a>', array(
'@uri' => url($asset_uri['path']),
'%title' => $asset_label,
));
drupal_set_message($message);
}
/****************************************************************
* Contrib hooks
* **************************************************************/
/**
* Implements hook_ctools_plugin_api().
*/
function farm_asset_ctools_plugin_api($owner, $api) {
$return = array();
if ($owner == 'feeds' && $api == 'plugins') {
$return['version'] = 1;
}
return $return;
}
/**
* Implements hook_ctools_plugin_directory().
*/
function farm_asset_ctools_plugin_directory($owner, $plugin_type) {
$directory = '';
if ($owner == 'page_manager' || $owner == 'ctools' || $owner == 'panels') {
if ($plugin_type == 'tasks') {
$directory = 'includes/ctools';
}
}
return $directory;
}
/**
* Implements hook_feed_plugins().
*/
function farm_asset_feeds_plugins() {
$info = array();
$info['FarmAssetProcessor'] = array(
'name' => 'Farm asset processor',
'description' => 'Create and update farm assets.',
'help' => 'Create and update farm assets from parsed content.',
'handler' => array(
'parent' => 'FeedsProcessor',
'class' => 'FarmAssetProcessor',
'file' => 'FarmAssetProcessor.inc',
'path' => drupal_get_path('module', 'farm_asset') . '/includes/feeds/plugins',
),
);
return $info;
}
/**
* Implements hook_views_api().
*/
function farm_asset_views_api($module = NULL, $api = NULL) {
return array(
"api" => "3.0",
);
}
/***************************************************************
* Access functions
* *************************************************************/
/**
* Access callback for asset entities.
*
* @param string $op
* The operation being performed. One of 'view', 'update', 'create', 'delete'.
* @param FarmAsset|string $farm_asset
* Optionally a specific asset entity to check.
* @param object $account
* The user to check for. Leave it to NULL to check for the global user.
*
* @return bool
* Whether access is allowed or not.
*/
function farm_asset_access($op, $farm_asset = NULL, $account = NULL) {
$rights =& drupal_static(__FUNCTION__, array());
// If $op is not one of the supported ones, deny access.
if (!in_array($op, array(
'create',
'view',
'update',
'delete',
), TRUE)) {
return FALSE;
}
// If no user object is supplied, the access check is for the current user.
if (empty($account)) {
global $user;
$account = $user;
}
// If no asset is provided, check for access to all assets.
if (empty($farm_asset)) {
return user_access('view farm assets', $account);
}
// $farm_asset may be either an object or an asset type. Since asset types
// cannot be an integer, use either id or type as the static cache id.
$cid = is_object($farm_asset) ? $farm_asset->id : $farm_asset;
// If we've already checked access for this asset, user and op, return from
// cache.
if (isset($rights[$account->uid][$cid][$op])) {
return $rights[$account->uid][$cid][$op];
}
// If the user has 'administer farm_asset module' permission, grant them
// access.
if (user_access('administer farm_asset module', $account)) {
$rights[$account->uid][$cid][$op] = TRUE;
return TRUE;
}
// Check access to the asset based on it's type.
$type = is_string($farm_asset) ? $farm_asset : $farm_asset->type;
$farm_asset_types = farm_asset_types();
$type_names = array();
foreach ($farm_asset_types as $name => $farm_asset_type) {
$type_names[] = $name;
}
if (in_array($type, $type_names)) {
if ($op == 'create' && user_access('create ' . $type . ' farm assets', $account)) {
$rights[$account->uid][$cid][$op] = TRUE;
return TRUE;
}
if ($op == 'view') {
if (user_access('view any ' . $type . ' farm assets', $account) || user_access('view own ' . $type . ' farm assets', $account) && $account->uid == $farm_asset->uid) {
$rights[$account->uid][$cid][$op] = TRUE;
return TRUE;
}
}
if ($op == 'update') {
if (user_access('edit any ' . $type . ' farm assets', $account) || user_access('edit own ' . $type . ' farm assets', $account) && $account->uid == $farm_asset->uid) {
$rights[$account->uid][$cid][$op] = TRUE;
return TRUE;
}
}
if ($op == 'delete') {
if (user_access('delete any ' . $type . ' farm assets', $account) || user_access('delete own ' . $type . ' farm assets', $account) && $account->uid == $farm_asset->uid) {
$rights[$account->uid][$cid][$op] = TRUE;
return TRUE;
}
}
}
// If all else fails, deny access.
return FALSE;
}
/**
* Access callback: Checks whether the user has permission to add an asset.
*
* @param object|null $account
* The user account.
*
* @return bool
* TRUE if the user has add permission, otherwise FALSE.
*/
function farm_asset_add_access($account = NULL) {
// If no user object is supplied, the access check is for the current user.
if (empty($account)) {
global $user;
$account = $user;
}
// Check each of the asset types to see if the user has access.
$types = farm_asset_types();
foreach ($types as $type) {
if (farm_asset_access('create', $type->type, $account)) {
return TRUE;
}
}
// If all else fails, deny access.
return FALSE;
}
/**
* Access callback for asset types.
*
* @param string $op
* The operation being performed.
* @param FarmAssetType $farm_asset_type
* The farm asset entity.
*
* @return bool
* Returns true if the user has access.
*/
function farm_asset_type_access($op, FarmAssetType $farm_asset_type = NULL) {
return user_access('administer farm_asset types');
}
/**
* Access callback for the farm_asset autocomplete path.
*
* @param string $asset_type
* The asset type to filter to, or "all" for no filtering.
*
* @return bool
* Returns TRUE or FALSE to grant or deny access to the path.
*/
function farm_asset_autocomplete_access($asset_type) {
if ($asset_type == 'all' || strpos($asset_type, '+') !== FALSE) {
return user_access('view farm assets');
}
return user_access('view any ' . $asset_type . ' farm assets');
}
/**
* Access callback for farm_asset properties.
*/
function farm_asset_properties_access($op, $property, $entity = NULL, $account = NULL) {
// Delegate to the general farm_asset access callback, based on the $op.
switch ($op) {
case 'view':
return farm_asset_access('view', $entity, $account);
case 'edit':
return farm_asset_access('update', $entity, $account);
}
// Otherwise, deny access.
return FALSE;
}
/***************************************************************
* Farm asset page callbacks.
* *************************************************************/
/**
* Page callback for the farm_asset autocomplete path.
*
* @param string $asset_type
* The asset type to filter to. If this is set to 'all' then no filtering
* will be performed. Multiple asset types can be specified as a single
* string, separated by plus characters (+). ie: "animal+group"
* @param string $string
* The text field asset name(s) to search for.
*
* @return array
* Returns an array of matching assets in JSON form.
*/
function farm_asset_autocomplete($asset_type, $string) {
// The user enters a comma-separated list of tags. We only autocomplete the last tag.
$tags_typed = drupal_explode_tags($string);
$tag_last = drupal_strtolower(array_pop($tags_typed));
// Search the database for assets with matching names
$query = db_select('farm_asset', 'fa')
->fields('fa', array(
'id',
'name',
'archived',
))
->condition('name', '%' . db_like($tag_last) . '%', 'LIKE')
->orderBy('name', 'ASC')
->range(0, 10);
// If the asset type is not "all", filter by asset type.
if ($asset_type != 'all') {
$asset_types = array();
if (strpos($asset_type, '+') !== FALSE) {
$asset_types = explode('+', $asset_type);
}
else {
$asset_types[] = $asset_type;
}
$query
->condition('type', $asset_types, 'IN');
}
// Execute the query.
$result = $query
->execute();
// Save matches to an array, including the asset name and ID.
$matches = array();
foreach ($result as $row) {
// Generate a prefix of previously matched tags.
$prefix = count($tags_typed) ? drupal_implode_tags($tags_typed) . ', ' : '';
// We use htmlspecialchars() instead of check_plain() to preserve single
// quotes (apostrophes) in asset names.
$match = htmlspecialchars($row->name) . ' [id: ' . $row->id . ']';
if (!empty($row->archived)) {
$match .= ' (' . t('archived') . ')';
}
// Add match to list of matches.
$matches[$prefix . $match] = $match;
}
// Return the matches as JSON.
drupal_json_output($matches);
}
/***************************************************************
* Farm asset API functions
* *************************************************************/
/**
* Load an asset.
*
* @param int $id
* The asset id.
* @param bool $reset
* Whether or not to reset the entity cache.
*
* @return FarmAsset
* Returns a farm asset object.
*/
function farm_asset_load($id, $reset = FALSE) {
$farm_assets = farm_asset_load_multiple(array(
$id,
), array(), $reset);
return reset($farm_assets);
}
/**
* Load multiple assets based on certain conditions.
*
* @param array $ids
* An array of farm asset ids.
* @param array $conditions
* An array of entity load conditions.
* @param bool $reset
* Whether or not to reset the entity cache.
*
* @return array
* Returns an array of farm assets.
*/
function farm_asset_load_multiple($ids = array(), $conditions = array(), $reset = FALSE) {
return entity_load('farm_asset', $ids, $conditions, $reset);
}
/**
* Save asset.
*
* @param FarmAsset $farm_asset
* The farm asset entity.
*/
function farm_asset_save(FarmAsset $farm_asset) {
entity_save('farm_asset', $farm_asset);
}
/**
* Delete single asset.
*
* @param FarmAsset $farm_asset
* The farm asset entity.
*/
function farm_asset_delete(FarmAsset $farm_asset) {
entity_delete('farm_asset', entity_id('farm_asset', $farm_asset));
}
/**
* Delete multiple assets.
*
* @param array $farm_asset_ids
* An array of farm asset ids.
*/
function farm_asset_delete_multiple(array $farm_asset_ids) {
entity_delete_multiple('farm_asset', $farm_asset_ids);
}
/***************************************************************
* Farm asset type API functions
* *************************************************************/
/**
* Load asset type.
*
* @param string $farm_asset_type
* The farm asset type.
*
* @return FarmAssetType
* Returns a farm asset type entity.
*/
function farm_asset_type_load($farm_asset_type) {
return farm_asset_types($farm_asset_type);
}
/**
* List of asset types.
*
* @param string $type_name
* The farm asset type name.
*
* @return FarmAssetType|array
* Returns either a single type, or an array of types.
*/
function farm_asset_types($type_name = NULL) {
$types = entity_load_multiple_by_name('farm_asset_type', isset($type_name) ? array(
$type_name,
) : FALSE);
return isset($type_name) ? reset($types) : $types;
}
/**
* Save asset type entity.
*
* @param FarmAssetType $farm_asset_type
* The farm asset type entity.
*/
function farm_asset_type_save(FarmAssetType $farm_asset_type) {
entity_save('farm_asset_type', $farm_asset_type);
}
/**
* Delete single asset type.
*
* @param FarmAssetType $farm_asset_type
* The farm asset type entity.
*/
function farm_asset_type_delete(FarmAssetType $farm_asset_type) {
entity_delete('farm_asset_type', entity_id('farm_asset_type', $farm_asset_type));
}
/**
* Delete multiple asset types.
*
* @param array $farm_asset_type_ids
* An array of farm asset type ids.
*/
function farm_asset_type_delete_multiple(array $farm_asset_type_ids) {
entity_delete_multiple('farm_asset_type', $farm_asset_type_ids);
}
/**
* Get the names of all asset types.
*
* @return array
* Returns an array of asset type names, keyed by machine name.
*/
function farm_asset_type_get_names() {
$names = array();
$types = farm_asset_types();
foreach ($types as $type) {
$names[$type->type] = $type->label;
}
return $names;
}