Làm thế nào để xóa đúng một bộ sưu tập trường?


9

Phiên bản Drupal: 7.21
Phiên bản mô-đun bộ sưu tập trường: 7.x-1.0-beta5

Giải thích ngắn gọn : Tôi đang bận nhập các bộ sưu tập trường theo chương trình nhưng khi xóa một số trong số chúng luôn có một số bộ sưu tập trường 'không có thật'.

Giải thích dài : Người dùng của tôi có trường thu thập trường trong hồ sơ của họ. Bộ sưu tập trường này chứa 3 trường văn bản. Tôi muốn nhập dữ liệu từ cơ sở dữ liệu sql tùy chỉnh vào bộ sưu tập trường của người dùng. Bộ sưu tập trường này có thể có nhiều giá trị. Khi tôi nhập dữ liệu lần đầu tiên mọi thứ hoạt động tốt, tôi thấy dữ liệu trong các trường của bộ sưu tập trường. Tuyệt quá.

Nhưng ở đây có phần khó khăn. Giả sử tôi nhập cho một người dùng cụ thể 5 hàng từ cơ sở dữ liệu tùy chỉnh. Chúng được thêm vào bộ sưu tập trường, vì vậy bộ sưu tập trường này có 5 mục, mỗi mục chứa 3 trường. Sau đó, tôi xóa một số hàng khỏi cơ sở dữ liệu tùy chỉnh của mình để tôi chỉ còn 3 hàng cho người dùng này. Tôi chạy lại quá trình nhập, cập nhật 3 mục đầu tiên của bộ sưu tập trường, nhưng sau đó tôi còn lại 2 mục từ lần nhập trước. Chúng nên bị xóa vì tôi chỉ có 3 hàng đã nhập nhưng vẫn có 5 mục bộ sưu tập trường.

Vì vậy, tôi đã cố gắng xóa các mục bộ sưu tập trường này, nhưng luôn có một hoặc nhiều mục còn lại. Các trường trống khi tôi nhìn vào hồ sơ người dùng nhưng vẫn còn một cái gì đó ở đó. Giả sử tại thời điểm này tôi thêm 5 hàng mới cho người dùng trong cơ sở dữ liệu tùy chỉnh của mình, vì vậy tôi có tổng cộng 8 hàng cho người dùng này. Sau đó tôi chạy nhập lại. 3 mục đầu tiên được cập nhật, nhưng sau đó khi tôi cố gắng thêm hàng thứ 4, nó vẫn nhận được id thực thể từ mục bộ sưu tập trường thứ 4, cố gắng cập nhật nhưng không thành công và trả về lỗi này:

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

Tôi đã thử xóa các mục bộ sưu tập trường với từng phương thức dưới đây:

// 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();

Đây là mã đầy đủ của tôi:

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();
      }
    }
  }
}

Vì vậy, câu hỏi của tôi là: Làm thế nào để tôi xóa các mục bộ sưu tập trường để chúng thực sự biến mất?


2
entity_delete_multiplechắc chắn 100% là cách đúng đắn để thực hiện - hãy xem field_collection_field_deletechức năng, đó là những gì mà Bộ sưu tập Trường sử dụng để dọn dẹp các mục khi trường được tham chiếu bị xóa
Clive

Cảm ơn rất nhiều vì phản hồi của bạn, tôi đánh giá cao nó. Bạn có tình cờ biết những đối số nào tôi nên cung cấp với field_collection_field_delete không? Tôi thấy chữ ký là field_collection_field_delete ($ entity_type, $ entity, $ field, $ dụ, $ langcode, & $ items) nhưng tôi thực sự không biết nên đặt giá trị nào vào: $ entity (đây là người dùng hay bộ sưu tập trường ?), $ field (giá trị trả về từ field_collection_item_load?), $ dụ, $ langcode (und?) và $ items.
Smos

1
Hàm cụ thể đó là một triển khai hook, về cơ bản khi bất kỳ trường nào bị xóa, tên trường được chuyển đến hàm đó và Bộ sưu tập trường sẽ kiểm tra xem có thực thể FC nào được liên kết với thể hiện trường đó không. Nếu có, nó sẽ xóa nó bằng cách sử dụng entity_delete_multiple(). Bạn có thể cần chạy cron một vài lần sau khi xóa các trường (dữ liệu trường được xóa theo lịch để không gây gánh nặng cho một tải trang với tất cả quá trình xử lý phải làm)
Clive

