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

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() - лучше, но все еще слишком тупо: убивает все записи поля, а не конкретные записи

Итак, чтобы уточнить, у меня есть код, который находит (и загружает) объект, который имеет поле с несколькими записями, и находит конкретную запись в этом поле, которую необходимо удалить. Я хочу полностью удалить эту запись, не касаясь каких-либо других записей или каких-либо других полей объекта.

user56reinstatemonica8
источник

Ответы:

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 ($ entity -> {$ 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

текущий предпочтительный метод будет использовать entity_metadata_wrapper

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

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

это лучший учебник по EMW, который я видел http://deeson-online.co.uk/labs/programatics-access-field-data-using-entitymetadatawrapper-drupal

dotist
источник
это не сработало. Я даже попробовал это без удачи; $ wrapper = entity_metadata_wrapper ('node', $ duty); unset ($ wrapper-> field_duty_user); $ wrapper-> Save (); node_save ($ долг);
Даррелл Дуэйн
1
Правильный путь был бы $ node_wrapped-> field_name-> set (""); затем $ wrapper-> save ()
chadpeppers