View source
<?php
declare (strict_types=1);
namespace Drupal\date_recur;
use Drupal\Core\Database\Connection;
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\Core\Entity\EntityFieldManagerInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\TypedData\TypedDataManagerInterface;
use Drupal\datetime\Plugin\Field\FieldType\DateTimeItem;
use Drupal\datetime\Plugin\Field\FieldType\DateTimeItemInterface;
use Drupal\field\FieldStorageConfigInterface;
use Drupal\views\Views;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\Core\Entity\FieldableEntityInterface;
use Drupal\Core\Entity\Sql\SqlEntityStorageInterface;
use Drupal\Core\Field\BaseFieldDefinition;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\Core\StringTranslation\TranslatableMarkup;
class DateRecurViewsHooks implements ContainerInjectionInterface {
use StringTranslationTrait;
protected $database;
protected $moduleHandler;
protected $entityTypeManager;
protected $entityFieldManager;
protected $typedDataManager;
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;
}
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'));
}
public function viewsData() : array {
$allFields = $this
->getDateRecurFields();
$data = [];
foreach ($allFields as $entityTypeId => $fields) {
$entityType = $this->entityTypeManager
->getDefinition($entityTypeId);
$viewsData = $this->entityTypeManager
->getHandler($entityType
->id(), 'views_data');
$entityViewsTable = $viewsData
->getViewsTableForEntityType($entityType);
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(),
];
$data[$entityViewsTable][$fieldName . '_occurrences']['filter'] = [
'id' => 'date_recur_occurrences_filter',
'title' => $this
->t('Occurrences filter for @field_name', $tArgs),
'field base entity_id' => $entityIdField,
'date recur field name' => $fieldName,
'entity_type' => $entityType
->id(),
];
$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,
'title' => $this
->t('Occurrences of @field_name', $tArgs),
'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;
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');
$data[$occurrenceTableName][$startField]['sort']['id'] = 'date';
$data[$occurrenceTableName][$endField]['sort']['id'] = 'date';
}
}
}
return $data;
}
public function viewsDataAlter(array &$data) : void {
$removeFieldKeys = $this
->getViewsPluginTypes();
$removeFieldKeys = array_flip($removeFieldKeys);
$allFields = $this
->getDateRecurFields();
foreach ($allFields as $entityTypeId => $fields) {
$entityStorage = $this->entityTypeManager
->getStorage($entityTypeId);
$tableMapping = $entityStorage
->getTableMapping($fields);
foreach ($fields as $fieldId => $fieldStorage) {
if (!$fieldStorage instanceof BaseFieldDefinition) {
continue;
}
if ($tableMapping
->requiresDedicatedTableStorage($fieldStorage)) {
$fieldTable = $tableMapping
->getDedicatedDataTableName($fieldStorage);
$fieldData =& $data[$fieldTable];
foreach ($fieldData as &$field) {
$field = array_diff_key($field, $removeFieldKeys);
}
}
}
}
}
public function fieldViewsData(FieldStorageConfigInterface $fieldDefinition) : array {
$data = [];
$entityTypeId = $fieldDefinition
->getTargetEntityTypeId();
$entityType = $this->entityTypeManager
->getDefinition($entityTypeId);
$entityStorage = $this->entityTypeManager
->getStorage($entityTypeId);
$tableMapping = $entityStorage
->getTableMapping();
$fieldName = $fieldDefinition
->getName();
$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;
unset($occurrenceTable['table']['join']);
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]);
}
$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;
foreach ($fieldTable as $key => &$definitions) {
$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;
}
protected function getDateRecurFields() : array {
$fields = [];
foreach ($this->entityTypeManager
->getDefinitions() as $entityType) {
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());
return isset($typeDefinition[DateRecurOccurrences::IS_DATE_RECUR]);
});
}
}
$fields = array_filter($fields);
return $fields;
}
protected function getFieldLabel($entityTypeId, $fieldName) : string {
return \views_entity_field_label($entityTypeId, $fieldName)[0];
}
protected function getParentFieldViewsData(FieldStorageConfigInterface $fieldDefinition) : array {
$this->moduleHandler
->loadInclude('datetime_range', 'inc', 'datetime_range.views');
return \datetime_range_field_views_data($fieldDefinition);
}
protected function getViewsPluginTypes() : array {
return Views::getPluginTypes();
}
protected function getFieldDateFormat(FieldStorageDefinitionInterface $fieldDefinition) : string {
return $fieldDefinition
->getSetting('datetime_type') == DateTimeItem::DATETIME_TYPE_DATE ? DateTimeItemInterface::DATE_STORAGE_FORMAT : DateTimeItemInterface::DATETIME_STORAGE_FORMAT;
}
}