Rilevamento generico dei campi modificati in un modulo personalizzato prima di salvare un nodo


12

Sto aggiungendo alcuni campi da un tipo di contenuto in un modulo personalizzato utilizzando field_attach_form (). Quando il modulo viene inviato, sto elaborando quei campi chiamando field_attach_form_validate () e field_attach_submit () da #validate e #submit callbacks.

A quel punto, voglio confrontare l'oggetto nodo preparato post-invio con il nodo originale e preoccuparmi solo di node_save () se uno dei campi è cambiato. Pertanto, inizio caricando il nodo originale utilizzando entity_load_unchanged().

Sfortunatamente, le matrici di campi nell'oggetto nodo originale non corrispondono alle matrici di campi nell'oggetto nodo preparato che è in attesa di essere salvato, anche se non sono state apportate modifiche ai campi, quindi un semplice "$ old_field == $ new_field "il confronto è impossibile. Ad esempio, un semplice campo di testo appare così nell'originale:

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

Mentre nel nodo preparato appare così.

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

Potresti pensare di confrontare semplicemente la chiave "valore", ma poi ti imbatti in campi costituiti da altri elementi che non hanno chiavi "valore". Ad esempio, diamo un'occhiata a un campo indirizzo in cui non esiste una chiave 'value' e ci sono chiavi sia nei nodi vecchi che preparati che non hanno controparti.

Nodo vecchio

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

Nodo preparato

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

Per i campi vuoti, c'è ancora un'altra discrepanza.

Nodo vecchio

$old_node->field_text = array();

Nodo preparato

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

Posso confrontare genericamente il vecchio e il nuovo valore di un campo per rilevare se è cambiato o no?
È solo impossibile?


Penso che puoi giocare con _field_invoke()qualcosa o qualcosa di simile per preparare la struttura di campo completa dal nodo "preparato", renderizzare entrambi i campi e semplicemente confrontare queste stringhe HTML. Solo un'idea
Kalabro,

@kalabro Sì, è sicuramente la strada da percorrere, ma non posso fare a meno di pensare che sarebbe piuttosto male per le prestazioni - per renderlo generico dovresti caricare ogni bit di informazioni sul campo singolarmente usando l'invio del modulo. Oppure suppongo che potresti scrivere una query aggregata per ottenere i dati, ma quindi gli hook importanti potrebbero non attivarsi. Concettualmente sembra possibile, ma penso che un'implementazione sarebbe piuttosto complicata
Clive

@kalabro Non capisco bene questa idea. Potresti pubblicare alcuni pseudocodici per dimostrare come preparare la struttura del campo e renderlo come descritto?
morbiD

Risposte:


9

Questo, alla fine, dovrebbe funzionare come una soluzione generica. Grazie a Clive e MorbiD per tutto l'input.

Passare entrambe le versioni del nodo alla seguente funzione. Lo farà:

  1. Estrarre tutti i campi modificabili del tipo di contenuto rilevato e le relative colonne modificabili (ovvero gli elementi che potrebbero apparire sul modulo personalizzato) dal database in una singola query.

  2. Ignora campi e colonne completamente vuoti in entrambe le versioni.

  3. Tratta un campo con un diverso numero di valori tra le due versioni come una modifica.

  4. Scorri attraverso ogni campo, valore e colonna e confronta le due versioni.

  5. Confronta gli elementi in modo non identico (! =) Se sono numerici e in modo identico (! ==) se sono qualcos'altro.

  6. Restituisce immediatamente VERO alla prima modifica rilevata (poiché una modifica è sufficiente per sapere che è necessario salvare nuovamente il nodo).

  7. Restituisce FALSO se non viene rilevata alcuna modifica dopo il confronto di tutti i valori.

  8. Confronta ricorsivamente le raccolte di campi caricandole e il loro schema e passando i risultati a se stessa. Questo DOVREBBE anche consentirgli di confrontare raccolte di campi nidificati. Il codice NON dovrebbe avere alcuna dipendenza dal modulo Raccolta campi.

Fammi sapere se ci sono altri bug o errori di battitura in questo codice.

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

A volte sei interessato a sapere quali campi sono cambiati. Per saperlo, è possibile utilizzare questa versione della funzione:

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

A volte potresti voler fare in modo che la modifica di determinati campi di un nodo non causi l'aggiornamento del timestamp "modificato" di quel nodo. Questo potrebbe essere implementato come segue:

