Програмно видалити один запис із одного поля на одній сутності


13

Який правильний спосіб програмного видалення одного конкретного запису поля для полів з декількома записами від однієї конкретної сутності? (це конкретні поля та конкретні сутності, а не типи полів чи екземпляри та типи сутностей)

Ось кілька можливостей, які я розглянув, які не працюють:

  • Завантажуючи сутність за допомогою entity_load(), встановлюючи запис для поля на = null або = array (), а потім зберігайте за допомогою field_attach_update(). Це найближче, що я знайшов, але він залишає запис нульового поля зомбі в базі даних, який відображається як порожній рядок у формах, поки форма не буде збережена і не hook_field_is_empty()може натиснути ( hook_field_is_empty()налаштована так, що = null або = array () буде позначено прапором як порожній).
  • Завантаження об'єкта за допомогою entity_load(), скидання поля поля за допомогою ключа, а потім збереження за допомогою field_attach_update(). Це, здається, нічого не робить - схоже, що Drupal трактує запис, що його немає, як знак, щоб не змінювати його. (як не дивно, я також інколи отримую максимальні терміни закінчення строку запиту при спробі такого підходу)
  • field_attach_delete() - це занадто тупо: це вбиває всі поля для сутності
  • field_purge_data() - краще, але все ще занадто тупо: це вбиває всі записи поля, а не конкретні записи

Щоб уточнити, у мене є код, який знаходить (і завантажує) сутність, у якої є поле, яке містить декілька записів, і знаходить конкретну запис у тому полі, яке потрібно видалити. Я хочу видалити цей запис повністю, не торкаючись будь-яких інших записів чи будь-яких інших полів об'єкта.

Відповіді:


24

Якщо ви можете покластися на модуль API сутності, ви повинні мати можливість використовувати код, подібний до наступного:

// Load some entity.
$entity = entity_load_single($entity_type, $id);

// Remove the field value.
unset($entity->field_FIELD_NAME[LANGUAGE_NONE][$index]);

// Reset the array to zero-based sequential keys.
$entity->field_FIELD_NAME[LANGUAGE_NONE] = array_values($entity->field_FIELD_NAME[LANGUAGE_NONE]);

// Save the entity.
entity_save($entity_type, $entity);

2
Це спрацювало! Дякую, мою проблему зомбі зараз усунули. Кілька зауважень, які можуть заощадити інший час: мені потрібно було оновити api сутності до RC2; оскільки я використовував ім'я динамічного поля, для невідомій лінії потрібні фігурні дужки, такі як unset ($ object -> {$ field_name} [LANGUAGE_NONE] [$ index]); і щоб уникнути попередження, мені потрібно було загорнути array_values ​​() у if (! empty (...)) {}
user56reinstatemonica8

Це також працює, якщо ви просто хочете очистити все поле, і уникнете жахливого "Порушення обмеження цілісності: стовпець 1048" field_duty_user_target_id 'не може бути нульовим "
Даррелл Дуейн,

Дуже дякую! намагався змінити значення поля через node_load, але це не спрацювало. Тож зміна значення поля сутності, як це, безумовно працює!
Артем Ільін

1

Мені потрібно було це зробити в рамках очищення міграції Drupal8.

Після деяких експериментів я виявив, що ітерація, а потім використання unset () на дельті може вбити її. У моєму прикладі було видалення тегу (отже, я шукаю "target_id", а не "value", як це часто робиться для інших полів.

/**
 * Removes a term from a field.
 *
 * @return bool
 *   success
 */
private function removeTerm(\Drupal\node\NodeInterface $object, \Drupal\taxonomy\TermInterface $term, $field_name) {
  // Check if tag value exists already.
  // Remember they may be multiples.
  /** @var @var \Drupal\Core\Field\FieldItemList $field_values */
  $field_values = $object->get($field_name);
  foreach ($field_values as $delta => $field_value) {
    if ($field_value->getValue()['target_id'] == $term->id()) {
      unset($field_values[$delta]);
      return TRUE;
    }
  }
  return FALSE;
}

А згодом, якщо успіх, то $object->save();


0

Для Drupal 8, щоб видалити поле з об'єкта:

$entity = Node::load($nid);
unset($entity->field_name);

Це викличе магічний метод __unset () від ContentEntityBase:

public function __unset($name) {
    // Unsetting a field means emptying it.
    if ($this->hasField($name)) {
        $this->get($name)->setValue([]);
    }
    // For non-field properties, unset the internal value.
    else {
        unset($this->values[$name]);
    }
}

Не забувайте, що для збереження змін вам потрібно зателефонувати

$entity->save();

Після того, як ви внесли всі свої зміни.


-1

Це кращий спосіб:

> $user = user_load($user->uid); 
> $user_wrp = entity_metadata_wrapper('user', $user);
> $user_wrp->{'field_data_multiple'} = array();

-2

поточний кращий метод буде використовувати сутність_metadata_wrapper

$node_wrapped = entity_metadata_wrapper('node', node_load($nid));

unset($node_wrapped->$field_name[$index];

це найкращий підручник із EMW, який я бачив http://deeson-online.co.uk/labs/programatic-access-field-data-using-entitymetadatawrapper-drupal


це не спрацювало. Я навіть спробував це так, не пощастивши; $ wrapper = entit_metadata_wrapper ('вузол', $ мито); unset ($ wrapper-> field_duty_user); $ wrapper-> save (); node_save ($ мито);
Даррелл Дуейн

1
Правильним способом було б $ node_wrapped-> field_name-> set (""); тоді $ wrapper-> save ()
chadpeppers
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.