नोड को सहेजने से पहले कस्टम रूप में परिवर्तित फ़ील्ड का सामान्य रूप से पता लगाना


12

मैं फ़ील्ड_टैच_फॉर्म () का उपयोग करके सामग्री प्रकार से कुछ फ़ील्ड को कस्टम रूप में जोड़ रहा हूं। जब फॉर्म सबमिट किया जाता है, तो मैं उन क्षेत्रों को फ़ील्ड कर रहा हूं जो #_idachate और #submit callbacks से field_attach_form_validate () और field_attach_submit () कॉल करके कर रहा है।

उस बिंदु पर, मैं पोस्ट-सबमिट, तैयार नोड ऑब्जेक्ट की तुलना मूल नोड से करना चाहता हूं और केवल नोड_सेवे () को परेशान करता हूं यदि कोई फ़ील्ड बदल गई है। इसलिए, मैं मूल नोड का उपयोग करके लोड करना शुरू करता हूं entity_load_unchanged()

दुर्भाग्य से, मूल नोड ऑब्जेक्ट में फ़ील्ड सरणियाँ तैयार नोड ऑब्जेक्ट में फ़ील्ड सरणियों से मेल नहीं खाती हैं, जो सहेजने की प्रतीक्षा कर रही है, भले ही फ़ील्ड में कोई परिवर्तन नहीं किया गया हो, इसलिए एक सरल "$ old_field == $ new_field “तुलना असंभव है। उदाहरण के लिए, एक साधारण पाठ फ़ील्ड मूल में इस तरह दिखाई देता है:

$old_node->field_text['und'][0] = array(
  'value' => 'Test',
  'format' => NULL,
  'safe_value' => 'Test',
);

जबकि तैयार नोड में यह इस तरह दिखाई देता है।

$node->field_text['und'][0] = array(
  'value' => 'Test',
);

आप केवल 'मान' कुंजी की तुलना करने के लिए सोच सकते हैं, लेकिन फिर आप अन्य तत्वों से बने क्षेत्रों में भाग लेते हैं, जिनमें 'मान' कुंजी नहीं होती है। उदाहरण के लिए, आइए एक पता फ़ील्ड देखें जहां कोई 'मान' कुंजी नहीं है और पुराने और तैयार किए गए दोनों नोड्स में चाबियाँ हैं जिनके समकक्ष नहीं हैं।

पुराना नोड

$old_node->field_address['und'][0] = array(
  'country' => 'GB',
  'administrative_area' => 'Test',
  'sub_administrative_area' => NULL,
  'locality' => 'Test',
  'dependent_locality' => NULL,
  'postal_code' => 'Test',
  'thoroughfare' => 'Test',
  'premise' => 'Test',
  'sub_premise' => NULL,
  'organisation_name' => 'Test',
  'name_line' => 'Test',
  'first_name' => NULL,
  'last_name' => NULL,
  'data' => NULL,
);

तैयार नोड

$node->field_address['und'][0] = array(
  'element_key' => 'node|page|field_address|und|0',
  'thoroughfare' => 'Test',
  'premise' => 'Test',
  'locality' => 'Test',
  'administrative_area' => 'Test',
  'postal_code' => 'Test',
  'country' => 'GB',
  'organisation_name' => 'Test',
  'name_line' => 'Test',
);

खाली खेतों के लिए, अभी तक एक और विसंगति है।

पुराना नोड

$old_node->field_text = array();

तैयार नोड

$node->field_text = array(
  'und' => array(),
);

क्या मैं यह पता लगाने के लिए किसी भी क्षेत्र के पुराने और नए मूल्य की उदारता से तुलना कर सकता हूं कि यह बदल गया है या नहीं?
क्या यह सिर्फ एक असंभावना है?


मुझे लगता है कि आप _field_invoke()"तैयार" नोड से पूर्ण क्षेत्र संरचना तैयार करने के लिए या कुछ से संबंधित खेल सकते हैं , दोनों क्षेत्रों को प्रस्तुत कर सकते हैं और बस इन HTML स्ट्रिंग्स की तुलना कर सकते हैं। एक विचार है।
कलाब्रो

