如何正确删除字段集合?


9

Drupal版本:7.21
字段收集模块版本:7.x-1.0-beta5

简短说明:我正忙于尝试以编程方式导入字段集合,但是在删除其中一些字段时,总会剩下一些“伪”字段集合。

详细说明:我的用户的个人资料上有一个字段收集字段。该字段集合包含3个文本字段。我想将数据从自定义sql数据库导入到用户的字段集合中。该字段集合可以具有多个值。当我第一次导入数据时,一切正常,我在字段集合的字段中看到了数据。大。

但是,这是棘手的部分。假设我为一个特定用户从定制数据库中导入了5行。它们被添加到字段集合中,因此此字段集合有5个项目,每个项目包含3个字段。然后,从自定义数据库中删除一些行,以使该用户仅剩下3行。我再次运行导入,更新了字段集合的前3个项目,但是接下来剩下的是前一次导入的2个项目。应该删除它们,因为我只有3个导入行,但仍然有5个字段收集项。

因此,我尝试删除这些字段收集项,但始终剩下一个或多个项。当我查看用户个人资料时,这些字段为空,但那里还是有东西。假设此时我在自定义数据库中为该用户添加了5个新行,因此该用户总共有8行。然后,我再次运行导入。前3个项目得到更新,但是当我尝试添加第4行时,它仍然从第4个字段集合项中获取实体ID,尝试对其进行更新,但失败并返回此错误:

 Fatal error: Call to undefined method stdClass::save()

我尝试使用以下每种方法删除字段收集项:

// Method 1
entity_delete_multiple('field_collection_item', array($fc_id));

// Method 2
$field_collection_item = field_collection_item_load($fc_id);
$field_collection_item->delete();

// Method 3
$field_collection_item = field_collection_item_load($fc_id);
$field_collection_item->deleteRevision();

这是我的完整代码:

function import_user_field_collection(&$user, $old_user_id) {

  // I do a query to get the rows I want to import for this specific user.
  db_set_active('custom_sql_database');
  $result = db_query("SELECT * FROM {users} WHERE user_id = :user_id", array(':user_id' => $old_user_id));

  db_set_active('default');
  $i = 0; // Keep count of how many rows I imported.
  foreach($result as $row) {
    // Check if the field collection item already exists.
    if(!empty($user->field_profile_diploma_opleiding[LANGUAGE_NONE][$i]['value'])) {
      // If it does exists, update this particular field collection item.
      $fc_id = $user->field_profile_diploma_opleiding[LANGUAGE_NONE][$i]['value'];
      $field_collection_item = entity_load('field_collection_item', array($fc_id));
      // These 3 text fields are children of the field collection field.
      $field_collection_item[$fc_id]->field_profile_diploma_instituut[LANGUAGE_NONE][0]['value'] = $row->instituut;
      $field_collection_item[$fc_id]->field_profile_diploma_vakgebied[LANGUAGE_NONE][0]['value'] = $row->vakgebied;
      $field_collection_item[$fc_id]->field_profile_diploma_jaar[LANGUAGE_NONE][0]['value'] = $row->jaar_diploma;
      $field_collection_item[$fc_id]->save(TRUE);
    } else {
      // If the field collection item doesn't exist I want to create a new field collection item.
      $field_collection_item = entity_create('field_collection_item', array('field_name' => 'field_profile_diploma_opleiding'));
      $field_collection_item->setHostEntity('user', $user);
      $field_collection_item->field_profile_diploma_instituut[LANGUAGE_NONE][0]['value'] = $row->instituut;
      $field_collection_item->field_profile_diploma_vakgebied[LANGUAGE_NONE][0]['value'] = $row->vakgebied;
      $field_collection_item->field_profile_diploma_jaar[LANGUAGE_NONE][0]['value'] = $row->jaar_diploma;
      $field_collection_item->save(TRUE);
    }
    $i++;
  }

  $fc_fields = field_get_items('user', $user, 'field_profile_diploma_opleiding');

  // Check if there are more field collection items than imported rows
  if(count($fc_fields) > $i) {
    for($i; $i <= count($fc_fields); $i++) {
      // Run through each field collection item that's left from the previous import and delete it.
      if(!empty($user->field_profile_diploma_opleiding[LANGUAGE_NONE][$i]['value'])) {
        // Method 1
        $fc_id = $user->field_profile_diploma_opleiding[LANGUAGE_NONE][$i]['value'];
        entity_delete_multiple('field_collection_item', array($fc_id));

        // Method 2
        //$field_collection_item = field_collection_item_load($fc_id);
        //$field_collection_item->delete();

        // Method 3
        //$field_collection_item = field_collection_item_load($fc_id);
        //$field_collection_item->deleteRevision();
      }
    }
  }
}

所以我的问题是:如何删除字段收集项以使它们实际上消失了?


2
entity_delete_multiple是100%绝对正确的方法-查看field_collection_field_delete功能,这是移除引用字段时Field Collection本身用来清理项目的功能
Clive

非常感谢您的回复,我非常感谢。您是否知道我应该为field_collection_field_delete提供哪些参数?我看到签名是field_collection_field_delete($ entity_type,$ entity,$ field,$ instance,$ langcode和&$ items),但我真的不知道要输入什么值:$ entity(这是用户还是字段集合?),$ field(来自field_collection_item_load的返回值?),$ instance,$ langcode(und?)和$ items。
Smos

1
该特定功能是一个钩子实现,基本上,当删除任何字段时,字段名称都会传递给该函数,然后Field Collection检查是否有与该字段实例相关联的FC实体。如果存在,它将使用删除它entity_delete_multiple()。删除字段后,您可能需要运行cron几次(按计划清除字段数据,以免单页加载处理所有工作)
Clive

