노드를 저장하기 전에 사용자 정의 양식에서 변경된 필드를 일반적으로 감지


12

field_attach_form ()을 사용하여 콘텐츠 유형의 특정 필드를 사용자 정의 양식에 추가하고 있습니다. 양식이 제출되면 #validate 및 #submit 콜백에서 field_attach_form_validate () 및 field_attach_submit ()을 호출하여 해당 필드를 처리합니다.

이 시점에서 제출 후 준비된 노드 객체를 원래 노드와 비교하고 필드가 변경된 경우 node_save () 만 신경 쓰려고합니다. 따라서을 사용하여 원래 노드를로드하는 것으로 시작합니다 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

@kalabro 그래, 그것은 확실히 갈 길이야, 나는 그것이 성능에 상당히 나쁘다는 느낌을 도울 수 없다.-그것을 일반화하기 위해서는 양식 제출을 사용하여 모든 필드 정보를 개별적으로로드해야합니다. 또는 데이터를 얻기 위해 집계 된 쿼리를 작성할 수 있지만 중요한 후크가 발생하지 않을 수 있습니다. 개념적으로는 가능해 보이지만 구현이 상당히 복잡 할 것이라고 생각합니다.
Clive

@ kalabro 나는이 아이디어를 잘 이해하지 못한다. 필드 구조를 준비하고 설명 된대로 렌더링하는 방법을 보여주기 위해 의사 코드를 게시 할 수 있습니까?
morbiD

답변:


9

이것은 결국 일반적인 솔루션으로 작동해야합니다. 모든 입력에 대한 Clive 및 morbiD 덕분입니다.

두 버전의 노드를 다음 기능으로 전달하십시오. 그것은 :

  1. 감지 된 모든 컨텐츠 유형의 편집 가능 필드 및 편집 가능한 열 (즉, 사용자 정의 양식에 나타날 수있는 항목)을 단일 쿼리로 데이터베이스에서 가져옵니다.

  2. 두 버전에서 완전히 비어있는 필드와 열은 무시하십시오.

  3. 두 버전간에 값이 다른 필드를 변경 사항으로 취급하십시오.

  4. 모든 필드, 값 및 열을 반복하고 두 버전을 비교하십시오.

  5. 항목이 숫자 인 경우 비 식별 적으로 (! ​​=) 비교하고 다른 항목 인 경우 동일하게 (! ==) 비교하십시오.

  6. 첫 번째 변경이 감지되면 즉시 TRUE를 반환합니다 (한 번의 변경으로 노드를 다시 저장해야한다는 것을 알 수 있기 때문에).

  7. 모든 값을 비교 한 후 변경이 감지되지 않으면 FALSE를 리턴하십시오.

  8. 필드 콜렉션과 해당 스키마를로드하고 결과를 자신에게 전달하여 필드 콜렉션을 재귀 적으로 비교합니다. 이 방법을 사용하면 중첩 된 필드 컬렉션을 비교할 수도 있습니다. 코드는 Field Collection 모듈에 의존해서는 안됩니다.

이 코드에 버그 나 오타가 더 있으면 알려주세요.

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

편집 (2013 년 7 월 30 일) 현장 수집 지원 강화. 여러 값을 가진 필드에 대한 지원이 추가되었습니다.

편집 (2015 년 7 월 31 일) 변경된 필드 를 반환 하는 함수 버전 과 사용 사례를 추가했습니다.


이것은 훌륭합니다. 개발자가 사용할 수있는 일종의 API 모듈에 있어야한다고 생각합니다.
Jelle

3

복잡한 서버 측 값 비교를 피하고 모든 형식으로 작동하는 또 다른 더 간단한 접근 방법이 있습니다.

  1. jQuery를 사용하여 양식 값이 변경되었는지 감지
  2. 숨겨진 요소 값을 설정하여 양식이 변경되었음을 나타냅니다.
  3. 숨겨진 요소 값 서버 측을 확인하고 필요에 따라 처리하십시오.

https://github.com/codedance/jquery.AreYouSure 와 같은 jQuery 더티 폼 플러그인을 사용할 수 있습니다.

