如何以编程方式从节点中删除字段?


16

如何以编程方式从节点中删除字段?我在迁移中将hook_update_N内容从a字段移到自定义表中。迁移之后,我想删除同一函数中的字段。

是否有可以删除字段的字段API?

编辑,解决方案:因为答案缺少实际的代码,所以这是我将$ users中的字段移到我自己的记录中,然后从数据库中删除该字段的方法;

function my_module_update_7005(&$sandbox) {
  $slice = 100;
  //Fetch users from database;
  if (!isset($sandbox['progress'])) {
    $sandbox['progress'] = 0;
    $sandbox['current_uid'] = 0;
    // We'll -1 to disregard the uid 0...
    $sandbox['max'] = db_query('SELECT COUNT(DISTINCT uid) FROM {users}')->fetchField() - 1;
  }
  if (empty($users)) {
    $sandbox["current_uid"] += $slice;
  }
  $users = db_select('users', 'u')
    ->fields('u', array('uid', 'name'))
    ->condition('uid', $sandbox['current_uid'], '>')
    ->range(0, $slice)
    ->orderBy('uid', 'ASC')
    ->execute();
  //Loop trough users;
  foreach ($users as $user) {
    $foo = new Foo();
    // Warning: drupal's fields return mixed values; e.g. NULL versus an int.
    $foo->debits = (int) $user->user()->field_credits["und"][0]["value"];
    $foo->save();

    $sandbox['progress']++;
    $sandbox['current_uid'] = $user->uid;
  }

  $sandbox['#finished'] = empty($sandbox['max']) ? 1 : ($sandbox['progress'] / $sandbox['max']);

  // Remove the field.
  field_delete_field("field_credits"); //note that the name for Foo is field_foo
  field_purge_batch($sandbox['max']+1);//Drupal seems to have an offbyone problem.
}

Answers:


29

field_delete_field($field_name)$field_name在下次执行cron时将其标记为删除。

field_purge_batch如果您不想在cron run上进行删除,则可以使用它来进行删除。

编辑: field_delete_field()当您还需要从其他捆绑软件中删除该字段时,也应使用该编辑器。如果您只想从特定的捆绑软件中删除该字段,则应使用field_delete_instance()@Clive所述。


4
小心,这也会将该字段从它可能附加到的任何其他捆绑包中删除:)field_purge_batch不过
高兴

@Clive:对,它将删除所有捆绑销售商品的字段。感谢您的纠正:)我已经编辑了答案。
AjitS 2012年

我确实想完全删除该字段,即从所有捆绑包中删除。但是警告是好的。谢谢。
berkes 2012年

1
field_delete_instance()是必经之路。
瑞安·麦克维

field_purge_batch()实际上只会删除与传递给它的批处理大小一样多的字段项。当字段只有几个项目时,这可能会有所帮助,这样就可以完全摆脱字段实例,而无需等待cron清除它。如果您在该字段中有很多值,请不要试图将批处理大小增加得太大(名称中的“批处理”并不意味着它会自己进行任何批处理,只是意味着它会进行单个批处理)根据您要求的数量);您可能最终会遇到PHP内存或时间限制。
Eelke Blok

24

要从特定捆绑包中删除字段,您可以使用 field_delete_instance()

将字段实例及其数据标记为删除。

例:

function my_module_update_7001() {
  if ($instance = field_info_instance('node', 'field_name', 'page'))  {
    field_delete_instance($instance, TRUE);
    field_purge_batch(1);
  }
}

要从系统中完全删除字段,可以使用 field_delete_field()

将字段及其实例和数据标记为删除。

例:

function my_module_update_7001() {
  field_delete_field('field_name');
  field_purge_batch(1);
}

字段/实例仅标记为删除,实际上将在随后的cron运行期间清除数据。要手动清除它,请执行以下操作:

field_purge_batch(1);

1
在通话field_delete_field()field_purge_batch()工作时,它将记录保存在field_config_instance和中field_config。这是为什么?
berkes 2012年

我不太明白为什么用值1调用field_purge_batch将摆脱所有字段数据。如果我正确理解代码,它将获取$ batchsize实体的字段数据并将其留在那(即,无需递归调用函数或任何东西);似乎是由调用方检查是否所有数据都消失了,如果没有,继续调用该函数。但是,也许我从根本上误会了一些东西。
Eelke Blok

实际上,field_ui.admin.inc中的此注释在解释这一点上有很长的路要走://在cron上清除了字段。但是,//当字段提供的字段类型在字段中被完全清除之前,//字段模块会阻止禁用模块。如果某个字段的内容很少或没有内容,则对field_purge_batch()的一次调用//会将其从系统中删除。//使用低批处理限制进行调用,以避免管理员在删除满足此条件的实例时必须等待cron运行。
Eelke Blok

@Clive,我相信您的建议几乎是隐性的,但是我无法克服在if条件下进行声明对我来说有多怪异。那是故意的吗?我指的是$instance = field_info_instance('node', 'field_name', 'page')。应该不是$instance = field_info_instance('node', 'field_contact', 'job');,然后删除if语句吗?
cdmo

1
@cdmo称为“状态分配”,是的,它确实有问题。但是Drupal核心甚至在最新版本中都自由使用它,因此至少有先例。老实说,这是5年前的事,现在我有点聪明了,我要么不使用它,要么出于某种原因我打包了作业(例如if ( ($foo = $bar) ) {,意图很明显,并且有潜力if语句本身是必需的,因为field_delete_instance它不检查是否为空
Clive

5

要回答@berkes问题:

field_delete_field()确实将该字段标记为要删除,从而导致该字段在下一次cron运行时被清除。但是,它确实保留了field_config_instance有关丢弃字段的数据。运行cron或field_purge_batch()不会从field_config_instance表中删除此数据,即使已将字段的已删除列设置1为。

对我来说,每个清除的字段都使用field_delete_instance()a field_purge_batch()来代替-立即从数据库中删除该字段(不需要cron),以及清除field_config_instance表中的任何字段数据(对于已删除的字段)。

解决方法如下:

/**
 * Implements hook_uninstall().
 */
function hook_uninstall() {
  // Delete all fields for all xyz entity bundles.

  // Retrieve all bundles for an entity.
  $bundles = field_info_bundles('XYZ'); // The name of your entity type, for example, 'node'.
  foreach ($bundles as $bundle => $properties) {

    // Retrieve all the fields for a given bundle.
    $instances = field_info_instances('XYZ', $bundle);
    foreach ($instances as $instance) {
      field_delete_instance($instance, TRUE);
      field_purge_batch(1);
    }
  }
}

请注意TRUEon field_delete_instance(),因为它表明Field API应该执行清除操作。


如何使用此代码?我想从内容类型删除标题字段
Umair
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.