/**
 * 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 (30/07/2013) Supporto rafforzato per la raccolta sul campo. Aggiunto supporto per campi con più valori.

EDIT (31/07/2015) Aggiunta la versione della funzione che restituisce quali campi sono stati modificati, ed esempio caso d'uso.


È fantastico, penso che questo dovrebbe essere in una sorta di modulo API che gli sviluppatori possono usare.
Jelle,

3

Ecco un altro approccio, più semplice, che evita i complessi confronti del valore lato server e funzionerebbe con qualsiasi forma:

  1. Utilizzare jQuery per rilevare se i valori del modulo sono stati modificati
  2. Impostare un valore di elemento nascosto per indicare che il modulo è stato modificato.
  3. Controllare il lato server con valore dell'elemento nascosto ed elaborarlo come richiesto.

È possibile utilizzare un plugin jQuery per moduli sporchi come https://github.com/codedance/jquery.AreYouSure

Anche se altri che ti consentono di ascoltare il modulo sono cambiati / lo stato sporco funzionerebbe anche.

Aggiungi un listener per impostare il valore di un elemento modulo nascosto:

Impostare l'elemento del modulo nascosto su un valore predefinito di "modificato" per salvare per impostazione predefinita per quegli utenti con javascript disabilitato (~ 2%).

per esempio:

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

È quindi possibile verificare il valore dell'elemento nascosto

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

nel tuo modulo convalida / invia i gestori.


2
Bella soluzione, anche se ovviamente ci sono alcuni utenti senza js. Inoltre, controlla Drupal.behaviors.formUpdated nel file misc / form.js del core drupal. Un'altra cosa da notare è che con il modo in cui funzionano alcuni editor wysiwyg e i loro moduli drupal, rilevare un valore modificato non è sempre così semplice come dovrebbe essere.
Rooby,

Sì, l'impostazione di un valore predefinito 'modificato' per l'elemento nascosto salverebbe per impostazione predefinita per quei pochi utenti senza js abilitato - piccola percentuale. Una nota interessante per quanto riguarda Drupal.behaviors.formUpdatedforse val()potrebbe essere collegata a quella anche se sembra che si innescherà senza che il valore cambi effettivamente (per esempio include l'evento click), mentre i plugin dedicati sono migliori nel rilevare i valori di forma cambiati effettivi.
David Thomas,

0

Non sono sicuro che sia perfetto, ma perché non farlo al contrario, confrontando le forme anziché gli oggetti nodo ?

Non sono sicuro che tu sia rigorosamente in un modulo nodo, ma comunque puoi renderizzare il modulo con il tuo vecchio nodo e il tuo nuovo nodo:

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

Confronta i tuoi moduli ...

Spero sia una buona pista ... fammi sapere.


Avevo già esaminato drupal_get_form () ma non mi ero reso conto che potresti passarci $ node come secondo parametro. Tuttavia, ho appena testato il codice di esempio sopra e sfortunatamente, mentre le strutture di array restituite sono le stesse, i valori non lo sono. Dai un'occhiata a questo array_diff_assoc () ricorsivo per il campo dell'indirizzo con cui sto testando: i.imgur.com/LUDPu1R.jpg
morbiD

Vedo che array_diff_assoc, ma avresti il ​​tempo di dare il dpm di entrambi drupal_get_form? Potrebbe esserci un modo per aggirare questo.
Gregory Kapustin,

0

Ecco un metodo che utilizza hook_node_presave ($ node). È solo un modello, se pensi che aiuti, testalo e miglioralo in base alle tue esigenze!

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

Suppongo che, per ogni valore di campo, le istanze definite in $ node debbano essere definite e uguali in $ node_before. Non mi importa dei campi del valore di campo che si trovano in $ node_before e non si trovano in $ node, suppongo che rimangano gli stessi.


Forse mi manca qualcosa, ma hook_node_presave () non implica che node_save () sia stato chiamato? Stiamo cercando di evitare di chiamare node_save () se non sono stati modificati campi.
morbiD

È vero, questo hook è chiamato all'interno di node_save (). Puoi comunque annullare il salvataggio chiamando drupal_goto () all'interno di mymodule_node_presave ().
dxvargas,

2
@hiphip Questa non è davvero una buona idea, lascerai il nodo salvato in uno stato incoerente se reindirizzi nel mezzo di esso
Clive

0

Questo è solo un po 'di codice che ho messo insieme. Tutto il merito deve essere andato a @eclecto per fare tutto il lavoro delle gambe. Questa è solo una variazione (allo stesso modo non testata) che prende direttamente gli oggetti del nodo, riduce un po 'gli hit del DB e si occupa della negoziazione del linguaggio.

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
Mi hai fatto pensare allo stesso modo con la mia nuova versione. Ho anche incluso il controllo di integrità del tipo di nodo.
Eric N,

0

La risposta fornita è ottima e mi ha aiutato, ma c'è qualcosa che ho dovuto correggere.

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

Nel foreach()ciclo, ho dovuto cambiare da $new_fielda $old_field. Non so se questa è una nuova versione di Drupal o solo il mio codice (potrebbe essere dovuto a un altro codice da qualche altra parte), ma non ho accesso a $new_field['entity'].


Ho appena testato la funzione _fields_changed () su una nuova installazione di Drupal 7.41 e il salvataggio di un nodo con field_collection mi dà questo $ old_field e $ new_field . Mi sembra che potresti chiamare _fields_changed () con i parametri $ old_entity e $ new_entity nel modo sbagliato (o hai scambiato accidentalmente i nomi delle variabili nel tuo codice da qualche parte).
morbiD

0

Grazie per il post, mi hai davvero risparmiato un sacco di tempo. Ho corretto un sacco di avvertimenti e avvisi che la funzione stava generando:

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

Spiegare in che modo questo codice risponde alla domanda originale (solo pubblicare un codice non è conforme alle regole qui intorno).
Pierre.Vriens,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.