@kalabro हाँ, यह निश्चित रूप से जाने का रास्ता है, मैं यह महसूस करने में मदद नहीं कर सकता कि प्रदर्शन के लिए काफी बुरा होगा - हालांकि यह सामान्य बनाने के लिए आपको फॉर्म सबमिट करने का उपयोग करके व्यक्तिगत रूप से प्रत्येक फ़ील्ड जानकारी को लोड करना होगा। या मुझे लगता है कि आप डेटा प्राप्त करने के लिए एक समग्र क्वेरी लिख सकते हैं, लेकिन तब महत्वपूर्ण हुक आग नहीं कर सकते हैं। सैद्धांतिक रूप से यह संभव लगता है, लेकिन मैं एक कार्यान्वयन काफी जटिल हो जाएगा लगता है
क्लाइव

@ कल्ब्रो मैं इस विचार को काफी नहीं समझता। क्या आप फ़ील्ड संरचना तैयार करने के लिए कुछ छद्मकोड प्रदर्शित कर सकते हैं और फिर जैसा आपने बताया है, उसे प्रस्तुत करें?
morbiD

जवाबों:


9

यह, लंबे समय तक, सामान्य समाधान के रूप में काम करना चाहिए। सभी इनपुट के लिए क्लाइव और मोरबीडी को धन्यवाद।

निम्न फ़ंक्शन के लिए नोड के दोनों संस्करणों को पास करें। यह:

  1. किसी भी क्वेरी में डेटाबेस से सभी ज्ञात सामग्री प्रकार के संपादन योग्य फ़ील्ड और उनके संपादन योग्य कॉलम (यानी आइटम जो संभवतः कस्टम रूप में प्रकट हो सकते हैं) को खींच लें।

  2. फ़ील्ड और स्तंभों को अनदेखा करें जो दोनों संस्करणों में पूरी तरह से खाली हैं।

  3. एक ऐसे क्षेत्र का इलाज करें जिसमें बदलाव के रूप में दो संस्करणों के बीच भिन्न मान हैं।

  4. हर क्षेत्र, मान और स्तंभ के माध्यम से परिवर्तन करें और दो संस्करणों की तुलना करें।

  5. यदि वे कुछ और हैं तो गैर-पहचान वाले (!)) की तुलना करें यदि वे संख्यात्मक और पहचान के हैं (! ==)।

  6. पहले परिवर्तन पर तत्काल वापस लौटें यह पता लगाता है (चूंकि एक परिवर्तन यह जानने के लिए पर्याप्त है कि हमें नोड को फिर से लिखना होगा)।

  7. यदि सभी मानों की तुलना के बाद कोई परिवर्तन नहीं पाया गया है, तो FALSE लौटें।

  8. उन्हें और उनके स्कीमा को लोड करके और परिणामों को स्वयं पास करके पुन: फ़ील्ड संग्रह की तुलना करें। यह भी इसे नेस्टेड फील्ड संग्रह की तुलना करने की अनुमति देता है। कोड को फ़ील्ड संग्रह मॉड्यूल पर कोई निर्भरता नहीं होनी चाहिए।

आपको बता दें कि इस कोड में कोई और बग या टाइपो हैं।

/*
 * Pass both versions of the node to this function. Returns TRUE if it detects any changes and FALSE if not.
 * Pass field collections as an array keyed by field collection ID.
 *
 * @param object $old_entity
 *   The original (stored in the database) node object.
 *   This function may also pass itself a FieldCollectionItemEntity object to compare field collections.
 * @param object $new_entity
 *   The prepared node object for comparison.
 *   This function may also pass itself a FieldCollectionItemEntity object to compare field collections.
 */
