Datums-Felder und Entity Query [Update]

Geschrieben von patrick am Mo., 05.02.2018 - 08:37 Uhr

Du wolltest immer schon mal eine condition für ein Datums-Feld zu einer Drupal 8 entity query hinzufügen? So funktioniert es zuverlässig:

In Drupal 8.5.x oder höher:

use Drupal\Core\Datetime\DrupalDateTime;
use Drupal\datetime\Plugin\Field\FieldType\DateTimeItemInterface;
 
// Get a date string suitable for use with entity query.
$date = new DrupalDateTime();
$date->setTimezone(new \DateTimeZone(DateTimeItemInterface::STORAGE_TIMEZONE));
$date = $date->format(DateTimeItemInterface::DATETIME_STORAGE_FORMAT);
 
// Set the condition.
$query->condition('field_date.value', $date, '>');

In Drupal 8.4.x oder niedriger:

use Drupal\Core\Datetime\DrupalDateTime;
 
// Get a date string suitable for use with entity query.
$date = new DrupalDateTime();
$date->setTimezone(new \DateTimeZone(DATETIME_STORAGE_TIMEZONE));
$date = $date->format(DATETIME_DATETIME_STORAGE_FORMAT);
 
// Set the condition.
$query->condition('field_date.value', $date, '>');

Der Trick ist, dass wir ein DrupalDateTime-Objekt verwenden, für das wir die korrekte Zeitzone des Datums-Speichers setzen (zur Verfügung gestellt durch die Konstante  DATETIME_STORAGE_TIMEZONE) und dann einen String im korrekten Datums-Format, das vom Datums-Speicher verwendet wird, abrufen (zur Verfügung gestellt durch die Konstante DATETIME_DATETIME_STORAGE_FORMAT). Dadurch erhalten wir verlässliche Ergebnisse. Im obigen Beispiel wollte ich nur nach der aktuellen Zeit filtern, aber du kannst auch einen Datums-String an den Konstruktor von DrupalDateTime übergeben, wenn du ein anderes Datum verwenden möchtest.

Bitte beachte: In Drupal 8.5.x wurden die oben genannten Konstanten als überholt gekennzeichnet und durch entsprechende Konstanten eines neuen DateTimeItemInterface ersetzt. Sie werden in Drupal 9.x entfernt.

Diese Objekte kann man mit der Methode getDateTime() auch direkt aus Datums-Feldern von Entitäten abrufen:

foreach ($node->field_date_range as $item) {
  foreach ($item as $index => $value) {
    $date = $value->getDateTime();
  }
}

Falls du die experimentellen date range Felder (mit Start- und Enddatum) verwendet, musst du außerdem noch wissen, dass das Enddatum in einer Spalte namens end_value gespeichert wird.

Ein etwas vollständigeres Beispiel, das Veranstaltungs-Inhalte in der Zukunft abruft, sieht so aus:

use Drupal\Core\Datetime\DrupalDateTime;
use Drupal\Core\Language\LanguageInterface;
 
// @note: In Drupal 8.5.x and later also include the following line: 
use Drupal\datetime\Plugin\Field\FieldType\DateTimeItemInterface;
 
$storage = \Drupal::service('entity_type.manager')->getStorage('node');
$query = $storage->getQuery()
  ->condition('type', 'event')
  ->condition('status', 1)
  ->sort('field_date_range.value', 'ASC')
  ->sort('field_date_range.end_value', 'ASC')
  ->sort('created', 'ASC');
 
$query->condition('langcode', [
  \Drupal::service('language_manager')->getCurrentLanguage()->getId(),
  LanguageInterface::LANGCODE_NOT_APPLICABLE,
  LanguageInterface::LANGCODE_NOT_SPECIFIED,
], 'IN');
 
// @note BEGIN: Code for Drupal 8.5.x and later: 
$date = new DrupalDateTime(); 
$date->setTimezone(new \DateTimeZone(DateTimeItemInterface::STORAGE_TIMEZONE)); 
$date = $date->format(DateTimeItemInterface::DATETIME_STORAGE_FORMAT); 
// @node END: Code for Drupal 8.5.x and later. 
 
// @note BEGIN: Code for Drupal 8.4.x and earlier:
$date = new DrupalDateTime();
$date->setTimezone(new \DateTimeZone(DATETIME_STORAGE_TIMEZONE));
$date = $date->format(DATETIME_DATETIME_STORAGE_FORMAT);
// @note END: Code for Drupal 8.4.x and earlier.
 
$and = $query->andConditionGroup()
  ->condition('field_date_range.value', $date, '>')
  ->notExists('field_date_range.end_value');
 
$or = $query->orConditionGroup()
  ->condition($and)
  ->condition('field_date_range.end_value', $date, '>');
 
$query->condition($or);
 
$ids = $query->execute();
$nodes = $storage->loadMultiple($ids);

Beachte, dass es zur Zeit ein Problem in Drupal Core mit verschachtelten Bedingungsgruppen für Entity Query gibt, die in diesem Beispiel verwendet werden.

Update: Dieser Beitrag wurde aktualisiert in Bezug auf Änderungen in Drupal 8.5.x (siehe Global constants in datetime.module are deprecated and DateTimeItemInterface has been introduced).

 

Systeme
Drupal 8/9