Bir düğümü kaydetmeden önce değiştirilmiş alanları özel bir formda genel olarak algılama


12

Bir alan türü belirli alanları field_attach_form () kullanarak özel bir forma ekliyorum. Form gönderildiğinde, #validate ve #submit geri çağrılarından field_attach_form_validate () ve field_attach_submit () yöntemlerini çağırarak bu alanları işliyorum.

Bu noktada, post-post, hazırlanmış düğüm nesnesini orijinal düğüme karşılaştırmak ve yalnızca alanlardan herhangi biri değiştiğinde node_save () ile uğraşmak istiyorum. Bu nedenle, orijinal düğümü kullanarak yükleyerek başlıyorum entity_load_unchanged().

Ne yazık ki, orijinal düğüm nesnesindeki alan dizileri, alanlarda değişiklik yapılmasa bile, kaydedilmeyi bekleyen hazırlanmış düğüm nesnesindeki alan dizileriyle eşleşmiyor, bu nedenle basit bir "$ old_field == $ new_field "karşılaştırma imkansız. Örneğin, orijinalde şöyle basit bir metin alanı görünür:

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

Oysa hazırlanan düğümde böyle görünür.

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

Sadece 'değer' anahtarını karşılaştırmayı düşünebilirsiniz, ancak daha sonra 'değer' anahtarları olmayan diğer öğelerden oluşan alanlarla karşılaşırsınız. Örneğin, hiçbir 'değer' anahtar olduğu bir adres alanına Bakalım ve karşılık bulmaz hem eski hem de hazırlanan nodlarında tuşları vardır.

Eski düğüm

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

Hazırlanan düğüm

$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',
);

Boş alanlar için başka bir tutarsızlık daha vardır.

Eski düğüm

$old_node->field_text = array();

Hazırlanan düğüm

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

Değişip değişmediğini tespit etmek için herhangi bir alanın eski ve yeni değerini genel olarak karşılaştırabilir miyim?
Bu sadece bir imkansızlık mı?


Bence oynayabilir _field_invoke()ya da "hazırlanan" düğümden tam alan yapısı hazırlamak, her iki alanı render ve sadece bu HTML dizeleri karşılaştırın ilgili bir şey düşünüyorum . Sadece bir fikir.
kalabro

@kalabro Evet kesinlikle bu yol, performans için oldukça kötü olacağını hissetmeye yardımcı olamıyorum - genel yapmak için form gönderimini kullanarak her alan bilgisini ayrı ayrı yüklemeniz gerekir. Veya veri almak için birleştirilmiş bir sorgu yazabilirsiniz sanırım, ama sonra önemli kancalar ateş olmayabilir. Kavramsal olarak mümkün görünüyor, ancak bence bir uygulama oldukça karmaşık olacak
Clive

@kalabro Bu fikri tam olarak anlamıyorum. Alan yapısının nasıl hazırlanacağını göstermek ve sonra açıkladığınız gibi göstermek için bazı sözde kod gönderebilir misiniz?
morbiD

Yanıtlar:


9

Bu, sonunda, genel bir çözüm olarak çalışmalıdır. Tüm girişler için Clive ve morbiD sayesinde.

Düğümün her iki sürümünü de aşağıdaki işleve geçirin. Olacak:

  1. Algılanan içerik türünün tüm düzenlenebilir alanlarını ve düzenlenebilir sütunlarını (yani, özel formda görünebilecek öğeler) tek bir sorguda veritabanından çekin.

  2. Her iki sürümde de tamamen boş olan alanları ve sütunları yok sayın.

  3. İki sürüm arasında farklı sayıda değer içeren bir alanı değişiklik olarak kabul edin.

  4. Her alanı, değeri ve sütunu yineleyin ve iki sürümü karşılaştırın.

  5. Öğeleri sayısal değilse aynı şekilde (! =) Ve başka bir şeydeyse aynı şekilde (! ==) karşılaştırın.

  6. Algıladığı ilk değişiklikten hemen sonra TRUE değerini döndürün (bir değişiklik düğümü yeniden kaydetmemiz gerektiğini bilmek için yeterli olduğundan).

  7. Tüm değerler karşılaştırıldıktan sonra herhangi bir değişiklik algılanmazsa FALSE değerini döndürün.

  8. Alan koleksiyonlarını, şemalarını yükleyerek ve sonuçları kendi kendine aktararak tekrar tekrar karşılaştırır. Bu, iç içe geçmiş alan koleksiyonlarını karşılaştırmasına bile izin vermelidir. Kodun Alan Toplama modülüne herhangi bir bağımlılığı OLMAMALIDIR.

