Support from Acquia helps fund testing for Drupal Acquia logo

Comments

chriscalip’s picture

Or even just a way to programmatically update node entity bundles (content types) from traditional title to fieldable title; right now the switch process is entwined with the batch api process..

plach’s picture

chriscalip’s picture

That was initially what i was thinking about and i took the time to profile this code and here's my findings.

I wanted to programmatically replace the action of "Replace title with a field instance"
See: Screenshot-before-replace.png

-- setting the bundle settings from traditional node title to more flexible fieldable title.
-- update the nodes belonging to that bundle from traditional node title to fieldable title.

-- i profiled the process of updating a page content type . with about 40 nodes and this function got called about 75 times.
See: Screenshot-after-process-watchdogs.png

chriscalip’s picture

I am slowly putting in more information as I dig deeper.

-- setting the bundle settings from traditional node title to more flexible fieldable title.
The drush extension can make use of
title_field_replacement_toggle($form['#entity_type'], $form['#bundle'], $form['#field_name']);

update the nodes belonging to that bundle from traditional node title to fieldable title.
currently checking if title_field_replacement_init() would be suitable for a drush extension context instead of entry point via the batch api specifically.. title_field_replacement_batch_set.

chriscalip’s picture

@plach

You were right drush extension can make use of title_field_replacement_init(). Also in terms of improving our contributed modules i'd like to share my findings and possible recommendations:

-- update the nodes belonging to that bundle from traditional node title to fieldable title.
title_field_replacement_init()

function title_field_replacement_init($entity_type, $bundle, $legacy_field, $start = 0, $length = 10) {
  $query = new EntityFieldQuery();

  $results = $query
    ->entityCondition('entity_type', $entity_type)
    ->range($start, $length)
    ->execute();

  if (!empty($results[$entity_type])) {
    $GLOBALS['title_field_replacement_init'] = TRUE;
    $entities = entity_load($entity_type, array_keys($results[$entity_type]));

    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']);
    return count($results[$entity_type]);
  }

  return 0;
}

In every process we have the advantage of having contextual information that user wants to update a specific bundle. The process could take advantage of user intention parameter value $bundle

By changing code From

  $results = $query
    ->entityCondition('entity_type', $entity_type)
    ->range($start, $length)
    ->execute();

To :

  $results = $query
    ->entityCondition('entity_type', $entity_type)
    ->entityCondition('bundle', $bundle)
    ->range($start, $length)
    ->execute();

This would be a significant performance booster and less memory requirements because the process is only loading nodes belonging to that bundle.

plach’s picture

This would be a significant performance booster and less memory requirements because the process is only loading nodes belonging to that bundle.

The reason for not going that way is that not every entity type supports bundle conditions, for instance taxonomy terms do not. However I think the version you are using is outdated, see the one I linked in #2.

q0rban’s picture

Here's a drush command that I wrote for a custom project to upgrade node titles to Title module fields. It could pretty easily be adapted to work with other entity types as well, I think.


/**
 * @file
 * Drush commands for Title module.
 */

/**
 * Implements hook_drush_help().
 */
function title_drush_help($section) {
  switch ($section) {
    case 'drush:upgrade-title-fields':
      return dt('Upgrade title fields to use title module, so that titles can be localized.');
  }
}

/**
 * Implements hook_drush_command().
 */
function title_drush_command() {
  $items['upgrade-title-fields'] = array(
    'description' => 'Upgrade title fields to use title module, so that titles can be localized.',
    'drupal dependencies' => array('title', 'entity_translation'),
  );
  $items['upgrade-title-field'] = array(
    'description' => 'Upgrade a title field on a legacy field. DO NOT call this command directly, it does not do any checking.',
    'hidden' => TRUE,
    'arguments' => array(
      'entity_type' => 'The type of entity, be it a node, user, term, etc.',
      'bundle' => 'The entity bundle.',
      'legacy_field' => 'The machine name of the legace field.',
    ),
  );

  return $items;
}

/**
 * Command callback for upgrade-title-fields.
 */
