| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003 | <?php/** * @file * Replaces entity legacy fields with regular fields. * * Provides an API and a basic UI to replace legacy pseudo-fields with regular * fields. The API only offers synchronization between the two data storage * systems and data replacement on entity load/save. Field definitions have to * be provided by the modules exploiting the API. * * Title implements its own entity description API to describe core legacy * pseudo-fields: * - Node: title * - Taxonomy Term: name, description * - Comment: subject * * @todo: API PHPdocs */module_load_include('inc', 'title', 'title.core');module_load_include('inc', 'title', 'title.field');/** * Implements hook_module_implements_alter(). */function title_module_implements_alter(&$implementations, $hook) {  if (isset($implementations['title'])) {    $group = $implementations['title'];    unset($implementations['title']);    switch ($hook) {      // The following hook implementations should be executed as last ones.      case 'entity_info_alter':      case 'entity_presave':      case 'field_attach_presave':        $implementations['title'] = $group;        break;      // Normally Title needs to act as first module to perform synchronization.      default:        $implementations = array('title' => $group) + $implementations;    }  }}/** * Implements hook_entity_info_alter(). */function title_entity_info_alter(&$info) {  foreach ($info as $entity_type => $entity_info) {    if (!empty($entity_info['fieldable']) && !empty($info[$entity_type]['field replacement'])) {      foreach ($info[$entity_type]['field replacement'] as $legacy_field => $data) {        // Provide defaults for the replacing field name.        $fr_info = &$info[$entity_type]['field replacement'][$legacy_field];        if (empty($fr_info['field']['field_name'])) {          $fr_info['field']['field_name'] = $legacy_field . '_field';        }        $fr_info['instance']['field_name'] = $fr_info['field']['field_name'];        // Provide defaults for the sync callbacks.        $type = $fr_info['field']['type'];        if (empty($fr_info['callbacks'])) {          $fr_info['callbacks'] = array();        }        $fr_info['callbacks'] += array(          'sync_get' => "title_field_{$type}_sync_get",          'sync_set' => "title_field_{$type}_sync_set",        );        // Support add explicit support for entity_label().        if (isset($entity_info['entity keys']['label']) && $entity_info['entity keys']['label'] == $legacy_field) {          // Store the original label callback for compatibility reasons.          if (isset($info[$entity_type]['label callback'])) {            $info[$entity_type]['label fallback']['title'] = $info[$entity_type]['label callback'];          }          $info[$entity_type]['label callback'] = 'title_entity_label';          $fr_info += array('preprocess_key' => $info[$entity_type]['entity keys']['label']);        }      }    }  }}/** * Return field replacement specific information. * * @param $entity_type *   The name of the entity type. * @param $legacy_field *   (Otional) The legacy field name to be replaced. */function title_field_replacement_info($entity_type, $legacy_field = NULL) {  $info = entity_get_info($entity_type);  if (empty($info['field replacement'])) {    return FALSE;  }  if (isset($legacy_field)) {    return isset($info['field replacement'][$legacy_field]) ? $info['field replacement'][$legacy_field] : FALSE;  }  else {    return $info['field replacement'];  }}/** * Return an entity label value. * * @param $entity *   The entity whose label has to be displayed. * @param $type *   The name of the entity type. * @param $langcode *   (Optional) The language the entity label has to be displayed in. * * @return *   The entity label as a string value. */function title_entity_label($entity, $type, $langcode = NULL) {  $entity_info = entity_get_info($type);  $legacy_field = $entity_info['entity keys']['label'];  $info = $entity_info['field replacement'][$legacy_field];  list(, , $bundle) = entity_extract_ids($type, $entity);  // If field replacement is enabled we use the replacing field value.  if (title_field_replacement_enabled($type, $bundle, $legacy_field)) {    $langcode = field_language($type, $entity, $info['field']['field_name'], $langcode);    $values = $info['callbacks']['sync_get']($type, $entity, $legacy_field, $info, $langcode);    return $values[$legacy_field];  }  // Otherwise if we have a fallback defined we use the original label callback.  elseif (isset($entity_info['label fallback']['title']) && function_exists($entity_info['label fallback']['title'])) {    return $entity_info['label fallback']['title']($entity, $type, $langcode);  }  else {    return (property_exists($entity, $legacy_field)) ? $entity->{$legacy_field} : NULL;  }}/** * Implements hook_entity_presave(). */function title_entity_presave($entity, $entity_type) {  $entity_langcode = title_entity_language($entity_type, $entity);  $langcode = $entity_langcode;  // If Entity Translation is enabled and the entity type is transltable,we need  // to check if we have a translation for the current active language. If so we  // need to synchronize the legacy field values into the replacing field  // translations in the active language.  if (module_invoke('entity_translation', 'enabled', $entity_type)) {    $langcode = title_active_language();    $translations = entity_translation_get_handler($entity_type, $entity)->getTranslations();    // If we are removing a translation for the active language we need to skip    // reverse synchronization, as we would store empty values in the original    // replacing fields immediately afterwards.    if (!isset($translations->data[$langcode])) {      $langcode = isset($translations->hook[$langcode]['hook']) && $translations->hook[$langcode]['hook'] == 'delete' ? FALSE : $entity_langcode;    }  }  // Perform reverse synchronization to retain any change in the legacy field  // values. We must avoid doing this twice as we might overwrite the already  // synchronized values, if we are updating an existing entity.  if ($langcode) {    title_entity_sync($entity_type, $entity, $langcode, TRUE);  }  // If we are not dealing with the entity language, we need to synchronize the  // original values into the legacy fields to ensure they are always stored in  // the entity table.  if ($entity_langcode != $langcode) {    list($id, , ) = entity_extract_ids($entity_type, $entity);    $sync = &drupal_static('title_entity_sync', array());    unset($sync[$entity_type][$id]);    title_entity_sync($entity_type, $entity, $entity_langcode);  }}/** * Implements hook_field_attach_update(). */function title_field_attach_update($entity_type, $entity) {  // Reset the field_attach_presave static cache so that subsequent saves work  // correctly.  $sync = &drupal_static('title_field_attach_presave', array());  list($id, , ) = entity_extract_ids($entity_type, $entity);  unset($sync[$entity_type][$id]);  // Immediately after saving the entity we need to ensure that the legacy field  // holds a value corresponding to the current active language, as it were  // just loaded.  title_entity_sync($entity_type, $entity);}/** * Implements hook_field_attach_load(). * * Synchronization must be performed as early as possible to prevent other code * from accessing replaced fields before they get their actual value. * * @see title_entity_load() */function title_field_attach_load($entity_type, $entities, $age, $options) {  // Allow values to re-sync when field_attach_load_revision() is called.  if ($age == FIELD_LOAD_REVISION) {    title_entity_sync_static_reset($entity_type, array_keys($entities));  }  title_entity_load($entities, $entity_type);}/** * Implements hook_entity_load(). * * Since the result of field_attach_load() is cached, synchronization must be * performed also here to ensure that there is always the correct value in the * replaced fields. */function title_entity_load($entities, $type) {  // Load entity translations otherwise field language will not be computed  // correctly.  module_invoke('entity_translation', 'entity_load', $entities, $type);  foreach ($entities as &$entity) {    // Synchronize values from the regular field unless we are intializing it.    title_entity_sync($type, $entity, NULL, !empty($GLOBALS['title_field_replacement_init']));  }}/** * Implements hook_entitycache_load(). * * Entity cache might cache the entire $entity object, in which case * synchronization will not be performed on entity load. */function title_entitycache_load($entities, $type) {  title_entity_load($entities, $type);}/** * Implements hook_entitycache_reset(). * * When the entity cache is reset the field sync has to be done again. */function title_entitycache_reset($ids, $entity_type) {  title_entity_sync_static_reset($entity_type, $ids);}/** * Implements hook_entity_prepare_view(). * * On load synchronization is performed using the current display language. A * different language might be specified while viewing the entity in which case * synchronization must be performed again. */function title_entity_prepare_view($entities, $type, $langcode) {  foreach ($entities as &$entity) {    title_entity_sync($type, $entity, $langcode);  }}/** * Check whether field replacement is enabled for the given field. * * @param $entity_type *   The type of $entity. * @param $bundle *   The bundle the legacy field belongs to. * @param $legacy_field *   The name of the legacy field to be replaced. * * @return *   TRUE if field replacement is enabled for the given field, FALSE otherwise. */function title_field_replacement_enabled($entity_type, $bundle, $legacy_field) {  $info = title_field_replacement_info($entity_type, $legacy_field);  if (!empty($info['field']['field_name'])) {    $instance = field_info_instance($entity_type, $info['field']['field_name'], $bundle);  }  return !empty($instance);}/** * Toggle field replacement for the given field. * * @param $entity_type *   The name of the entity type. * @param $bundle *   The bundle the legacy field belongs to. * @param $legacy_field *   The name of the legacy field to be replaced. */function title_field_replacement_toggle($entity_type, $bundle, $legacy_field) {  $info = title_field_replacement_info($entity_type, $legacy_field);  if (!$info) {    return;  }  $field_name = $info['field']['field_name'];  $instance = field_info_instance($entity_type, $field_name, $bundle);  if (empty($instance)) {    $options = variable_get('title_' . $entity_type, array());    $field = field_info_field($field_name);    if (empty($field)) {      field_create_field($info['field']);    }    $info['instance']['entity_type'] = $entity_type;    $info['instance']['bundle'] = $bundle;    $info['instance']['settings']['hide_label']['page'] = isset($options['hide_label']['page']) ? $options['hide_label']['page'] : FALSE;    $info['instance']['settings']['hide_label']['entity'] = isset($options['hide_label']['entity']) ? $options['hide_label']['entity'] : FALSE;    field_create_instance($info['instance']);    return TRUE;  }  else {    field_delete_instance($instance);    return FALSE;  }}/** * Set a batch process to initialize replacing field values. * * @param $entity_type *   The type of $entity. * @param $bundle *   The bundle the legacy field belongs to. * @param $legacy_field *   The name of the legacy field to be replaced. */function title_field_replacement_batch_set($entity_type, $bundle, $legacy_field) {  $batch = array(    'title' => t('Replacing field values for %field', array('%field' => $legacy_field)),    'operations' => array(      array('title_field_replacement_batch', array($entity_type, $bundle, $legacy_field)),    ),  );  batch_set($batch);}/** * Batch operation: initialize a batch of replacing field values. */function title_field_replacement_batch($entity_type, $bundle, $legacy_field, &$context) {  $info = entity_get_info($entity_type);  $query = new EntityFieldQuery();  $query->entityCondition('entity_type', $entity_type);  // There is no general way to tell if an entity supports bundle conditions  // (for instance taxonomy terms and comments do not), hence we may need to  // loop over all the entities of the given type.  if (!empty($info['efq bundle conditions'])) {    $query->entityCondition('bundle', $bundle);  }  if (empty($context['sandbox'])) {    $count_query = clone $query;    $total = $count_query      ->count()      ->execute();    $context['sandbox']['steps'] = 0;    $context['sandbox']['progress'] = 0;    $context['sandbox']['total'] = $total;  }  $step = variable_get('title_field_replacement_batch_size', 5);  $start = $step * $context['sandbox']['steps']++;  $results = $query    ->entityCondition('entity_type', $entity_type)    ->range($start, $step)    ->execute();  if (!empty($results[$entity_type])) {    $ids = array_keys($results[$entity_type]);    title_field_replacement_init($entity_type, $bundle, $legacy_field, $ids);    $context['sandbox']['progress'] += count($ids);  }  if ($context['sandbox']['progress'] != $context['sandbox']['total']) {    $context['finished'] = $context['sandbox']['progress'] / $context['sandbox']['total'];  }}/** * Initialize a batch of replacing field values. * * @param $entity_type *   The type of $entity. * @param $bundle *   The bundle the legacy field belongs to. * @param $legacy_field *   The name of the legacy field to be replaced. * @param $ids *   An array of entity IDs. * * @return *   The number of entities processed. */function title_field_replacement_init($entity_type, $bundle, $legacy_field, $ids) {  $GLOBALS['title_field_replacement_init'] = TRUE;  $entities = entity_load($entity_type, $ids);  foreach ($entities as $id => $entity) {    list(, , $entity_bundle) = entity_extract_ids($entity_type, $entity);    if ($entity_bundle == $bundle) {      field_attach_presave($entity_type, $entity);      field_attach_update($entity_type, $entity);    }  }  unset($GLOBALS['title_field_replacement_init']);}/** * Synchronize replaced fields with the regular field values. * * @param $entity_type *   The name of the entity type. * @param $entity *   The entity to work with. * @param $set *   Specifies the direction synchronization must be performed. */function title_entity_sync($entity_type, &$entity, $langcode = NULL, $set = FALSE) {  $sync = &drupal_static(__FUNCTION__, array());  list($id, , $bundle) = entity_extract_ids($entity_type, $entity);  if (!isset($langcode)) {    $langcode = $set ? title_entity_language($entity_type, $entity) : title_active_language();  }  // We do not need to perform synchronization more than once.  if (!$set && !empty($id) && !empty($sync[$entity_type][$id][$langcode][$set])) {    return;  }  $sync[$entity_type][$id][$langcode][$set] = TRUE;  $fr_info = title_field_replacement_info($entity_type);  if ($fr_info) {    foreach ($fr_info as $legacy_field => $info) {      if (title_field_replacement_enabled($entity_type, $bundle, $legacy_field)) {        $function = 'title_field_sync_' . ($set ? 'set' : 'get');        $function($entity_type, $entity, $legacy_field, $info, $langcode);      }    }  }}/** * Reset the list of entities whose fields have already been synchronized. * * @param $entity_type *   The name of the entity type. * @param $entity_ids *   Either an array of entity IDs to reset or NULL to reset all. */function title_entity_sync_static_reset($entity_type, $entity_ids = NULL) {  $sync = &drupal_static('title_entity_sync', array());  if (is_array($entity_ids)) {    foreach ($entity_ids as $id) {      unset($sync[$entity_type][$id]);    }  }  else {    unset($sync[$entity_type]);  }}/** * Synchronize a single legacy field with its regular field value. * * @param $entity_type *   The name of the entity type. * @param $entity *   The entity to work with. * @param $legacy_field *   The name of the legacy field to be replaced. * @param $field_name *   The regular field to use as source value. * @param $info *   Field replacement information for the given entity. * @param $langcode *   The field language to use for the source value. */function title_field_sync_get($entity_type, $entity, $legacy_field, $info, $langcode = NULL) {  if (property_exists($entity, $legacy_field)) {    // Save the legacy field value to LEGACY_FIELD_NAME_original.    $entity->{$legacy_field . '_original'} = $entity->{$legacy_field};    // Find out the actual language to use (field might be untranslatable).    $langcode = field_language($entity_type, $entity, $info['field']['field_name'], $langcode);    $values = $info['callbacks']['sync_get']($entity_type, $entity, $legacy_field, $info, $langcode);    foreach ($values as $name => $value) {      if ($value !== NULL) {        $entity->{$name} = $value;      }    }    // Ensure we do not pollute field language static cache.    $cache = &drupal_static('field_language');    list($id, ,) = entity_extract_ids($entity_type, $entity);    unset($cache[$entity_type][$id]);  }}/** * Synchronize a single regular field from its legacy field value. * * @param $entity_type *   The name of the entity type. * @param $entity *   The entity to work with. * @param $legacy_field *   The name of the legacy field to be replaced. * @param $field_name *   The regular field to use as source value. * @param $info *   Field replacement information for the given entity. * @param $langcode *   The field language to use for the target value. */function title_field_sync_set($entity_type, $entity, $legacy_field, $info, $langcode) {  if (property_exists($entity, $legacy_field)) {    // Find out the actual language to use (field might be untranslatable).    $field = field_info_field($info['field']['field_name']);    $langcode = field_is_translatable($entity_type, $field) ? $langcode : LANGUAGE_NONE;    $info['callbacks']['sync_set']($entity_type, $entity, $legacy_field, $info, $langcode);  }}/** * Returns and optionally stores the active language. * * @param string $langcode *   (optional) The active language to be set. If none is provided the active *   language is just returned. * * @return string *   The active language code. Defaults to the current content language. */function title_active_language($langcode = NULL) {  static $drupal_static_fast;  if (!isset($drupal_static_fast)) {    $drupal_static_fast['active_language'] = &drupal_static(__FUNCTION__);  }  $active_langcode = &$drupal_static_fast['active_language'];  if (isset($langcode)) {    $active_langcode = $langcode;  }  if (empty($active_langcode)) {    $active_langcode = $GLOBALS['language_content']->language;  }  return $active_langcode;}/** * Provide the original entity language. * * If a language property is defined for the current entity we synchronize the * field value using the entity language, otherwise we fall back to * LANGUAGE_NONE. * * @param $entity_type * @param $entity * * @return *   A language code */function title_entity_language($entity_type, $entity) {  if (module_exists('entity_translation') && entity_translation_enabled($entity_type)) {    $handler = entity_translation_get_handler($entity_type, $entity, TRUE);    $langcode = $handler->getLanguage();  }  else {    $langcode = entity_language($entity_type, $entity);  }  return !empty($langcode) ? $langcode : LANGUAGE_NONE;}/** * Implements hook_field_attach_form(). * * Hide legacy field widgets on the assumption that this is always called on * fieldable entity forms. */function title_field_attach_form($entity_type, $entity, &$form, &$form_state, $langcode) {  list(, , $bundle) = entity_extract_ids($entity_type, $entity);  $fr_info = title_field_replacement_info($entity_type);  if (!empty($fr_info)) {    foreach ($fr_info as $legacy_field => $info)  {      if (isset($form[$legacy_field]) && title_field_replacement_enabled($entity_type, $bundle, $legacy_field)) {        // Inherit the access from the title widget, so that other modules        // restricting access to it keep working.        if (isset($form[$legacy_field]['#access'])) {          $form[$info['field']['field_name']]['#access'] = $form[$legacy_field]['#access'];        }        // Add class from legacy field so behaviors can still be applied on        // title widget.        $form[$info['field']['field_name']]['#attributes']['class'] = array('form-item-' . $legacy_field);        // Restrict access to the legacy field form element and mark it as        // replaced.        $form[$legacy_field]['#access'] = FALSE;        $form[$legacy_field]['#field_replacement'] = TRUE;      }    }  }}/** * Implements hook_field_attach_submit(). * * Synchronize submitted field values into the corresponding legacy fields. */function title_field_attach_submit($entity_type, $entity, $form, &$form_state) {  $fr_info = title_field_replacement_info($entity_type);  if (!empty($fr_info)) {    // We copy (rather than reference) the values from $form_state because the    // subsequent call to drupal_array_get_nested_value() is destructive and    // will affect other hooks relying on data in $form_state. At the end, we    // copy any modified value back into the $form_state array using    // drupal_array_set_nested_value().    $values = $form_state['values'];    $values = drupal_array_get_nested_value($values, $form['#parents']);    $langcode = entity_language($entity_type, $entity);    foreach ($fr_info as $legacy_field => $info) {      if (!empty($form[$legacy_field]['#field_replacement'])) {        $field_name = $info['field']['field_name'];        // Give a chance to operate on submitted values either.        if (!empty($info['callbacks']['submit'])) {          $info['callbacks']['submit']($entity_type, $entity, $legacy_field, $info, $langcode, $values);        }        drupal_static_reset('field_language');        title_field_sync_get($entity_type, $entity, $legacy_field, $info, $langcode);      }    }    drupal_array_set_nested_value($form_state['values'], $form['#parents'], $values);  }}/** * Implements of hook_menu(). */function title_menu() {  $items = array();  foreach (entity_get_info() as $entity_type => $entity_info) {    if (!empty($entity_info['field replacement'])) {      foreach ($entity_info['bundles'] as $bundle_name => $bundle_info) {        // Blindly taken from field_ui_menu().        if (isset($bundle_info['admin'])) {          $path = $bundle_info['admin']['path'];          if (isset($bundle_info['admin']['bundle argument'])) {            $bundle_arg = $bundle_info['admin']['bundle argument'];          }          else {            $bundle_arg = $bundle_name;          }          $access = array_intersect_key($bundle_info['admin'], drupal_map_assoc(array('access callback', 'access arguments')));          $access += array(            'access callback' => 'user_access',            'access arguments' => array('administer site configuration'),          );          $path = "$path/fields/replace/%";          $field_arg = count(explode('/', $path)) - 1;          $items[$path] = array(            'load arguments' => array(),            'title' => 'Replace fields',            'page callback' => 'drupal_get_form',            'page arguments' => array('title_field_replacement_form', $entity_type, $bundle_arg, $field_arg),            'file' => 'title.admin.inc',          ) + $access;        }      }    }  }  $items['admin/config/content/title'] = array(    'title' => 'Title settings',    'description' => 'Settings for the Title module.',    'page callback' => 'drupal_get_form',    'page arguments' => array('title_admin_settings_form'),    'access arguments' => array('administer site configuration'),    'file' => 'title.admin.inc',  );  return $items;}/** * Implements hook help. */function title_help($path, $arg) {  switch ($path) {    case 'admin/config/content/title':      return '<p>' . t('The settings below allow to configure the <em>default</em> settings to be used when creating new replacing fields. It is even possibile to configure them so that the selected fields are created automatically when a new bundle is created.') . '</p>';  }}/** * Implements hook_field_extra_fields_alter(). */function title_field_extra_fields_alter(&$info) {  $entity_info = entity_get_info();  foreach ($info as $entity_type => $bundles) {    foreach ($bundles as $bundle_name => $bundle) {      if (!empty($entity_info[$entity_type]['field replacement'])) {        foreach ($entity_info[$entity_type]['field replacement'] as $field_name => $field_replacement_info) {          if (title_field_replacement_enabled($entity_type, $bundle_name, $field_name)) {            // Remove the replaced legacy field.            unset($info[$entity_type][$bundle_name]['form'][$field_name],  $info[$entity_type][$bundle_name]['display'][$field_name]);          }        }      }    }  }}/** * Implements hook_form_FORM_ID_alter(). */function title_form_field_ui_field_overview_form_alter(&$form, &$form_state) {  module_load_include('inc', 'title', 'title.admin');  title_form_field_ui_overview($form, $form_state);}/** * Implements hook_tokens_alter(). * * Make sure tokens are properly translated. */function title_tokens_alter(array &$replacements, array $context) {  $mapping = &drupal_static(__FUNCTION__);  if (empty($mapping)) {    foreach (entity_get_info() as $entity_type => $info) {      if (!empty($info['token type'])) {        $mapping[$info['token type']] = $entity_type;      }    }  }  if (isset($mapping[$context['type']])) {    $entity_type = $mapping[$context['type']];    $fr_info = title_field_replacement_info($entity_type);    if ($fr_info && !empty($context['data'][$context['type']])) {      $entity = $context['data'][$context['type']];      list($id, $vid, $bundle) = entity_extract_ids($entity_type, $entity);      $options = $context['options'];      // Since Title tokens are mostly used in storage contexts we default to      // the current working language, that is the entity language. Modules      // using Title tokens in display contexts need to specify the current      // display language.      $langcode = isset($options['language']) ? $options['language']->language : entity_language($entity_type, $entity);      if ($fr_info) {        foreach ($fr_info as $legacy_field => $info) {          if (title_field_replacement_enabled($entity_type, $bundle, $legacy_field)) {            if (isset($context['tokens'][$legacy_field])) {              $langcode = field_language($entity_type, $entity, $info['field']['field_name'], $langcode);              $values = $info['callbacks']['sync_get']($entity_type, $entity, $legacy_field, $info, $langcode);              $item = $values[$legacy_field];              if (!empty($item)) {                if (is_array($item)) {                  $item = reset($item);                }                $replacements[$context['tokens'][$legacy_field]] = $item;              }            }          }        }      }    }  }}/** * Implements hook_form_FORM_ID_alter(). */function title_form_field_ui_field_edit_form_alter(&$form, $form_state) {  $instance = $form['#instance'];  $entity_type = $instance['entity_type'];  if (title_field_replacement_is_label($entity_type, $instance['field_name'])) {    $info = entity_get_info($entity_type);    $form['instance']['settings']['hide_label'] = _title_hide_label_widget($instance['settings'], $info['label']);  }}/** * Returns the hide label form widget. */function _title_hide_label_widget($default, $entity_label) {  return array(    '#type' => 'checkboxes',    '#title' => t('Label replacement'),    '#description' => t('Check these options if you wish to hide the main page title or each label when displaying multiple items of type %entity_label.', array('%entity_label' => $entity_label)),    '#default_value' => !empty($default['hide_label']) ? $default['hide_label'] : array(),    '#options' => array(      'page' => t('Hide page title'),      'entity' => t('Hide label in %entity_label listings', array('%entity_label' => drupal_strtolower($entity_label))),    ),  );}/** * Checks whether the given field name is a replaced entity label. * * @param $entity_type *   The name of the entity type. * @param $field_name *   The replacing field name. * * @return *   TRUE id the give field is replacing the entity label, FALSE otherwise. */function title_field_replacement_is_label($entity_type, $field_name) {  $label = FALSE;  $legacy_field = title_field_replacement_get_legacy_field($entity_type, $field_name);  if ($legacy_field) {    $info = entity_get_info($entity_type);    $label = $legacy_field == $info['entity keys']['label'];  }  return $label;}/** * Returns the legacy field replaced by the given field name. *  * @param $entity_type *   The name of the entity type. * @param $field_name *   The replacing field name. * *  @return *    The replaced legacy field name or FALSE if none available. */function title_field_replacement_get_legacy_field($entity_type, $field_name) {  $result = FALSE;  $fr_info = title_field_replacement_info($entity_type);  if ($fr_info) {    foreach ($fr_info as $legacy_field => $info) {      if ($info['field']['field_name'] == $field_name) {        $result = $legacy_field;        break;      }    }  }  return $result;}/** * Returns the field instance replacing the given entity type's label. * * @param $entity_type *   The name of the entity type. * @param $bundle *   The name of the bundle the instance is attached to. * *  @return *   The field instance replacing the label or FALSE if none available. */function title_field_replacement_get_label_field($entity_type, $bundle) {  $instance = FALSE;  $info = entity_get_info($entity_type);  if (!empty($info['field replacement'])) {    $fr_info = $info['field replacement'];    $legacy_field = $info['entity keys']['label'];    if (!empty($fr_info[$legacy_field]['field'])) {      $instance = field_info_instance($entity_type, $fr_info[$legacy_field]['field']['field_name'], $bundle);    }  }  return $instance;}/** * Hides the label from the given variables. * * @param $entity_type *   The name of the entity type. * @param $entity *   The entity to work with. * @param $vaiables *   A reference to the variables array related to the template being processed. * @param $page *   (optional) The current render phase: page or entity. Defaults to entity. */function title_field_replacement_hide_label($entity_type, $entity, &$variables, $page = FALSE) {  list(, , $bundle) = entity_extract_ids($entity_type, $entity);  $instance = title_field_replacement_get_label_field($entity_type, $bundle);  $settings_key = $page ? 'page' : 'entity';  if (!empty($instance['settings']['hide_label'][$settings_key])) {    // If no key is passed default to the label one.    if ($page) {      $key = 'title';    }    else {      $info = entity_get_info($entity_type);      $key = $info['field replacement'][$info['entity keys']['label']]['preprocess_key'];    }    // We cannot simply unset the variable value since this may cause templates    // to throw notices.    $variables[$key] = FALSE;  }}/** * Implements hook_views_api(). */function title_views_api() {  return array(    'api' => 3,    'path' => drupal_get_path('module', 'title') . '/views',  );}/** * Implements hook_field_attach_create_bundle(). * * Automatically attach the replacement field to the new bundle. */function title_field_attach_create_bundle($entity_type, $bundle) {  $entity_info = entity_get_info($entity_type);  if (empty($entity_info['field replacement'])) {    return;  }  $options = variable_get('title_' . $entity_type, array());  foreach (array_keys($entity_info['field replacement']) as $legacy_field) {    if (empty($options['auto_attach'][$legacy_field])) {      continue;    }    // Do not continue if the replacement field already exists.    $field_name = $entity_info['field replacement'][$legacy_field]['field']['field_name'];    if (field_info_instance($entity_type, $field_name, $bundle)) {      continue;    }    title_field_replacement_toggle($entity_type, $bundle, $legacy_field);    $instance = field_info_instance($entity_type, $field_name, $bundle);    if ($instance) {      $params = array(        '@entity_label' => drupal_strtolower($entity_info['label']),        '%field_name' => $instance['label'],      );      drupal_set_message(t('The @entity_label %field_name field was automatically replaced.', $params));    }  }}/** * Implements hook_field_info_alter(). */function title_field_info_alter(&$info) {  $supported_types = array('taxonomy_term_reference' => TRUE);  foreach ($info as $field_type => &$field_type_info) {    if (isset($supported_types[$field_type])) {      if (!isset($field_type_info['settings'])) {        $field_type_info['settings'] = array();      }      $field_type_info['settings'] += array('options_list_callback' => 'title_taxonomy_allowed_values');    }  }}/** * Return taxonomy term values for taxonomy reference fields. */function title_taxonomy_allowed_values($field) {  $bundle = !empty($field['settings']['allowed_values'][0]['vocabulary']) ? $field['settings']['allowed_values'][0]['vocabulary'] : NULL;  if ($bundle && ($label = title_field_replacement_get_label_field('taxonomy_term', $bundle))) {    $options = array();    foreach ($field['settings']['allowed_values'] as $tree) {      $vocabulary = taxonomy_vocabulary_machine_name_load($tree['vocabulary']);      if ($vocabulary && ($terms = taxonomy_get_tree($vocabulary->vid, $tree['parent'], NULL, TRUE))) {        foreach ($terms as $term) {          $options[$term->tid] = str_repeat('-', $term->depth) . entity_label('taxonomy_term', $term);        }      }    }    return $options;  }  return taxonomy_allowed_values($field);}
 |