양식 변경 / 더티 상태를들을 수있는 다른 사용자도 작동합니다.

숨겨진 양식 요소의 값을 설정하기 위해 리스너를 추가하십시오.

자바 스크립트가 비활성화 된 (~ 2 %) 사용자의 경우 기본적으로 저장하려면 숨겨진 양식 요소를 기본값 'changed'로 설정하십시오.

예 :

// 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 core의 misc / form.js 파일에서 Drupal.behaviors.formUpdated를 확인하십시오. 주목해야 할 또 다른 사항은 일부 wysiwyg 편집기 및 해당 drupal 모듈이 작동하는 방식으로 변경된 값을 감지하는 것이 항상 그렇게 간단하지는 않다는 것입니다.
루비

예, 숨겨진 요소에 기본값 'changed'를 설정하면 js를 사용하지 않는 소수의 사용자에게는 기본적으로 작은 비율이 저장됩니다. Drupal.behaviors.formUpdated어쩌면에 관한 흥미로운 메모는 val()실제로 값을 변경하지 않고 트리거하는 것처럼 보이지만 (예 : 클릭 이벤트 포함) 전용 플러그인은 실제로 변경된 양식 값을 감지하는 데 더 좋습니다.
David Thomas

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 ()을 살펴 보았지만 $ node를 두 번째 매개 변수로 전달할 수 있다는 것을 알지 못했습니다. 그러나 위의 예제 코드를 테스트했지만 불행히도 반환 된 배열 구조는 동일하지만 값은 다릅니다. 테스트하고있는 주소 필드에 대한이 재귀 array_diff_assoc ()를 살펴보십시오. i.imgur.com/LUDPu1R.jpg
morbiD

그 array_diff_assoc을 보았지만 drupal_get_form의 dpm을 줄 시간이 있습니까? 이 문제를 해결할 방법이있을 수 있습니다.
Gregory Kapustin

0

다음은 hook_node_presave ($ node)를 사용하는 방법입니다. 도움이된다고 생각하면 테스트하고 필요에 맞게 개선하는 것은 단지 모형 일뿐입니다!

  /**
   * 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에 정의 된 인스턴스가 $ node_before에서 정의되고 동일해야한다고 가정합니다. $ node_before에 있고 $ node에 있지 않은 필드 값의 필드는 신경 쓰지 않습니다.


어쩌면 나는 뭔가를 놓치고 있지만 hook_node_presave ()가 node_save ()가 호출되었음을 암시하지 않습니까? 필드가 변경되지 않은 경우 node_save () 호출을 피하려고합니다.
morbiD

사실이 후크는 node_save () 안에서 호출됩니다. 그러나 mymodule_node_presave () 내에서 drupal_goto ()를 호출하여 저장을 취소 할 수 있습니다.
dxvargas

2
@hiphip 정말 좋은 생각은 아닙니다. 중간에 리디렉션하면 노드 저장이 일관성이없는 상태로 유지됩니다
Clive

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
내 새 버전과 같은 줄을 따라 생각하게 했어. 노드 유형 상태 점검도 포함했습니다.
Eric N

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. 이 버전이 Drupal의 새 버전인지 아니면 내 코드 만인지는 모르지만 (어딘가에 다른 코드가있을 수 있음)에 액세스 할 수 없습니다 $new_field['entity'].


방금 Drupal 7.41을 새로 설치하여 _fields_changed () 함수를 테스트했으며 field_collection으로 노드를 저장하면 $ old_field 및 $ new_field가 표시 됩니다. $ old_entity 및 $ new_entity 매개 변수를 사용하여 _fields_changed ()를 잘못된 방법으로 호출하는 것처럼 보입니다 (또는 실수로 코드의 변수 이름을 어딘가에서 바꿨습니다).
morbiD

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

이 코드가 원래 질문에 어떻게 대답하는지 설명하십시오 (일부 코드 만 게시하는 것이 여기의 규칙을 준수하지 않음).
Pierre.Vriens
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.