function _fields_changed($old_entity, $new_entity) {
  // Check for node or field collection.
  $entity_is_field_collection = (get_class($old_entity) == 'FieldCollectionItemEntity');

  $bundle = ($entity_is_field_collection ? $old_entity->field_name : $old_entity->type);

  // Sanity check. Exit and throw an error if the content types don't match.
  if($bundle !== ($entity_is_field_collection ? $new_entity->field_name : $new_entity->type)) {
    drupal_set_message('Content type mismatch. Unable to save changes.', 'error');
    return FALSE;
  }

  // Get field info.
  $field_read_params = array(
    'entity_type' => ($entity_is_field_collection ? 'field_collection_item' : 'node'),
    'bundle' => $bundle
  );
  $fields_info = field_read_fields($field_read_params);

  foreach($fields_info as $field_name => $field_info) {
    $old_field = $old_entity->$field_name;
    $new_field = $new_entity->$field_name;

    // Check the number of values for each field, or if they are populated at all.
    $old_field_count = (isset($old_field[LANGUAGE_NONE]) ? count($old_field[LANGUAGE_NONE]) : 0);
    $new_field_count = (isset($new_field[LANGUAGE_NONE]) ? count($new_field[LANGUAGE_NONE]) : 0);

    if ($old_field_count != $new_field_count) {
      // The two versions have a different number of values. Something has changed.
      return TRUE;
    } elseif ($old_field_count > 0 && $new_field_count > 0) {
      // Both versions have an equal number of values. Time to compare.

      // See if this field is a field collection.
      if ($field_info['type'] == 'field_collection') {

        foreach ($new_field[LANGUAGE_NONE] as $delta => $values) {
          $old_field_collection = entity_load_unchanged('field_collection_item', $values['entity']->item_id);
          $new_field_collection = $values['entity'];

          if (_fields_changed($old_field_collection, $new_field_collection)) {
            return TRUE;
          }
        }
        unset($delta, $values);

      } else {
        foreach($old_field[LANGUAGE_NONE] as $delta => $value) {
          foreach($field_info['columns'] as $field_column_name => $field_column_info) {
            $old_value = $old_field[LANGUAGE_NONE][$delta][$field_column_name];
            $new_value = $new_field[LANGUAGE_NONE][$delta][$field_column_name];
            $field_column_type = $field_column_info['type'];

            // As with the overall field, exit if one version has a value and the other doesn't.
            if (isset($old_value) != isset($new_value)) {
              return TRUE;
            } elseif (isset($old_value) && isset($new_value)) {
              // The column stores numeric data so compare values non-identically.
              if (in_array($field_column_type, array('int', 'float', 'numeric'))) {
                if ($new_value != $old_value) {
                  return TRUE;
                }
              }
              // The column stores non-numeric data so compare values identically,
              elseif ($new_value !== $old_value) {
                return TRUE;
              }
            } else {
              // Included for clarity. Both values are empty so there was obviously no change.
            }
          } 
          unset($field_column_name, $field_column_info);
        }
        unset($delta, $value);
      }
    } else {
      // Included for clarity. Both values are empty so there was obviously no change.
    }
  }
  unset($field_name, $field_info);
  // End of field comparison loop.

  // We didn't find any changes. Don't resave the node.
  return FALSE;
}

कभी-कभी आप यह जानने में रुचि रखते हैं कि कौन से क्षेत्र बदले हैं। यह जानने के लिए कि, आप फ़ंक्शन के इस संस्करण का उपयोग कर सकते हैं:

/*
 * Pass both versions of the node to this function. Returns an array of
 * fields that were changed or an empty array if none were changed.
 * Pass field collections as an array keyed by field collection ID.
 *
 * @param object $old_entity
 *   The original (stored in the database) node object.
 *   This function may also pass itself a FieldCollectionItemEntity object to compare field collections.
 * @param object $new_entity
 *   The prepared node object for comparison.
 *   This function may also pass itself a FieldCollectionItemEntity object to compare field collections.
 */