function drush_title_upgrade_title_fields() {
  $entity_type = 'node';
  $entity_info = entity_get_info($entity_type);
  if (empty($entity_info['field replacement'])) {
    drush_log(t('There are no available title fields to upgrade.'), 'error');
    return FALSE;
  }

  $field_replacement_info = $entity_info['field replacement'];

  $upgraded = $failed = $skipped = 0;
  foreach (title_content_types() as $bundle) {
    $dt_args['@bundle'] = $bundle;
    $field_instances = field_info_instances($entity_type, $bundle);
    $extra_fields = field_info_extra_fields($entity_type, $bundle, 'form');
    $possible_fields = array_merge($field_instances, $extra_fields);

    if ($info = array_intersect_key($field_replacement_info, $possible_fields)) {
      foreach (array_keys($info) as $legacy_field) {
        $dt_args['@legacy_field'] = $legacy_field;
        if (drush_invoke_process('@self', 'upgrade-title-field', array($entity_type, $bundle, $legacy_field))) {
          $upgraded++;
        }
        else {
          $failed++;
        }
      }
    }
    else {
      $skipped++;
      drush_log(dt('Title fields have already been upgraded on content type @bundle.', $dt_args), 'ok');
    }
  }

  $messages = array();
  if ($upgraded) {
    $dt_args['@upgraded'] = $upgraded;
    $messages[] = 'Upgraded @upgraded title field(s).';
  }
  if ($skipped) {
    $dt_args['@skipped'] = $skipped;
    $messages[] = 'Skipped @skipped title field(s).';
  }
  if ($failed) {
    $dt_args['@failed'] = $failed;
    $messages[] = '@failed failed.';
  }
  $message = empty($messages) ? 'No fields upgraded.' : implode(' ', $messages);
  drush_log(dt($message, $dt_args), 'completed');
  if ($failed) {
    return FALSE;
  }
}

/**
 * Command callback for upgrade-title-field.
 */
function drush_title_upgrade_title_field($entity_type, $bundle, $legacy_field) {
  $dt_args['@entity_type'] = $entity_type;
  $dt_args['@bundle'] = $bundle;
  $dt_args['@field'] = $legacy_field;
  if (!title_field_replacement_toggle($entity_type, $bundle, $legacy_field)) {
    drush_log(dt("Failed to upgrade title field '@field' on content type @bundle.", $dt_args), 'warning');
    return FALSE;
  }
  title_field_replacement_batch_set($entity_type, $bundle, $legacy_field);
  drush_backend_batch_process();

  if (drush_get_error()) {
    drush_log(dt("Failed upgrading title field '@field' on bundle '@bundle'. Your database is likely messed up now. Sorry about that.", $dt_args), 'error');
    return FALSE;
  }
  drush_log(dt("Upgraded title field '@field' on content type @bundle.", $dt_args), 'success');
  return TRUE;
}
drzraf’s picture

FileSize
3.84 KB

The exact version of q0rban attached as a patch

But I noticed a bunch of these:
Undefined property: stdClass::$original file.field.inc:265
what does not happen using the browser.

Other than that it appears to work well.
Thanks.

drzraf’s picture

The notice was unrelated, after applying the patch from #985642: Remove file_attach_load() from file_field_update() the title replacement processed quietly.

drzraf’s picture

ping ?

DamienMcKenna’s picture

Issue summary: View changes
Status: Active » Needs review

Don't forget to update the issue to "needs review" after you upload a patch ;-)

Pol’s picture

It would be a very nice to have indeed.

Pol’s picture

Status: Needs review » Reviewed & tested by the community

Patch tested and working.

alex_optim’s picture

+1

pifagor’s picture

  • pifagor committed 231386e on 7.x-1.x authored by drzraf
    Issue #1801242 by drzraf, chriscalip, plach, Pol, alex_optim, q0rban,...
pifagor’s picture

Status: Reviewed & tested by the community » Fixed

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.

douggreen’s picture

How was this RTBC and committed. AFAICT, this is broken because title_content_types() doesn't exist and never existed.

And ideally, this would not hard code 'node' but take the entity type as an argument.