class DateRecurViewsHooks in Recurring Dates Field 3.0.x
Same name and namespace in other branches
- 8.2 src/DateRecurViewsHooks.php \Drupal\date_recur\DateRecurViewsHooks
- 3.x src/DateRecurViewsHooks.php \Drupal\date_recur\DateRecurViewsHooks
- 3.1.x src/DateRecurViewsHooks.php \Drupal\date_recur\DateRecurViewsHooks
Defines Views hooks.
Hierarchy
- class \Drupal\date_recur\DateRecurViewsHooks implements ContainerInjectionInterface uses StringTranslationTrait
Expanded class hierarchy of DateRecurViewsHooks
1 file declares its use of DateRecurViewsHooks
File
- src/
DateRecurViewsHooks.php, line 28
Namespace
Drupal\date_recurView source
class DateRecurViewsHooks implements ContainerInjectionInterface {
use StringTranslationTrait;
/**
* The active database connection.
*
* @var \Drupal\Core\Database\Connection
*/
protected $database;
/**
* Module handler.
*
* @var \Drupal\Core\Extension\ModuleHandlerInterface
*/
protected $moduleHandler;
/**
* Entity type manager.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected $entityTypeManager;
/**
* The entity field manager.
*
* @var \Drupal\Core\Entity\EntityFieldManagerInterface
*/
protected $entityFieldManager;
/**
* The typed data manager.
*
* @var \Drupal\Core\TypedData\TypedDataManagerInterface
*/
protected $typedDataManager;
/**
* DateRecurViewsHooks constructor.
*
* @param \Drupal\Core\Database\Connection $connection
* The active database connection.
* @param \Drupal\Core\Extension\ModuleHandlerInterface $moduleHandler
* Module handler.
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager
* Entity type manager.
* @param \Drupal\Core\Entity\EntityFieldManagerInterface $entityFieldManager
* The entity field manager.
* @param \Drupal\Core\TypedData\TypedDataManagerInterface $typedDataManager
* The typed data manager.
*/
public function __construct(Connection $connection, ModuleHandlerInterface $moduleHandler, EntityTypeManagerInterface $entityTypeManager, EntityFieldManagerInterface $entityFieldManager, TypedDataManagerInterface $typedDataManager) {
$this->database = $connection;
$this->moduleHandler = $moduleHandler;
$this->entityTypeManager = $entityTypeManager;
$this->entityFieldManager = $entityFieldManager;
$this->typedDataManager = $typedDataManager;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static($container
->get('database'), $container
->get('module_handler'), $container
->get('entity_type.manager'), $container
->get('entity_field.manager'), $container
->get('typed_data_manager'));
}
/**
* Implements hook_views_data().
*
* @see \hook_views_data()
* @see \date_recur_views_data()
*/
public function viewsData() : array {
$allFields = $this
->getDateRecurFields();
$data = [];
foreach ($allFields as $entityTypeId => $fields) {
$entityType = $this->entityTypeManager
->getDefinition($entityTypeId);
/** @var \Drupal\views\EntityViewsDataInterface $viewsData */
$viewsData = $this->entityTypeManager
->getHandler($entityType
->id(), 'views_data');
$entityViewsTable = $viewsData
->getViewsTableForEntityType($entityType);
/** @var \Drupal\Core\Field\FieldStorageDefinitionInterface[] $fields */
foreach ($fields as $fieldId => $field) {
$fieldLabel = $this
->getFieldLabel($field
->getTargetEntityTypeId(), $fieldId);
$fieldName = $field
->getName();
$entityIdField = $entityType
->getKey('id');
$entityRevisionField = $entityType
->isRevisionable() ? $entityType
->getKey('revision') : NULL;
$tArgs = [
'@field_name' => $fieldLabel,
'@entity_type' => $entityType
->getLabel(),
];
// Occurrence filter.
$data[$entityViewsTable][$fieldName . '_occurrences']['filter'] = [
'id' => 'date_recur_occurrences_filter',
'title' => $this
->t('Occurrences filter for @field_name', $tArgs),
// Instruct the filter to join the occurrence.entity_id field on
// base.entityId:
'field base entity_id' => $entityIdField,
'date recur field name' => $fieldName,
'entity_type' => $entityType
->id(),
];
// Relationship from entity table to occurrence table.
$occurrenceTableName = DateRecurOccurrences::getOccurrenceCacheStorageTableName($field);
$data[$entityViewsTable][$fieldName . '_occurrences']['relationship'] = [
'id' => 'standard',
'base' => $occurrenceTableName,
'base field' => isset($entityRevisionField) ? 'revision_id' : 'entity_id',
'help' => $this
->t('Get all occurrences for recurring date field @field_name', $tArgs),
'field' => $entityRevisionField ?? $entityIdField,
// Add new 'title'.
'title' => $this
->t('Occurrences of @field_name', $tArgs),
// Default label for relationship in the UI.
'label' => $this
->t('Occurrences of @field_name', $tArgs),
];
$dateField = [
'id' => 'date_recur_date',
'source date format' => $this
->getFieldDateFormat($field),
'source time zone' => DateTimeItemInterface::STORAGE_TIMEZONE,
];
$data[$occurrenceTableName][$fieldName . '_value']['field'] = $dateField;
$data[$occurrenceTableName][$fieldName . '_end_value']['field'] = $dateField;
// Attached fields get automatic functionality provided by
// hook_field_views_data(). Add features here for base fields.
if ($field instanceof BaseFieldDefinition) {
$data[$occurrenceTableName]['table']['group'] = $this
->t('Occurrences for @entity_type @field_name', [
'@entity_type' => $entityType
->getLabel(),
'@field_name' => $fieldLabel,
]);
$startField = $fieldName . '_value';
$endField = $fieldName . '_end_value';
$data[$occurrenceTableName][$startField]['title'] = $this
->t('Occurrence start date');
$data[$occurrenceTableName][$endField]['title'] = $this
->t('Occurrence end date');
// Sort.
// datetime_range_field_views_data() uses 'datetime', which relies
// on entity things.
$data[$occurrenceTableName][$startField]['sort']['id'] = 'date';
$data[$occurrenceTableName][$endField]['sort']['id'] = 'date';
}
}
}
return $data;
}
/**
* Implements hook_views_data_alter().
*
* @see \hook_views_data_alter()
* @see \date_recur_views_data_alter()
*/
public function viewsDataAlter(array &$data) : void {
$removeFieldKeys = $this
->getViewsPluginTypes();
$removeFieldKeys = array_flip($removeFieldKeys);
// Base fields don't yet have an option to provide defaults for their type,
// but entity views data still tries to add default views integration for
// the field primitives in
// \Drupal\views\EntityViewsData::mapSingleFieldViewsData
// Feature to add in: https://www.drupal.org/node/2489476.
// Remove the default plugins from entity views data since they are not
// something that should be supported. This also means adding plugins for
// date recur base fields cannot be added in hook_views_data or
// entity 'views_data' handlers..
// @todo bring in all plugins from \datetime_range_field_views_data() if/when
// it supports base fields.
$allFields = $this
->getDateRecurFields();
foreach ($allFields as $entityTypeId => $fields) {
/** @var \Drupal\Core\Entity\Sql\SqlEntityStorageInterface $entityStorage */
$entityStorage = $this->entityTypeManager
->getStorage($entityTypeId);
/** @var \Drupal\Core\Entity\Sql\DefaultTableMapping $tableMapping */
$tableMapping = $entityStorage
->getTableMapping($fields);
/** @var \Drupal\Core\Field\FieldStorageDefinitionInterface[] $fields */
foreach ($fields as $fieldId => $fieldStorage) {
if (!$fieldStorage instanceof BaseFieldDefinition) {
continue;
}
if ($tableMapping
->requiresDedicatedTableStorage($fieldStorage)) {
$fieldTable = $tableMapping
->getDedicatedDataTableName($fieldStorage);
$fieldData =& $data[$fieldTable];
// Remove handler keys within each field. Keys like 'title', 'help'
// etc are ignored. Whereas 'argument', 'field', etc are removed.
foreach ($fieldData as &$field) {
$field = array_diff_key($field, $removeFieldKeys);
}
}
}
}
}
/**
* Implements hook_field_views_data().
*
* @see \hook_field_views_data()
* @see \date_recur_field_views_data()
*/
public function fieldViewsData(FieldStorageConfigInterface $fieldDefinition) : array {
$data = [];
$entityTypeId = $fieldDefinition
->getTargetEntityTypeId();
$entityType = $this->entityTypeManager
->getDefinition($entityTypeId);
/** @var \Drupal\Core\Entity\Sql\SqlEntityStorageInterface $entityStorage */
$entityStorage = $this->entityTypeManager
->getStorage($entityTypeId);
/** @var \Drupal\Core\Entity\Sql\DefaultTableMapping $tableMapping */
$tableMapping = $entityStorage
->getTableMapping();
$fieldName = $fieldDefinition
->getName();
// The field label, see also usage in views.views.inc.
$fieldLabel = $this
->getFieldLabel($fieldDefinition
->getTargetEntityTypeId(), $fieldDefinition
->getName());
$fieldTableName = $tableMapping
->getDedicatedDataTableName($fieldDefinition);
$parentData = $this
->getParentFieldViewsData($fieldDefinition);
if (empty($parentData)) {
return $data;
}
$originalTable = $parentData[$fieldTableName];
$occurrenceTableName = DateRecurOccurrences::getOccurrenceCacheStorageTableName($fieldDefinition);
if ($this->database
->schema()
->tableExists($occurrenceTableName)) {
$occurrenceTable = $originalTable;
// Remove the automatic join, requires site builders to use relationship
// plugin.
unset($occurrenceTable['table']['join']);
// Unset some irrelevant fields.
foreach (array_keys($occurrenceTable) as $fieldId) {
$fieldId = (string) $fieldId;
if ($fieldId === 'table' || strpos($fieldId, $fieldName . '_value', 0) !== FALSE || strpos($fieldId, $fieldName . '_end_value', 0) !== FALSE) {
continue;
}
unset($occurrenceTable[$fieldId]);
}
// Update table name references.
$handlerTypes = $this
->getViewsPluginTypes();
$recurTableGroup = $this
->t('Occurrences for @entity_type @field_name', [
'@entity_type' => $entityType
->getLabel(),
'@field_name' => $fieldLabel,
]);
foreach ($occurrenceTable as $fieldId => &$field) {
$field['group'] = $recurTableGroup;
foreach ($handlerTypes as $handlerType) {
if (!empty($field[$handlerType]['table'])) {
$field[$handlerType]['table'] = $occurrenceTableName;
$field[$handlerType]['additional fields'] = [
$fieldName . '_value',
$fieldName . '_end_value',
'delta',
'field_delta',
];
}
}
}
$data[$occurrenceTableName] = $occurrenceTable;
}
$fieldTable = $originalTable;
// Change the title for all plugins provided by
// \datetime_range_field_views_data().
foreach ($fieldTable as $key => &$definitions) {
/** @var \Drupal\Core\StringTranslation\TranslatableMarkup|string|null $originalTitle */
$originalTitle = $definitions['title'] ?? '';
$tArgs = $originalTitle instanceof TranslatableMarkup ? $originalTitle
->getArguments() : [];
$tArgs['@field_label'] = $fieldLabel;
if ($fieldName === $key) {
$definitions['title'] = isset($tArgs['@argument']) ? $this
->t('@field_label (@argument)', $tArgs) : $this
->t('@field_label', $tArgs);
}
elseif (strpos($key, $fieldName . '_value', 0) !== FALSE) {
$definitions['title'] = isset($tArgs['@argument']) ? $this
->t('@field_label: first occurrence start date (@argument)', $tArgs) : $this
->t('@field_label: first occurrence start date', $tArgs);
}
elseif (strpos($key, $fieldName . '_end_value', 0) !== FALSE) {
$definitions['title'] = isset($tArgs['@argument']) ? $this
->t('@field_label: first occurrence end date (@argument)', $tArgs) : $this
->t('@field_label: first occurrence end date', $tArgs);
}
elseif (strpos($key, $fieldName . '_rrule', 0) !== FALSE) {
$definitions['title'] = $this
->t('@field_label: recurring rule', $tArgs);
}
elseif (strpos($key, $fieldName . '_timezone', 0) !== FALSE) {
$definitions['title'] = $this
->t('@field_label: time zone', $tArgs);
}
elseif (strpos($key, $fieldName . '_infinite', 0) !== FALSE) {
$definitions['title'] = $this
->t('@field_label: is infinite', $tArgs);
}
elseif ('delta' === $key) {
$definitions['title'] = $this
->t('@field_label: field delta', $tArgs);
}
}
$data[$fieldTableName] = $fieldTable;
return $data;
}
/**
* Get date recur fields for entities supporting views.
*
* @return array
* An array of arrays of date recur fields keyed by entity type ID.
*/
protected function getDateRecurFields() : array {
// Date recur fields keyed by entity type id.
$fields = [];
// Get all date recur fields as base and attached fields.
foreach ($this->entityTypeManager
->getDefinitions() as $entityType) {
// \Drupal\views\EntityViewsData class only allows entities with
// \Drupal\Core\Entity\Sql\SqlEntityStorageInterface.
// Only fieldable entities have base fields.
if ($this->entityTypeManager
->getStorage($entityType
->id()) instanceof SqlEntityStorageInterface && $entityType
->hasHandlerClass('views_data') && $entityType
->entityClassImplements(FieldableEntityInterface::class)) {
$fields[$entityType
->id()] = array_filter($this->entityFieldManager
->getFieldStorageDefinitions($entityType
->id()), function (FieldStorageDefinitionInterface $field) : bool {
$typeDefinition = $this->typedDataManager
->getDefinition('field_item:' . $field
->getType());
// @see \Drupal\date_recur\DateRecurCachedHooks::fieldInfoAlter
return isset($typeDefinition[DateRecurOccurrences::IS_DATE_RECUR]);
});
}
}
// Remove entity types with no date recur fields.
$fields = array_filter($fields);
return $fields;
}
/**
* Get the most popular label for a field storage.
*
* @param string $entityTypeId
* The entity type ID.
* @param string $fieldName
* The field.
*
* @return string
* The most popular label for a field storage.
*/
protected function getFieldLabel($entityTypeId, $fieldName) : string {
return \views_entity_field_label($entityTypeId, $fieldName)[0];
}
/**
* Get the views definition for the field, as defined by datetime_range.
*
* @param \Drupal\field\FieldStorageConfigInterface $fieldDefinition
* A field storage definition.
*
* @return array
* The views data for a field.
*/
protected function getParentFieldViewsData(FieldStorageConfigInterface $fieldDefinition) : array {
$this->moduleHandler
->loadInclude('datetime_range', 'inc', 'datetime_range.views');
return \datetime_range_field_views_data($fieldDefinition);
}
/**
* Get an array of all views plugin types.
*
* @return array
* An array of all views plugin types.
*/
protected function getViewsPluginTypes() : array {
return Views::getPluginTypes();
}
/**
* Get date format of field storage.
*
* @param \Drupal\Core\Field\FieldStorageDefinitionInterface $fieldDefinition
* A field definition.
*
* @return string
* A date format.
*/
protected function getFieldDateFormat(FieldStorageDefinitionInterface $fieldDefinition) : string {
return $fieldDefinition
->getSetting('datetime_type') == DateTimeItem::DATETIME_TYPE_DATE ? DateTimeItemInterface::DATE_STORAGE_FORMAT : DateTimeItemInterface::DATETIME_STORAGE_FORMAT;
}
}
Members
Name | Modifiers | Type | Description | Overrides |
---|---|---|---|---|
DateRecurViewsHooks:: |
protected | property | The active database connection. | |
DateRecurViewsHooks:: |
protected | property | The entity field manager. | |
DateRecurViewsHooks:: |
protected | property | Entity type manager. | |
DateRecurViewsHooks:: |
protected | property | Module handler. | |
DateRecurViewsHooks:: |
protected | property | The typed data manager. | |
DateRecurViewsHooks:: |
public static | function |
Instantiates a new instance of this class. Overrides ContainerInjectionInterface:: |
|
DateRecurViewsHooks:: |
public | function | Implements hook_field_views_data(). | |
DateRecurViewsHooks:: |
protected | function | Get date recur fields for entities supporting views. | |
DateRecurViewsHooks:: |
protected | function | Get date format of field storage. | |
DateRecurViewsHooks:: |
protected | function | Get the most popular label for a field storage. | |
DateRecurViewsHooks:: |
protected | function | Get the views definition for the field, as defined by datetime_range. | |
DateRecurViewsHooks:: |
protected | function | Get an array of all views plugin types. | |
DateRecurViewsHooks:: |
public | function | Implements hook_views_data(). | |
DateRecurViewsHooks:: |
public | function | Implements hook_views_data_alter(). | |
DateRecurViewsHooks:: |
public | function | DateRecurViewsHooks constructor. | |
StringTranslationTrait:: |
protected | property | The string translation service. | 4 |
StringTranslationTrait:: |
protected | function | Formats a string containing a count of items. | |
StringTranslationTrait:: |
protected | function | Returns the number of plurals supported by a given language. | |
StringTranslationTrait:: |
protected | function | Gets the string translation service. | |
StringTranslationTrait:: |
public | function | Sets the string translation service to use. | 2 |
StringTranslationTrait:: |
protected | function | Translates a string to the current language or to a given language. |