function _fields_changed($old_entity, $new_entity) {
  // Check for node or field collection.
  $entity_is_field_collection = (get_class($old_entity) == 'FieldCollectionItemEntity');

  $bundle = ($entity_is_field_collection ? $old_entity->field_name : $old_entity->type);

  // Sanity check. Exit and throw an error if the content types don't match.
  if ($bundle !== ($entity_is_field_collection ? $new_entity->field_name : $new_entity->type)) {
    drupal_set_message('Content type mismatch. Unable to save changes.', 'error');
    return FALSE;
  }

  // Get field info.
  $field_read_params = array(
    'entity_type' => ($entity_is_field_collection ? 'field_collection_item' : 'node'),
    'bundle' => $bundle
  );
  $fields_info = field_read_fields($field_read_params);

  $fields_changed = array();

  foreach ($fields_info as $field_name => $field_info) {
    $old_field = $old_entity->$field_name;
    $new_field = $new_entity->$field_name;

    // Check the number of values for each field, or if they are populated at all.
    $old_field_count = (isset($old_field[LANGUAGE_NONE]) ? count($old_field[LANGUAGE_NONE]) : 0);
    $new_field_count = (isset($new_field[LANGUAGE_NONE]) ? count($new_field[LANGUAGE_NONE]) : 0);

    if ($old_field_count != $new_field_count) {
      // The two versions have a different number of values. Something has changed.
      $fields_changed[] = $field_name;
    }
    elseif ($old_field_count > 0 && $new_field_count > 0) {
      // Both versions have an equal number of values. Time to compare.

      // See if this field is a field collection.
      if ($field_info['type'] == 'field_collection') {

        foreach ($new_field[LANGUAGE_NONE] as $delta => $values) {
          $old_field_collection = entity_load_unchanged('field_collection_item', $values['entity']->item_id);
          $new_field_collection = $values['entity'];

          $fields_changed = array_merge($fields_changed, _fields_changed($old_field_collection, $new_field_collection));
        }
        unset($delta, $values);

      }
      else {
        foreach ($old_field[LANGUAGE_NONE] as $delta => $value) {
          foreach ($field_info['columns'] as $field_column_name => $field_column_info) {
            $old_value = $old_field[LANGUAGE_NONE][$delta][$field_column_name];
            $new_value = $new_field[LANGUAGE_NONE][$delta][$field_column_name];
            $field_column_type = $field_column_info['type'];

            // As with the overall field, exit if one version has a value and the other doesn't.
            if (isset($old_value) != isset($new_value)) {
              $fields_changed[] = $old_field;
            }
            elseif (isset($old_value) && isset($new_value)) {
              // The column stores numeric data so compare values non-identically.
              if (in_array($field_column_type, array(
                'int',
                'float',
                'numeric'
              ))) {
                if ($new_value != $old_value) {
                  $fields_changed[] = $field_name;
                }
              }
              // The column stores non-numeric data so compare values identically,
              elseif ($new_value !== $old_value) {
                $fields_changed[] = $field_name;
              }
            }
            else {
              // Included for clarity. Both values are empty so there was obviously no change.
            }
          }
          unset($field_column_name, $field_column_info);
        }
        unset($delta, $value);
      }
    }
    else {
      // Included for clarity. Both values are empty so there was obviously no change.
    }
  }
  unset($field_name, $field_info);
  // End of field comparison loop.

  return $fields_changed;
}

कभी-कभी आप इसे बनाना चाह सकते हैं ताकि नोड के कुछ क्षेत्रों को बदलने से नोड के "परिवर्तित" टाइमस्टैम्प को अद्यतन न किया जाए। इसे इस प्रकार लागू किया जा सकता है:

/**
 * Implements hook_node_presave().
 */
function mymodule_node_presave($node) {
  $fields_changed = _fields_changed($node->original, $node);
  $no_update_timestamp_fields = array('field_subject', 'field_keywords');
  if (!empty($fields_changed) &&
    empty(array_diff($fields_changed, $no_update_timestamp_fields))) {
    // Don't change the $node->changed timestamp if one of the fields has
    // been changed that should not affect the timestamp.
    $node->changed = $node->original->changed;
  }
}

EDIT (7/30/2013) क्षेत्र संग्रह समर्थन को मजबूत किया। कई मूल्यों वाले क्षेत्रों के लिए समर्थन जोड़ा गया।

EDIT (7/31/2015) फंक्शन का वर्जन जोड़ा गया है जो उन फील्ड्स को लौटाता है जो फील्ड में बदल चुके हैं और उदाहरण केस केस।