Bu kodda daha fazla hata veya yazım hatası olup olmadığını bana bildirin.

/*
 * 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;
}

Bazen hangi alanların değiştiğini bilmek istersiniz. Bunu bilmek için, işlevin bu sürümünü kullanabilirsiniz:

/*
 * 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;
}

Bazen bir düğümün belirli alanlarının değiştirilmesi, düğümün "değiştirilmiş" zaman damgasının güncellenmesine neden olmayacak şekilde yapmak isteyebilirsiniz. Bu aşağıdaki gibi uygulanabilir:

/**
 * 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) Sıkılaştırılmış saha toplama desteği. Birden çok değere sahip alanlar için destek eklendi.

DÜZENLE (7/31/2015) Hangi alanların değiştiğini döndüren işlevin sürümü ve örnek kullanım örneği eklendi.


Bu harika, bunun geliştiricilerin kullanması için bir çeşit api modülünde olması gerektiğini hissediyorum.
Jelle

3

İşte karmaşık sunucu tarafı değer karşılaştırmasını önleyen ve herhangi bir formla çalışacak başka, daha basit bir yaklaşım:

  1. Form değerlerinin değişip değişmediğini tespit etmek için jQuery kullanın
  2. Formun değiştiğini göstermek için gizli bir öğe değeri ayarlayın.
  3. Gizli öğe değeri sunucu tarafını kontrol edin ve gerektiği gibi işleyin.

Https://github.com/codedance/jquery gibi bir jQuery kirli form eklentisi kullanabilirsiniz.

Formu dinlemenize izin veren diğerleri değişti / kirli durumu da işe yarayacaktır.

Gizli form öğesinin değerini ayarlamak için bir dinleyici ekleyin:

Javascript devre dışı bırakılmış kullanıcılar için varsayılan olarak kaydetmek üzere gizli form öğesini varsayılan olarak 'değiştirildi' olarak ayarlayın (~% 2).

Örneğin:

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

Daha sonra gizli öğenin değerini kontrol edebilirsiniz

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

formunuzda işleyicileri doğrulayın / gönderin.


2
Güzel çözüm, açıkçası js olmayan bazı kullanıcılar olmasına rağmen. Ayrıca, drupal çekirdeğinin misc / form.js dosyasında Drupal.behaviors.formUpdated dosyasına bakın. Dikkat edilmesi gereken başka bir şey, bazı wysiwyg editörlerinin ve drupal modüllerinin çalışma şekliyle, değişen bir değeri tespit etmenin her zaman olması gerektiği kadar basit olmadığıdır.
rooby

Evet, gizli öğe için varsayılan olarak "değiştirildi" değeri ayarlandığında js etkin olmayan az sayıda kullanıcı için varsayılan olarak kaydedilecektir - küçük yüzde. Drupal.behaviors.formUpdatedBelki de ilgili ilginç bir not val(), gerçekte değer değişmeden tetiklenecek gibi görünse de bağlantılı olabilir (örneğin, tıklama olayını içerir), ancak özel eklentiler, gerçek değiştirilmiş form değerlerini tespit etmede daha iyidir.
David Thomas

0

Bunun mükemmel olduğundan emin değilim, ama neden düğüm nesneleri yerine formları karşılaştırarak onu tersine çevirmiyorsunuz ?

Kesinlikle bir düğüm formunda olduğunuzdan emin değilim, ancak yine de formu eski düğümünüz ve yeni düğümünüzle oluşturabilirsiniz:

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

Formlarınızı karşılaştırın ...

Umarım iyi bir iz ... bana haber ver.


Zaten drupal_get_form () içine bakmıştım ama 2 düğüm olarak $ düğüm geçebilir farkında değildi. Ancak, sadece yukarıdaki örnek kodunuzu test ettim ve ne yazık ki, döndürülen dizi yapıları aynı olsa da, değerler değildir. Test ettiğim adres alanı için bu özyinelemeli dizi_diff_assoc () 'a bir göz atın: i.imgur.com/LUDPu1R.jpg
morbiD

Ben array_diff_assoc görüyorum, ama her iki drupal_get_form dpm vermek için zaman var mı? Bunun etrafında bir yol olabilir.
Gregory Kapustin

0

İşte hook_node_presave ($ node) kullanan bir yöntem. Bu sadece bir mockup, eğer yardımcı olduğunu düşünüyorsanız, test edin ve ihtiyaçlarınıza göre geliştirin!

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

Her alan değeri için, $ düğümünde tanımlanan örneklerin tanımlanmış ve $ düğümü_before'de eşit olması gerektiğini varsayalım. Ben $ node_before ve $ düğümünde olmayan alan değeri alanları için umurumda değil, onlar aynı kalmak varsayalım.


Belki bir şey eksik, ama hook_node_presave () ima node_save () çağrıldığını ima etmez? Hiçbir alan değiştirilmediyse node_save () çağrısından kaçınmaya çalışıyoruz.
morbiD

Doğru, bu kanca node_save () içinde çağrılır. Ancak mymodule_node_presave () içinde drupal_goto () yöntemini çağırarak kaydetmeyi iptal edebilirsiniz.
dxvargas

2
@hiphip Bu gerçekten iyi bir fikir değil, ortasında yönlendirirseniz düğümü tutarsız bir durumda saklayacaksınız
Clive

0

Bu sadece birlikte kodladığım bazı kodlar. Tüm bacak işlerini yapmak için tüm kredinin @eclecto adresine gitmesi gerekir. Bu, düğüm nesnelerini doğrudan alan, DB isabetlerini biraz azaltan ve dil müzakere süreciyle ilgilenen (benzer şekilde test edilmemiş) bir varyasyondur.

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
Yeni versiyonumla aynı çizgileri düşünmemi sağladın. Düğüm tipi akıl kontrolü bile dahil.
Eric N

0

Verilen cevap harika ve bana yardımcı oldu, ama düzeltmem gereken bir şey var.

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

In foreach()döngü, ben değiştirmek zorunda $new_fieldiçin $old_field. Bu Drupal veya sadece benim kod (başka bir yerde başka bir kod nedeniyle olabilir) yeni bir sürümü olup olmadığını bilmiyorum, ama erişimim yok $new_field['entity'].


Sadece taze bir Drupal 7.41 kurulumunda _fields_changed () işlevini test ettim ve bir field_collection ile bir düğümü kaydetme bana bu $ old_field ve $ new_field veriyor . Görünüşe göre $ old_entity ve $ new_entity parametreleriyle _fields_changed () öğesini yanlış yolla çağırıyor olabilirsiniz (ya da yanlışlıkla kodunuzdaki değişken adlarını bir yere değiştirdiniz).
morbiD

0

Gönderi için teşekkürler, gerçekten çok zaman kazandım. Ben fonksiyon çıktı olduğunu uyarıları ve uyarıları bir demet sabit:

/*
 * 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;
}

Lütfen bu kodun orijinal soruya nasıl yanıt verdiğini açıklayın (yalnızca bazı kodların yayınlanması buradaki kurallara uygun değildir).
Pierre.Vriens
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.