필드 컬렉션을 올바르게 삭제하는 방법?


9

드루팔 버전 : 7.21
필드 수집 모듈 버전 : 7.x-1.0-beta5

간단한 설명 : 프로그래밍 방식으로 필드 컬렉션을 가져 오려고하는데 바쁘지만 일부를 삭제하면 항상 '가짜'필드 컬렉션이 남아 있습니다.

자세한 설명 : 내 사용자는 자신의 프로필에 필드 수집 필드를 가지고 있습니다. 이 필드 모음에는 3 개의 텍스트 필드가 있습니다. 사용자 지정 SQL 데이터베이스에서 사용자의 필드 컬렉션으로 데이터를 가져오고 싶습니다. 이 필드 컬렉션은 여러 값을 가질 수 있습니다. 데이터를 처음 가져올 때 모든 것이 제대로 작동하면 필드 컬렉션의 필드에 데이터가 표시됩니다. 큰.

그러나 여기 까다로운 부분이 있습니다. 사용자 정의 데이터베이스에서 특정 사용자 5 행을 가져옵니다. 필드 콜렉션에 추가되므로이 필드 콜렉션에는 각각 3 개의 필드를 포함하는 5 개의 항목이 있습니다. 그런 다음 사용자 정의 데이터베이스에서 일부 행을 삭제 하여이 사용자에 대해 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_multiple100 % 확실히 올바른 방법입니다. field_collection_field_delete기능을 살펴보십시오 . 참조 된 필드를 제거 할 때 필드 컬렉션 자체가 항목을 정리하는 데 사용됩니다
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
즉, 특정 기능은 기본적으로 할 때, 후크 구현 어떤 해당 필드 인스턴스에 연결된 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

@ Smos : 안녕 친구, 비슷한 문제 ( drupal.stackexchange.com/questions/239784/… ) 를 도와 줄 수 있습니까? 관련 코드를 시도했지만 작동시키지 못했습니다.
sisko

답변:


13

소스 구조가 Feeds에 대해 너무 복잡했기 때문에 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)노드를 잊지 마십시오 .
Bernhard Fürst

@ 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

피드에서 FC 항목으로 데이터를 가져 오는 비슷한 문제가있었습니다. 피드에서 호스트 엔터티에 대한 업데이트를 수행하고 해당 변경 사항을 가져 오는 경우 더 이상 피드 소스에 존재하지 않는 기존 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 데이터에 변화가 없으면 삭제되고 다시 생성된다는 것입니다. 그러나 그것은 큰 문제가 아닙니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.