यह बहुत अच्छा है, मुझे लगता है कि डेवलपर्स के उपयोग के लिए यह किसी प्रकार के एपीआई मॉड्यूल में होना चाहिए।
जेल

3

यहां एक और सरल, दृष्टिकोण है जो जटिल सर्वर साइड मूल्य तुलना से बचा जाता है, और किसी भी रूप में काम करेगा:

  1. प्रपत्र मानों में परिवर्तन हुआ है या नहीं, यह जानने के लिए jQuery का उपयोग करें
  2. प्रपत्र को परिवर्तित करने के लिए एक छिपा तत्व मान सेट करें।
  3. आवश्यक के रूप में छिपा तत्व मूल्य सर्वर पक्ष और प्रक्रिया की जाँच करें।

आप https://github.com/codedance/jquery.AreYouSure जैसे jQuery के गंदे फॉर्म प्लगइन का उपयोग कर सकते हैं

हालाँकि अन्य जो आपको परिवर्तित रूप / गंदे स्थिति को सुनने देते हैं, वे भी काम करेंगे।

छिपे हुए तत्व तत्व का मान सेट करने के लिए एक श्रोता जोड़ें:

जावास्क्रिप्ट अक्षम (~ 2%) के साथ उन उपयोगकर्ताओं के लिए डिफ़ॉल्ट रूप से सहेजने के लिए 'परिवर्तित' के डिफ़ॉल्ट मान के लिए छिपे हुए प्रपत्र तत्व को सेट करें।

उदाहरण के लिए:

// Clear initial state for js-enabled user
$('input#hidden-indicator').val('')
// Add changed listener
$('#my-form').areYouSure({
    change: function() {
      // Set hidden element value
      if ($(this).hasClass('dirty')) {
        $('input#hidden-indicator').val('changed');
      } else {
        $('input#hidden-indicator').val('');
      }
    }
 });

फिर आप छिपे हुए तत्व के मूल्य की जांच कर सकते हैं

if ($form_state['values']['hidden_indicator'] == 'changed') { /* node_save($node) */ }

अपने फ़ॉर्म में हैंडलर को मान्य / जमा करें।


2
अच्छा समाधान, हालांकि स्पष्ट रूप से js के बिना कुछ उपयोगकर्ता हैं। इसके अलावा, Drupal.behaviors.formUpdated को misc / form.js फ़ाइल में drup कोर की जाँच करें। ध्यान देने वाली एक और बात यह है कि जिस तरह से कुछ wysiwyg संपादकों और उनके ड्रूपल मॉड्यूल काम करते हैं, एक बदले हुए मूल्य का पता लगाना हमेशा उतना आसान नहीं होता जितना कि आगे होना चाहिए।
रॉबी

हां, छिपे हुए तत्व के लिए 'परिवर्तित' का डिफ़ॉल्ट मान सेट करने से उन कुछ उपयोगकर्ताओं के लिए डिफ़ॉल्ट रूप से बचत होगी जो बिना सक्षम किए js - छोटा प्रतिशत है। के बारे में दिलचस्प नोट Drupal.behaviors.formUpdatedशायद इसके val()साथ जोड़ा जा सकता है कि हालांकि ऐसा लगता है कि यह वास्तव में बदले मूल्य के बिना ट्रिगर होगा (जैसे क्लिक घटना भी शामिल है), जबकि समर्पित प्लगइन्स वास्तविक परिवर्तित रूप मानों का पता लगाने में बेहतर हैं।
डेविड थॉमस

0

मुझे यकीन नहीं है कि यह सही है, लेकिन नोड वस्तुओं के बजाय रूपों की तुलना करके इसे दूसरे तरीके से क्यों नहीं लिया जा रहा है ?

मुझे यकीन नहीं है कि अगर आप सख्ती से नोड फॉर्म में हैं, लेकिन वैसे भी आप फॉर्म को अपने पुराने नोड और अपने नए नोड के साथ प्रस्तुत कर सकते हैं:

module_load_include('inc', 'node', 'node.pages');
node_object_prepare($new_node);
$new_form = drupal_get_form($new_node->node_type . '_node_form', $new_node);
node_object_prepare($old_node);
$old_form = drupal_get_form($old_node->node_type . '_node_form', $old_node);

