Я добавляю определенные поля из типа контента в пользовательскую форму, используя field_attach_form (). Когда форма отправлена, я обрабатываю эти поля, вызывая field_attach_form_validate () и field_attach_submit () из обратных вызовов #validate и #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',
);
Вы можете подумать о том, чтобы просто сравнить ключ «значение», но затем вы столкнетесь с полями, составленными из других элементов, которые не имеют ключей «значение». Например, давайте посмотрим на поле адреса, в котором нет ключа 'value', а в старых и подготовленных узлах есть ключи, которые не имеют аналогов.
Старый узел
$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. Просто идея.Ответы:
Это, наконец, должно работать как общее решение. Спасибо Клайву и morbiD за весь вклад.
Передайте обе версии узла следующей функции. Это будет:
Извлеките все редактируемые поля обнаруженного типа контента и их редактируемые столбцы (т. Е. Элементы, которые могут появиться в пользовательской форме) из базы данных в одном запросе.
Игнорировать поля и столбцы, которые полностью пусты в обеих версиях.
Обрабатывайте поле с разным количеством значений в двух версиях как изменение.
Переберите все поля, значения и столбцы и сравните две версии.
Сравнивайте элементы не тождественно (! =), Если они числовые, и тождественно (! ==), если они являются чем-то другим.
Немедленно верните TRUE при первом обнаруженном изменении (так как одного изменения достаточно, чтобы узнать, что нам нужно повторно сохранить узел).
Возвратите FALSE, если никаких изменений не обнаружено после сравнения всех значений.
Рекурсивно сравнивайте коллекции полей, загружая их и их схему и передавая результаты себе. Это ДОЛЖНО даже позволить ему сравнивать вложенные коллекции полей. Код НЕ должен иметь никакой зависимости от модуля Field Collection.
Дайте мне знать, если в этом коде есть еще ошибки или опечатки.
Иногда вам интересно узнать, какие поля изменились. Чтобы узнать это, вы можете использовать эту версию функции:
Иногда вы можете захотеть сделать так, чтобы изменение определенных полей узла не приводило к обновлению «измененной» временной метки этого узла. Это может быть реализовано следующим образом:
РЕДАКТИРОВАТЬ (30.07.2013) Укреплена поддержка сбора на местах. Добавлена поддержка полей с несколькими значениями.
РЕДАКТИРОВАТЬ (31.07.2015) Добавлена версия функции, которая возвращает, какие поля были изменены, и пример использования.
источник
Вот еще один, более простой подход, позволяющий избежать сложных сравнений значений на стороне сервера и работающий с любой формой:
Вы можете использовать плагин грязной формы jQuery, такой как https://github.com/codedance/jquery.AreYouSure
Хотя другие, которые позволяют слушать измененную форму / грязный статус, также будут работать.
Добавьте слушателя, чтобы установить значение скрытого элемента формы:
Установите для скрытого элемента формы значение по умолчанию «изменено», чтобы сохранить по умолчанию для пользователей с отключенным JavaScript (~ 2%).
например:
Затем вы можете проверить значение скрытого элемента
if ($form_state['values']['hidden_indicator'] == 'changed') { /* node_save($node) */ }
в вашей форме подтвердить / отправить обработчики.
источник
Drupal.behaviors.formUpdated
возможно,val()
может быть связано с тем, что, хотя, похоже, оно сработает без фактического изменения значения (например, включает в себя событие щелчка), тогда как выделенные плагины лучше обнаруживают измененные значения формы.Я не уверен, что это идеально, но почему бы не взять его наоборот, сравнивая формы вместо узловых объектов ?
Я не уверен, что вы строго находитесь в форме узла, но в любом случае вы можете визуализировать форму с помощью старого узла и нового узла:
Сравните ваши формы ...
Я надеюсь, что это хороший трек ... дайте мне знать.
источник
Вот метод, использующий hook_node_presave ($ node). Это всего лишь макет, если вы думаете, что он помогает, протестируйте его и улучшите в соответствии с вашими потребностями!
Я предполагаю, что для каждого значения поля экземпляры, которые определены в $ node, должны быть определены и равны в $ node_before. Меня не волнуют поля значений полей, которые находятся в $ node_before и не находятся в $ node, я полагаю, что они остаются прежними.
источник
Это всего лишь некоторый код, который я собрал вместе. Все заслуги должны идти на @eclecto для выполнения всей работы по ногам. Это всего лишь (аналогично непроверенный) вариант, который напрямую принимает объекты узла, немного уменьшает попадания в БД и обеспечивает согласование языка.
источник
Приведенный ответ отличный, и он мне помог, но есть кое-что, что я должен был исправить.
В
foreach()
цикле мне пришлось сменить с$new_field
на$old_field
. Я не знаю, является ли это новой версией Drupal или только моим кодом (возможно, из-за другого кода где-то еще), но у меня нет доступа к нему$new_field['entity']
.источник
Спасибо за пост, действительно сэкономил мне много времени. Я исправил кучу предупреждений и уведомлений, которые выводила функция:
источник