फ़ील्ड संग्रह को ठीक से कैसे हटाएं?


9

Drupal संस्करण: 7.21
फ़ील्ड संग्रह मॉड्यूल संस्करण: 7.x-1.0-beta5

संक्षिप्त विवरण : मैं प्रोग्राम संग्रह को प्रोग्रामेटिक रूप से आयात करने की कोशिश में व्यस्त हूं, लेकिन जब उनमें से कुछ को हटा दिया जाता है तो हमेशा कुछ 'फर्जी' फ़ील्ड संग्रह शेष रह जाता है।

लंबी व्याख्या : मेरे उपयोगकर्ताओं के पास उनकी प्रोफ़ाइल पर फ़ील्ड संग्रह फ़ील्ड है। इस फ़ील्ड संग्रह में 3 टेक्स्ट फ़ील्ड हैं। मैं उपयोगकर्ता के क्षेत्र संग्रह में एक कस्टम sql डेटाबेस से डेटा आयात करना चाहता हूं। इस फ़ील्ड संग्रह में कई मान हो सकते हैं। जब मैं पहली बार डेटा आयात करता हूं तो सब कुछ ठीक काम करता है, मैं डेटा को फ़ील्ड संग्रह के क्षेत्रों में देखता हूं। महान।

लेकिन यहाँ मुश्किल हिस्सा आता है। मान लीजिए कि मैं कस्टम डेटाबेस से एक विशिष्ट उपयोगकर्ता 5 पंक्तियों के लिए आयात करता हूं। वे फ़ील्ड संग्रह में जुड़ जाते हैं, इसलिए इस फ़ील्ड संग्रह में 3 फ़ील्ड वाले 5 आइटम हैं। फिर मैं अपने कस्टम डेटाबेस से कुछ पंक्तियों को हटा देता हूं ताकि मेरे पास इस उपयोगकर्ता के लिए केवल 3 पंक्तियाँ बची रहें। मैं फिर से आयात चलाता हूं, फ़ील्ड संग्रह के पहले 3 आइटम को अपडेट करता हूं, लेकिन फिर मैं पिछले आयात से 2 आइटम के साथ छोड़ दिया जाता हूं। उन्हें हटा दिया जाना चाहिए क्योंकि मेरे पास केवल 3 आयातित पंक्तियाँ हैं लेकिन फिर भी 5 फ़ील्ड संग्रह आइटम हैं।

इसलिए मैंने इन फ़ील्ड संग्रह आइटमों को हटाने का प्रयास किया, लेकिन हमेशा एक या अधिक आइटम शेष हैं। जब मैं उपयोगकर्ता प्रोफ़ाइल को देखता हूं, तो फ़ील्ड खाली हैं, लेकिन वहां अभी भी कुछ है। मान लें कि इस बिंदु पर मैं अपने कस्टम डेटाबेस में उपयोगकर्ता के लिए 5 नई पंक्तियाँ जोड़ता हूं, इसलिए मेरे पास इस उपयोगकर्ता के लिए कुल 8 पंक्तियाँ हैं। फिर मैं फिर से आयात चलाता हूं। पहले 3 आइटम अपडेट हो जाते हैं, लेकिन तब जब मैं 4 वीं पंक्ति को जोड़ने की कोशिश करता हूं, तब भी इसे 4 फील्ड संग्रह आइटम से एक इकाई आईडी मिलती है, इसे अपडेट करने की कोशिश करता है, लेकिन विफल रहता है और इस त्रुटि को वापस करता है:

 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_field_delete के साथ क्या तर्क देना चाहिए? मैं देखता हूं कि हस्ताक्षर field_collection_field_delete ($ एंट्री_टाइप, $ एंटिटी, $ फ़ील्ड, $ इंस्टेंस, $ लैंगकोड, और $ आइटम) है, लेकिन मैं वास्तव में नहीं जानता कि किन मूल्यों में डालूं: $ एंटिटी (यह उपयोगकर्ता या फ़ील्ड संग्रह है) ?), $ फ़ील्ड (field_collection_item_load से वापसी मूल्य?), $ उदाहरण, $ lcode (und?) और $ आइटम।
स्मोच