अपने रूपों की तुलना करें ...

मुझे उम्मीद है कि यह एक अच्छा ट्रैक है ... मुझे बताएं।


मैंने पहले ही drupal_get_form () में देख लिया था, लेकिन मुझे नहीं पता था कि आप इसे 2 डी पैरामीटर के रूप में $ नोड पास कर सकते हैं। हालाँकि, मैंने अभी ऊपर और दुर्भाग्य से आपके उदाहरण कोड का परीक्षण किया है, जबकि सरणी संरचनाएँ समान हैं, मान नहीं हैं। इस पुनरावर्ती array_diff_assoc () पर पता कर रहा हूँ कि मैं किसके साथ परीक्षण कर रहा हूँ: i.imgur.com/LUDPu1R.jpg
morbiD

मुझे वह array_diff_assoc दिखाई देता है, लेकिन क्या आपके पास drupal_get_form दोनों का dpm देने का समय होगा? इसके आसपास कोई रास्ता हो सकता है।
ग्रेगरी कपुस्टीन

0

यहाँ एक विधि है जो हुक_नोड_स्प्रेस ($ नोड) का उपयोग कर रही है। यह सिर्फ एक मॉकअप है, अगर आपको लगता है कि यह मदद करता है, तो इसका परीक्षण करें और इसे अपनी आवश्यकताओं में सुधार करें!

  /**
   * Implements hook_node_presave().
   *
   * Look for changes in node fields, before they are saved
   */
  function mymodule_node_presave($node) {

    $changes = array();

    $node_before = node_load($node->nid);

    $fields = field_info_instances('node', $node->type);
    foreach (array_keys($fields) as $field_name) {

      $val_before = field_get_items('node', $node_before, $field_name);
      $val = field_get_items('node', $node, $field_name);

      if ($val_before != $val) {

        //if new field values has more instances then old one, it has changed
        if (count($val) != count($val_before)) {
          $changes[] = $field_name;
        } else {
          //cycle throught 1 or multiple field value instances
          foreach ($val as $k_i => $val_i) {
            if (is_array($val_i)) {
              foreach ($val_i as $k => $v) {
                if (isset($val_before[$k_i][$k]) && $val_before[$k_i][$k] != $val[$k_i][$k]) {
                  $changes[] = $field_name;
                }
              }
            }
          }
        }
      }
    }
    dpm($changes);
  }

मुझे लगता है कि, प्रत्येक क्षेत्र मूल्य के लिए, $ नोड में परिभाषित उदाहरणों को परिभाषित किया जाना चाहिए और $ node_before में बराबर होना चाहिए। मैं फील्ड वैल्यू के उन क्षेत्रों की परवाह नहीं करता, जो $ नोड_बेफ़र में हैं और $ नोड में नहीं हैं, मुझे लगता है कि वे समान रहते हैं।


शायद मुझे कुछ याद आ रहा है, लेकिन hook_node_presave () imply node_save () नहीं कहा गया है? यदि कोई फ़ील्ड नहीं बदला गया है, तो हम node_save () को कॉल करने से बचने का प्रयास कर रहे हैं।
morbiD

सही है, इस हुक को नोड_सेवे () के अंदर कहा जाता है। लेकिन आप अभी भी mymodule_node_presave () के अंदर drupal_goto () कॉल करके बचत को रद्द कर सकते हैं।
dxvargas

2
यह वास्तव में एक अच्छा विचार नहीं है @hiphip, यदि आप इसे के बीच में अनुप्रेषित एक असंगत स्थिति में बचाने नोड छोड़ देंगे
क्लाइव

0

यह सिर्फ कुछ कोड है जिन्हें मैंने एक साथ सिल दिया था। सभी काम पैर के सभी काम करने के लिए @eclecto पर जाने चाहिए। यह सिर्फ एक (समान रूप से अप्रयुक्त) भिन्नता है जो नोड ऑब्जेक्ट्स को सीधे लेती है, DB को थोड़ा कम करती है और भाषा की बातचीत का ख्याल रखती है।

