Detectando Genericamente Campos Alterados em um Formulário Customizado Antes de Salvar um Nó

12

Estou adicionando certos campos de um tipo de conteúdo a um formulário personalizado usando field_attach_form (). Quando o formulário é enviado, estou processando esses campos chamando field_attach_form_validate () e field_attach_submit () de #validate e #submit retornos de chamada.

Nesse ponto, desejo comparar o objeto de nó preparado pós-envio com o nó original e me preocupar apenas com node_save () se algum dos campos tiver sido alterado. Portanto, começo carregando o nó original usando entity_load_unchanged().

Infelizmente, as matrizes de campo no objeto de nó original não correspondem às matrizes de campo no objeto de nó preparado que está aguardando para ser salvo, mesmo que nenhuma alteração tenha sido feita nos campos, portanto, um simples "$ old_field == $ new_field "comparação é impossível. Por exemplo, um campo de texto simples aparece assim no original:

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

Enquanto no nó preparado aparece assim.

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

Você pode apenas comparar a chave 'value', mas depois encontra campos compostos de outros elementos que não possuem chaves 'value'. Por exemplo, vejamos um campo de endereço em que não há chave de 'valor' e há chaves nos nós antigos e preparados que não possuem contrapartes.

Nó antigo

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

Nó preparado

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

Para campos vazios, há outra discrepância.

Nó antigo

$old_node->field_text = array();

Nó preparado

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

Posso comparar genericamente o valor antigo e o novo de qualquer campo para detectar se ele foi alterado ou não?
Isso é apenas uma impossibilidade?

mórbido
fonte
Eu acho que você pode brincar _field_invoke()ou algo relacionado para preparar a estrutura de campo completa do nó "preparado", renderizar os dois campos e simplesmente comparar essas seqüências de caracteres HTML. Apenas uma ideia.
22413 kalabro
@kalabro Sim, esse é definitivamente o caminho a percorrer, mas não posso deixar de pensar que isso seria muito ruim para o desempenho - para torná-lo genérico, você precisará carregar todas as informações de campo individualmente usando o envio do formulário. Ou acho que você poderia escrever uma consulta agregada para obter os dados, mas ganchos importantes podem não ser acionados. Conceitualmente, parece possível, mas acho que uma implementação seria bastante complicada
Clive
@kalabro Eu não entendo bem essa idéia. Você poderia postar algum pseudocódigo para demonstrar como preparar a estrutura do campo e depois renderizá-la conforme descrito?
mórbida

Respostas:

9

Por fim, isso deve funcionar como uma solução genérica. Obrigado a Clive e morbiD por toda a entrada.

Passe as duas versões do nó para a seguinte função. Será:

  1. Puxe todos os campos editáveis ​​do tipo de conteúdo detectado e suas colunas editáveis ​​(ou seja, itens que podem aparecer no formulário personalizado) do banco de dados em uma única consulta.

  2. Ignore campos e colunas completamente vazios nas duas versões.

  3. Trate um campo que tenha um número diferente de valores entre as duas versões como uma alteração.

  4. Repita todos os campos, valores e colunas e compare as duas versões.

  5. Compare itens de forma não idêntica (! =) Se eles forem numéricos e idênticos (! ==) se forem outros itens.

  6. Retorne imediatamente TRUE na primeira alteração que detectar (já que uma alteração é suficiente para saber que precisamos salvar novamente o nó).

  7. Retorne FALSE se nenhuma alteração for detectada depois que todos os valores forem comparados.

  8. Compare recursivamente as coleções de campos carregando-as e seu esquema e passando os resultados para si. Isso DEVE mesmo permitir comparar coleções de campos aninhados. O código NÃO deve ter nenhuma dependência no módulo Field Collection.

Informe-me se houver mais erros ou erros de digitação neste código.

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

Às vezes você está interessado em saber quais campos foram alterados. Para saber isso, você pode usar esta versão da função:

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

Às vezes, convém fazer com que a alteração de certos campos de um nó não faça com que o carimbo de data e hora "alterado" desse nó seja atualizado. Isso pode ser implementado da seguinte maneira:

/**
 * 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/7/2013) Suporte reforçado à coleta de campo. Adicionado suporte para campos com vários valores.

EDIT (31/07/2015) Adicionada versão da função que retorna quais campos foram alterados e exemplo de caso de uso.

Eric N
fonte
Isso é ótimo, eu sinto que isso deveria estar em algum tipo de módulo API para os desenvolvedores usarem.
Jelle
3

Aqui está outra abordagem mais simples que evita comparações complexas de valores no servidor e funcionaria de qualquer forma:

  1. Use jQuery para detectar se os valores do formulário foram alterados
  2. Defina um valor de elemento oculto para indicar que o formulário foi alterado.
  3. Verifique o valor do elemento oculto do lado do servidor e processe conforme necessário.

Você pode usar um plugin de formulário sujo do jQuery, como https://github.com/codedance/jquery.AreYouSure

Embora outros que permitem ouvir o status alterado / sujo do formulário também funcionem.

Adicione um ouvinte para definir o valor de um elemento oculto do formulário:

Defina o elemento oculto do formulário como um valor padrão de 'alterado' para salvar por padrão para os usuários com o javascript desativado (~ 2%).

por exemplo:

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

Você pode então verificar o valor do elemento oculto

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

no seu formulário, valide / envie manipuladores.

David Thomas
fonte
2
Solução agradável, embora obviamente haja alguns usuários sem js. Além disso, confira Drupal.behaviors.formUpdated no arquivo misc / form.js do drupal core. Outro aspecto a ser observado é que, com a maneira como alguns editores wysiwyg e seus módulos drupal funcionam, detectar um valor alterado nem sempre é tão direto quanto deveria.
ROOBY
Sim, definir um valor padrão de 'alterado' para o elemento oculto salvaria por padrão os poucos usuários sem js ativado - porcentagem pequena. Nota interessante a respeito Drupal.behaviors.formUpdatedtalvez val()possa estar ligada a isso, embora pareça que será acionada sem que o valor seja realmente alterado (por exemplo, inclui evento click), enquanto os plug-ins dedicados são melhores para detectar valores reais de formulário alterados.
David Thomas
0

Não tenho certeza de que seja perfeito, mas por que não fazer o contrário, comparando os formulários em vez dos objetos do nó ?

Não tenho certeza se você está estritamente em um formulário de nó, mas mesmo assim você pode renderizar o formulário com seu nó antigo e seu novo nó:

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

Compare seus formulários ...

Espero que seja uma boa pista ... me avise.

Gregory Kapustin
fonte
Eu já tinha examinado drupal_get_form (), mas não sabia que você poderia passar o $ node para ele como um segundo parâmetro. No entanto, acabei de testar seu código de exemplo acima e, infelizmente, enquanto as estruturas de matriz retornadas são as mesmas, os valores não são. Ter um olhar para este array_diff_assoc recursiva () para o campo de endereço estou testando com: i.imgur.com/LUDPu1R.jpg
mórbida
Eu vejo esse array_diff_assoc, mas você teria tempo para fornecer o dpm de ambos drupal_get_form? Pode haver uma maneira de contornar isso.
precisa
0

Aqui está um método usando hook_node_presave ($ node). É apenas uma maquete, se você acha que ajuda, teste e melhore para as suas necessidades!

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

Suponho que, para cada valor de campo, as instâncias definidas em $ node devem ser definidas e iguais em $ node_before. Eu não ligo para os campos do valor do campo que estão em $ node_before e não estão em $ node, suponho que eles permaneçam iguais.

dxvargas
fonte
Talvez esteja faltando alguma coisa, mas hook_node_presave () não implica que node_save () tenha sido chamado? Estamos tentando evitar chamar node_save () se nenhum campo foi alterado.
mórbida
É verdade que esse gancho é chamado dentro de node_save (). Mas você ainda pode cancelar o salvamento, chamando drupal_goto () dentro de mymodule_node_presave ().
Dxvargas
2
@hiphip Isso não é realmente uma boa idéia, você vai deixar o nó salvar em um estado inconsistente se você redirecionar no meio dele
Clive
0

Este é apenas um código que juntei. Todo o crédito deve ir para @eclecto por fazer todo o trabalho das pernas. Essa é apenas uma variação (igualmente não testada) que leva os objetos do nó diretamente, reduz um pouco as ocorrências do banco de dados e cuida da negociação da linguagem.

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;
}
Clive
fonte
1
Você me fez pensar na mesma linha da minha nova versão. Inclusive incluí a verificação de integridade do tipo de nó.
Eric N
0

A resposta fornecida é ótima e me ajudou, mas há algo que precisei corrigir.

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

No foreach()loop, eu tive que mudar de $new_fieldpara $old_field. Não sei se esta é uma nova versão do Drupal ou apenas meu código (pode ser devido a outro código em outro lugar), mas não tenho acesso $new_field['entity'].

Doud
fonte
Acabei de testar a função _fields_changed () em uma nova instalação do Drupal 7.41 e salvar um nó com uma field_collection me dá esse $ old_field e $ new_field . Parece-me que você pode estar chamando _fields_changed () com os parâmetros $ old_entity e $ new_entity da maneira errada (ou você acidentalmente trocou os nomes das variáveis ​​em seu código em algum lugar).
mórbida
0

Obrigado pelo post, realmente me salvou muito tempo. Corrigi vários avisos e avisos de que a função estava sendo exibida:

/*
 * 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;
}
pwaterz
fonte
Por favor, explique como esse código responde à pergunta original (apenas postar algum código não é compatível com as regras por aqui).
precisa saber é o seguinte