Tôi đã thử sử dụng entity_delete_mult Môn một lần nữa và tôi nhận thấy rằng các mục bị xóa trong bảng field_collection_item nhưng các trường vẫn tồn tại trong bảng field_data_field_collection_name. Tôi nghĩ rằng điều này gây ra lỗi nghiêm trọng Gọi đến phương thức không xác định stdClass :: save () vì chúng được coi là các trường nhưng chúng không có mục bộ sưu tập trường được liên kết với nó. Khi tôi sử dụng $ field_collection_item-> xóaRevision, nó sẽ xóa dữ liệu trong cả hai bảng nhưng khi tôi lưu người dùng, một hàng sẽ được thêm vào bảng field_data_field_collection_name và đó là mục thu thập trường trống.
Smos

@Smos: Này anh bạn, anh có thể giúp tôi một vấn đề tương tự không ( drupal.stackexchange.com/questions/239784/ít )? Tôi đã thử các bit có liên quan của mã của bạn nhưng tôi không thể làm cho nó hoạt động được.
sisko

Câu trả lời:


13

Tôi đã gặp một trường hợp sử dụng tương tự khi tôi muốn ánh xạ một số dữ liệu vào bộ sưu tập trường trong hook_feed_presave () do cấu trúc nguồn quá phức tạp đối với Nguồn cấp dữ liệu. Tôi thấy rằng entity_delete_mult Môn () đã xóa các mục bộ sưu tập trường, nhưng khi tôi chỉnh sửa nút, vẫn còn một loạt bộ sưu tập trường trống ở đó. Bỏ cài đặt và xóa đã thực hiện thủ thuật mà tôi tìm thấy ở đây: https://drupal.stackexchange.com/a/31820/2762

Nếu nguồn cấp dữ liệu đã thay đổi, tôi xóa tất cả các mục bộ sưu tập trường và tạo lại. Hy vọng điều này là hữu ích.

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);

Cách tiếp cận 2 bước này là cách duy nhất hoạt động AFAIK. Đừng quên node_save($node)nút của bạn.
Bernhard Fürst

@ BernhardFürst thực sự chúng tôi không cần node_save($node), DrupalEntityControllersẽ làm công việc này
coffeduong

8

Cách tốt nhất để làm điều này bây giờ là gọi $field_collection->delete()và điều đó sẽ xử lý mọi thứ.

 <?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

Các câu trả lời ở trên không phải là cách tốt nhất, với việc bỏ đặt tất cả các mục khác biến mất khỏi bộ sưu tập trường và cách khác với ->delete()lỗi ném mô-đun Entity.

Cách đúng. Vâng, những gì tôi đã làm là thế này:

Trong trường hợp của tôi, tôi muốn xóa mục cuối cùng trong bộ sưu tập trường

hãy xem mã này, (đối với người mới bắt đầu: "hãy nhớ rằng bạn phải tải thực thể $")

// 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);

đó là tất cả! cách khác là

//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));

Cách trên là sử dụng entity_metadata_wrapperchức năng tốt nhưng với cách đó có một lỗi phức tạp mà tôi không biết cách giải quyết, bạn có thể kiểm tra tại https://drupal.org/node/1880412 và sau khi áp dụng bản vá trong # 9 bạn gặp vấn đề tiếp theo, hãy kiểm tra nó tại đây https://drupal.org/node/2186689 lỗi này cũng là nếu bạn sử dụng ->delete()chức năng.

Hy vọng nó sẽ giúp được ai đó.


0

sử dụng vbo để xóa các mục bộ sưu tập trường. nó sẽ tự động loại bỏ quan hệ trường với thực thể máy chủ lưu trữ mục bộ sưu tập.


0

Tôi gặp vấn đề tương tự, khi tôi nhập dữ liệu từ nguồn cấp dữ liệu vào mục FC. Khi một bản cập nhật cho thực thể máy chủ được tạo từ nguồn cấp dữ liệu và tôi đang nhập những thay đổi đó, tôi muốn đảm bảo rằng mọi mục FC hiện có không còn tồn tại từ nguồn cấp dữ liệu đã bị xóa.

Giải pháp của tôi:

// 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();

Và đó là nó. Hook_field_update ( field_collection_field_update) của Bộ sưu tập trường sẽ đảm nhiệm việc thực sự xóa mọi mục FC hiện có đã được hủy tham chiếu.

Nhược điểm duy nhất của điều này là nếu không có thay đổi trong dữ liệu FC, dù sao nó cũng bị xóa và được tạo lại. Nhưng đó không phải là một vấn đề lớn đối với tôi.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.