function _node_fields_have_changed($old_node, $new_node) {
  // @TODO Sanity checks (e.g. node types match).

  // Get the fields attached to the node type.
  $params = array('entity_type' => 'node', 'bundle' => $old_node->type);
  foreach (field_read_fields($params) as $field) {
    // Get the field data for both nodes.
    $old_field_data = field_get_items('node', $old_node, $field['field_name']);
    $new_field_data = field_get_items('node', $new_node, $field['field_name']);

    // If the field existed on the old node, but not the new, it's changed.
    if ($old_field_data && !$new_field_data) {
      return TRUE;
    }
    // Ditto but in reverse.
    elseif ($new_field_data && !$old_field_data) {
      return TRUE;
    }

    foreach ($field['columns'] as $column_name => $column) {
      // If there's data in both columns we need an equality check.
      if (isset($old_field_data[$column_name]) && isset($new_field_data[$column_name])) {
        // Equality checking based on column type.
        if (in_array($column['type'], array('int', 'float', 'numeric')) && $old_field_data[$column_name] != $new_field_data[$column_name]) {
          return TRUE;
        }
        elseif ($old_field_data[$column_name] !== $new_field_data[$column_name]) {
          return TRUE;
        }
      }
      // Otherwise, if there's data for one column but not the other,
      // something changed.
      elseif (isset($old_field_data[$column_name]) || isset($new_field_data[$column_name])) {
        return TRUE;
      }
    } 
  }

  return FALSE;
}

1
आप मुझे अपने नए संस्करण के साथ उसी तर्ज पर सोच रहे हैं। मैं भी नोड प्रकार विवेक की जाँच शामिल है।
एरिक एन

0

प्रदान किया गया उत्तर बहुत अच्छा है और इससे मुझे मदद मिली, लेकिन कुछ ऐसा है जिसे मुझे सही करना था।

// See if this field is a field collection.
if ($field_info['type'] == 'field_collection') {
  foreach ($old_field[LANGUAGE_NONE] as $delta => $values) {
    $old_field_collection = entity_load_unchanged('field_collection_item', $values['entity']->item_id);
    $new_field_collection = $values['entity'];

    $fields_changed = array_merge($fields_changed, erplain_api_fields_changed($old_field_collection, $new_field_collection));
  }
  unset($delta, $values);
}

में foreach()पाश, मैं से बदलना पड़ा $new_fieldकरने के लिए $old_field। मुझे नहीं पता कि यह ड्रुपल का नया संस्करण है या केवल मेरा कोड (किसी अन्य कोड के कारण कहीं और हो सकता है), लेकिन मेरे पास इसका उपयोग नहीं है $new_field['entity']


मैंने अभी हाल ही में एक नए Drupal 7.41 पर _fields_changed () फ़ंक्शन का परीक्षण किया और एक field_collection के साथ नोड को सहेजने से मुझे यह $ old_field और $ new_field मिलता है । यह मुझे ऐसा लग रहा है कि आप $ old_entity और $ new_entity पैरामीटर्स के साथ _fields_changed () को गलत तरीके से राउंड कह सकते हैं (या आपने गलती से अपने कोड में चर नामों को कहीं स्वैप कर लिया है)।
मोरबी

0

पोस्ट के लिए धन्यवाद, वास्तव में मुझे बहुत समय बचा लिया। मैंने चेतावनियों और सूचनाओं का एक गुच्छा तय किया, जो फ़ंक्शन आउटपुट कर रहा था:

/*
 * Pass both versions of the node to this function. Returns an array of
 * fields that were changed or an empty array if none were changed.
 * Pass field collections as an array keyed by field collection ID.
 *
 * @param object $old_entity
 *   The original (stored in the database) node object.
 *   This function may also pass itself a FieldCollectionItemEntity object to compare field collections.
 * @param object $new_entity
 *   The prepared node object for comparison.
 *   This function may also pass itself a FieldCollectionItemEntity object to compare field collections.
 */