我再次尝试使用entity_delete_multiple,但我注意到该项目在表field_collection_item中被删除,但这些字段仍然存在于表field_data_field_collection_name中。我认为这会导致致命错误,即对未定义方法stdClass :: save()的调用,因为它们应该是字段,但没有链接到它的字段集合项。当我使用$ field_collection_item-> deleteRevision时,它会删除两个表中的数据,但是当我保存用户时,会在表field_data_field_collection_name中添加一行,这是一个空白字段收集项。
Smos 2013年

@Smos:嘿,哥们,您能帮我解决类似的问题吗(drupal.stackexchange.com/questions/239784/…)?我尝试了代码的相关部分,但无法正常工作。
sisko

Answers:


13

我遇到了一个类似的用例,因为源结构对于Feed来说太复杂了,所以我想在hook_feeds_presave()期间将一些数据映射到字段集合中。我发现entity_delete_multiple()删除了字段收集项,但是当我编辑节点时,那里仍然有一堆空字段收集。取消设置和删除就可以了,我在这里找到了窍门:https ://drupal.stackexchange.com/a/31820/2762

如果提要源已更改,我将删除所有字段收集项并重新创建。希望这会有所帮助。

foreach ($node->field_international_activity[LANGUAGE_NONE] as $key => $value) {
  // Build array of field collection values.
  $field_collection_item_values[] = $value['value'];

  // Unset them.  
  unset($node->field_international_activity[LANGUAGE_NONE][$key]);
}

// Delete field collection items.
entity_delete_multiple('field_collection_item', $field_collection_item_values);

这2步方法是唯一可行的AFAIK方法。不要忘记node_save($node)您的节点。
2013年

@BernhardFürst实际上我们不需要node_save($node)DrupalEntityController将要做此工作
coffeduong

8

现在最好的方法是通话$field_collection->delete(),它将处理所有事情。

 <?php
    /**
     * Deletes the field collection item and the reference in the host entity.
     */
    public function delete() {
      parent::delete();
      $this->deleteHostEntityReference();
    }

    /**
     * Deletes the host entity's reference of the field collection item.
     */
    protected function deleteHostEntityReference() {
      $delta = $this->delta();
      if ($this->item_id && isset($delta)) {
        unset($this->hostEntity->{$this->field_name}[$this->langcode][$delta]);
        entity_save($this->hostEntityType, $this->hostEntity);
      }
    }
 ?>

0

上面的答案不是最好的方法,取消所有其他项的设置会从字段集合中消失,而->delete()通过Entity模块抛出错误。

正确的方法。好吧,我这样做的是:

就我而言,我想删除字段集合中的最后一项

看一下这段代码,(对于初学者:“记住,您必须已经加载了$ entity”)

// Remove the field value
unset($entity->field_salida_mercanc_a[LANGUAGE_NONE][count($entity->field_salida_mercanc_a[LANGUAGE_NONE])-1]);

// Reset the array to zero-based sequential keys
$entity->field_salida_mercanc_a[LANGUAGE_NONE] = array_values($entity->field_salida_mercanc_a[LANGUAGE_NONE]);

// Save the entity
entity_save($entity_type, $entity);

就这样!另一种方法是

//Get the node wapper
$wrapper = entity_metadata_wrapper($entity_type, $entity);
//Get the last position of the array items, thanks to the ->value() statement you can get the complete Array properties.
$field_collection_item_value = $wrapper->field_collection_mine[count($wrapper->field_collection_mine->value())-1]->value();
//Do not use 'unset' to delete the item due to is not the correct way, I use the entity_delete_multiple provided by the entity API
entity_delete_multiple('field_collection_item', array($field_collection_item_value->item_id));

上面的方法很好地使用了entity_metadata_wrapper函数,但是这样有一个复杂的错误,我不知道如何解决,您可以在https://drupal.org/node/1880312进行检查,并在#9中应用补丁后您会收到下一个问题,请在这里检查https://drupal.org/node/2186689如果您使用->delete()函数,此错误也将出现。

希望它可以帮助某人。


0

使用vbo删除字段收集项。它将自动删除与字段收集项目宿主实体的字段关系。


0

我遇到了类似的问题,即将数据从Feed导入FC项目。当通过Feed对主机实体进行更新时,我正在导入这些更改,因此我想确保从Feed源中删除不再存在的所有现有FC项目。

我的解决方案:

// Load host entity that I'm updating.
$host_entity = node_load($nid);
$host_entity_wrapper = entity_metadata_wrapper('node', $host_entity);

// Clear out the references to the existing FC items so that I have a fresh start.
$host_entity_wrapper->field_my_fc_items->set(NULL);

// Re-create the FC items from the source feed data.
foreach ($feed_data->items as $feed_item) {
  $fc = entity_create('field_collection_item', array('field_name' => 'field_my_fc_items'));
  $fc->setHostEntity($host_entity);
  // Some some fields on the FC item from the feed data.
  $fc_wrapper = entity_metadata_wrapper('field_collection_item', $fc);
  $fc_wrapper->field_some_fc_item_field->set($feed_item->data);
}

// Sync other field info onto host entity.
...

$host_entity_wrapper->save();

就是这样。字段集合的hook_field_update(field_collection_field_update)将负责删除实际上已被取消引用的所有FC项目。

唯一的缺点是,如果FC数据没有更改,则无论如何都会删除并重新创建它。但这对我来说并不重要。

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.