Programowo usuń jeden wpis z jednego pola na jednym obiekcie

13

Jaki jest właściwy sposób programowo usunąć jeden konkretny wpis pola dla pola wielokrotnego wpisu z jednego konkretnego obiektu? (to są określone pola i określone encje, a nie typy lub instancje pól i typy encji)

Oto kilka możliwości, które sprawdziłem i które nie działają:

  • Ładowanie encji za pomocą entity_load(), ustawienie wpisu pola na = null lub = array (), a następnie zapisywanie za pomocą field_attach_update(). Jest to najbliższe, jakie znalazłem, ale pozostawia wpis zerowego pola zombie w bazie danych, który pojawia się jako pusty wiersz w formularzach, dopóki formularz nie zostanie zapisany i hook_field_is_empty()może się uruchomić ( hook_field_is_empty()jest skonfigurowany tak, że = null lub = array () będzie oznaczać jak pusty).
  • Ładowanie encji za pomocą entity_load(), odznaczanie pola wpisu kluczem, a następnie zapisywanie za pomocą field_attach_update(). To wydaje się nic nie robić - wydaje się, że Drupal interpretuje nieistnienie wpisu jako znak, aby go nie modyfikować. (co dziwne, czasami próbuję tego podejścia uzyskać maksymalny limit czasu ważności zapytania)
  • field_attach_delete() - to jest zbyt tępe: zabija wszystkie pola dla bytu
  • field_purge_data() - lepiej, ale wciąż zbyt tępo: zabija wszystkie wpisy w polu, a nie konkretne wpisy

Aby to wyjaśnić, mam kod, który znajduje (i ładuje) byt, który ma pole zawierające wiele wpisów i znajduje określony wpis w tym polu, który należy usunąć. Chcę całkowicie usunąć ten wpis, nie dotykając żadnych innych wpisów ani żadnych pól w encji.

user56reinstatemonica8
źródło

Odpowiedzi:

24

Jeśli możesz polegać na module API encji , powinieneś być w stanie użyć kodu podobnego do następującego:

// 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);
Clive
źródło
2
To zadziałało! Dzięki, mój problem z zombie został rozwiązany. Kilka uwag, które mogą zaoszczędzić czas innym: Potrzebowałem zaktualizować interfejs API encji do RC2; ponieważ używałem dynamicznej nazwy pola, nieuzbrojona linia potrzebowała nawiasów klamrowych, takich jak unset ($ entity -> {$ field_name} [LANGUAGE_NONE] [$ index]); i aby uniknąć ostrzeżenia, musiałem zawinąć wartość array_values ​​() w if (! empty (...)) {}
user56reinstatemonica8
Działa to również, jeśli chcesz po prostu wyczyścić całe pole i uniknąć przerażającego „Naruszenia zasad integralności: kolumna 1048„ field_duty_user_target_id ”nie może mieć wartości zerowej”
Darrell Duane
Wielkie dzięki! próbował zmienić wartość pola za pomocą node_load, ale to nie działało. Tak więc zmiana wartości pola encji na pewno działa!
Артем Ильин
1

Musiałem to zrobić w ramach czyszczenia migracji Drupal8.

Po kilku eksperymentach odkryłem, że iteracja, a następnie użycie metody unset () w delcie może ją zabić. Moim przykładem było usunięcie tagu (stąd szukam „target_id”, a nie „wartość”, jak to często bywało w przypadku innych pól.

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

A potem, jeśli sukces, to $object->save();

dman
źródło
0

W przypadku Drupal 8, aby usunąć pole z encji:

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

Spowoduje to wywołanie magicznej metody __unset () z 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]);
    }
}

Nie zapominaj, że aby zachować zmiany, musisz zadzwonić

$entity->save();

Po wprowadzeniu wszystkich zmian.

Miguel Guerreiro
źródło
-1

To lepszy sposób:

> $user = user_load($user->uid); 
> $user_wrp = entity_metadata_wrapper('user', $user);
> $user_wrp->{'field_data_multiple'} = array();
Mike Nguyen
źródło
-2

obecna preferowana metoda wykorzystywałaby element_wadania_metadanych

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

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

to najlepszy poradnik na temat EMW, jaki widziałem http://deeson-online.co.uk/labs/programatically-access-field-data-using-entitymetadatawrapper-drupal

dotist
źródło
to nie zadziałało. Próbowałem nawet tak bez powodzenia; $ wrapper = entity_metadata_wrapper ('node', $ duty); unset ($ wrapper-> field_duty_user); $ wrapper-> save (); node_save ($ duty);
Darrell Duane
1
Prawidłowy sposób to $ node_wrapped-> field_name-> set (""); następnie $ wrapper-> save ()
chadpeppers