1
वह विशेष फ़ंक्शन एक हुक कार्यान्वयन है, मूल रूप से किसी भी फ़ील्ड को हटाए जाने पर फ़ील्ड का नाम उस फ़ंक्शन को दिया जाता है, और फ़ील्ड संग्रह जाँचता है कि क्या उस फ़ील्ड उदाहरण से संबंधित कोई एफसी इकाई है। अगर वहाँ है, यह इसे हटाकर उपयोग करता है entity_delete_multiple()। के बाद आप हटाना क्षेत्रों बार के एक जोड़े क्रॉन चलाने के लिए आवश्यकता हो सकती है (फ़ील्ड डेटा किसी शेड्यूल पर बोझ करने के लिए सभी के साथ एक एकल पृष्ठ लोड पर्ज है तो के रूप में नहीं है कि ऐसा करने के लिए प्रसंस्करण)
क्लाइव

मैंने फिर से Unit_delete_multiple का उपयोग करने का प्रयास किया और मैंने देखा कि आइटम तालिका फ़ील्ड_collection_item में हटा दिए जाते हैं, लेकिन फ़ील्ड अभी भी फ़ील्ड field_data_field_collection_name में मौजूद हैं। मुझे लगता है कि यह घातक त्रुटि कॉल को अपरिभाषित विधि stdClass :: save () का कारण बनता है क्योंकि वे फ़ील्ड माना जाता है, लेकिन उनके पास फ़ील्ड संग्रह आइटम नहीं जुड़ा हुआ है। जब मैं $ field_collection_item-> delete का उपयोग करता हूं, तो यह दोनों तालिकाओं में डेटा को हटा देता है, लेकिन जब मैं उपयोगकर्ता को सहेजता हूं तो तालिका फ़ील्ड_data_field_collection_name में एक पंक्ति जुड़ जाती है और यह एक रिक्त फ़ील्ड आइटम होता है।
स्कोस

@Smos: अरे दोस्त, क्या आप मुझे इसी तरह के मुद्दे ( drupal.stackexchange.com/questions/239784/… ) के साथ मदद कर सकते हैं ? मैंने आपके कोड के प्रासंगिक बिट्स की कोशिश की, लेकिन मैं इसे काम नहीं कर पाया।
सिस्को

जवाबों:


13

फीड के लिए स्रोत संरचना बहुत जटिल होने के बाद से मैं एक समान उपयोग के मामले में भाग गया, जहां मैं हुक_फीड्स_स्प्रेस () के दौरान कुछ डेटा को फ़ील्ड संग्रह में मैप करना चाहता था। मैंने पाया कि Unit_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)अपने नोड को मत भूलना ।
बर्नहार्ड फर्स्ट

@ बर्नहार्डफर्स्ट वास्तव में हमें जरूरत नहीं है 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()एंटिटी मॉड्यूल के साथ एक बग को फेंक देता है।

सही तरीका। खैर मैंने यह क्या किया:

मेरे मामले में मैं फील्ड संग्रह के भीतर अंतिम आइटम को हटाना चाहता था

इस कोड पर एक नज़र डालें, (शुरुआत के लिए: "याद रखें कि आपके पास पहले से भरी हुई $ इकाई होनी चाहिए")

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

मेरे पास एक समान मुद्दा था, जहां मैं फ़ीड से एफसी आइटम में डेटा आयात कर रहा हूं। जब एक होस्ट इकाई को फ़ीड से अपडेट किया जाता है, और मैं उन परिवर्तनों को आयात कर रहा हूं, तो मैं यह सुनिश्चित करना चाहता था कि कोई भी मौजूदा एफसी आइटम जो कि फ़ीड स्रोत से मौजूद नहीं हैं, हटा दिए गए थे।

मेरा समाधान:

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

और बस। फ़ील्ड संग्रह के हुक_फ़ील्ड_अपडेट ( field_collection_field_update) वास्तव में किसी भी मौजूदा एफसी आइटम को हटाने का ख्याल रखेगा जो डी- रेफ़र किए गए हैं।

इसका एकमात्र पहलू यह है कि अगर एफसी डेटा में कोई बदलाव नहीं हुआ, तो इसे हटा दिया जाता है और फिर से बनाया जाता है। लेकिन मेरे लिए यह कोई बड़ी बात नहीं है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.