function _fields_changed($old_entity, $new_entity) {
  $fields_changed = array();

  // Check for node or field collection.
  if (is_object($old_entity)) {
    $entity_is_field_collection = (get_class($old_entity) == 'FieldCollectionItemEntity');
    $bundle = !empty($entity_is_field_collection) ? $old_entity->field_name : $old_entity->type;
  }

  // Sanity check. Exit and throw an error if the content types don't match.
  if (is_object($new_entity)) {
    if ($bundle !== (!empty($entity_is_field_collection) ? $new_entity->field_name : $new_entity->type)) {
      drupal_set_message('Content type mismatch. Unable to save changes.', 'error');
      return FALSE;
    }
  }

  // Get field info.
  $field_read_params = array(
    'entity_type' => !empty($entity_is_field_collection) ? 'field_collection_item' : 'node',
  );

  if (!empty($bundle)) {
    $field_read_params['bundle'] = $bundle;
  }

  $fields_info = field_read_fields($field_read_params);

  foreach ($fields_info as $field_name => $field_info) {
    $old_field = isset($old_entity->$field_name) ? $old_entity->$field_name : NULL;
    $new_field = isset($new_entity->$field_name) ? $new_entity->$field_name : NULL;

    // Check the number of values for each field, or if they are populated at all.
    $old_field_count = (isset($old_field[LANGUAGE_NONE]) ? count($old_field[LANGUAGE_NONE]) : 0);
    $new_field_count = (isset($new_field[LANGUAGE_NONE]) ? count($new_field[LANGUAGE_NONE]) : 0);

    if ($old_field_count != $new_field_count) {
      // The two versions have a different number of values. Something has changed.
      $fields_changed[] = $field_name;
    }
    elseif ($old_field_count > 0 && $new_field_count > 0) {
      // Both versions have an equal number of values. Time to compare.

      // See if this field is a field collection.
      if ($field_info['type'] == 'field_collection') {

        foreach ($new_field[LANGUAGE_NONE] as $delta => $values) {
          $old_field_collection = NULL;
          if (!empty($values['entity']->item_id)) {
            $old_field_collection = entity_load_unchanged('field_collection_item', $values['entity']->item_id);
          }

          $new_field_collection = NULL;
          if (isset($values['entity'])) {
            $new_field_collection = $values['entity'];
          }

          $fields_changed = array_merge($fields_changed, _fields_changed($old_field_collection, $new_field_collection));
        }
        unset($delta, $values);

      }
      else {
        foreach ($old_field[LANGUAGE_NONE] as $delta => $value) {
          foreach ($field_info['columns'] as $field_column_name => $field_column_info) {
            $old_value = isset($old_field[LANGUAGE_NONE][$delta][$field_column_name]) ? $old_field[LANGUAGE_NONE][$delta][$field_column_name] : NULL;
            $new_value = isset($new_field[LANGUAGE_NONE][$delta][$field_column_name]) ? $new_field[LANGUAGE_NONE][$delta][$field_column_name] : NULL;
            $field_column_type = $field_column_info['type'];

            // As with the overall field, exit if one version has a value and the other doesn't.
            if (isset($old_value) != isset($new_value)) {
              $fields_changed[] = $old_field;
            }
            elseif (isset($old_value) && isset($new_value)) {
              // The column stores numeric data so compare values non-identically.
              if (in_array($field_column_type, array(
                'int',
                'float',
                'numeric'
              ))) {
                if ($new_value != $old_value) {
                  $fields_changed[] = $field_name;
                }
              }
              // The column stores non-numeric data so compare values identically,
              elseif ($new_value !== $old_value) {
                $fields_changed[] = $field_name;
              }
            }
            else {
              // Included for clarity. Both values are empty so there was obviously no change.
            }
          }
          unset($field_column_name, $field_column_info);
        }
        unset($delta, $value);
      }
    }
    else {
      // Included for clarity. Both values are empty so there was obviously no change.
    }
  }
  unset($field_name, $field_info);
  // End of field comparison loop.

  return $fields_changed;
}

कृपया बताएं कि यह कोड मूल प्रश्न का उत्तर कैसे देता है (केवल कुछ कोड पोस्ट करना यहां के नियमों के अनुरूप नहीं है)।
पियरे.विरेंस
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.