media_mpx-8.x-1.x-dev/src/Plugin/views/filter/Availability.php
src/Plugin/views/filter/Availability.php
<?php
namespace Drupal\media_mpx\Plugin\views\filter;
use Drupal\Component\Datetime\TimeInterface;
use Drupal\Core\Database\Query\Condition;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Entity\Sql\SqlContentEntityStorage;
use Drupal\Core\Form\FormStateInterface;
use Drupal\views\Plugin\views\filter\FilterPluginBase;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Filter by mpx availability.
*
* @ViewsFilter("media_mpx_availability")
*/
class Availability extends FilterPluginBase {
const AVAILABLE_UPCOMING = 'available_upcoming';
const AVAILABLE = 'available';
const EXPIRED = 'expired';
/**
* Disable the possibility to use operators.
*
* @var bool
*/
// phpcs:disable
public $no_operator = TRUE;
// phpcs:enable
/**
* Disable the possibility to force a single value.
*
* @var bool
*/
protected $alwaysMultiple = TRUE;
/**
* Entity type manager.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected $entityTypeManager;
/**
* Date time service.
*
* @var \Drupal\Component\Datetime\TimeInterface
*/
protected $time;
/**
* Constructs a Availability object.
*
* @param array $configuration
* A configuration array containing information about the plugin instance.
* @param string $plugin_id
* The plugin_id for the plugin instance.
* @param mixed $plugin_definition
* The plugin implementation definition.
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* Entity type manager.
* @param \Drupal\Component\Datetime\TimeInterface $time
* Date time service.
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManagerInterface $entity_type_manager, TimeInterface $time) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->entityTypeManager = $entity_type_manager;
$this->time = $time;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static(
$configuration,
$plugin_id,
$plugin_definition,
$container->get('entity_type.manager'),
$container->get('datetime.time')
);
}
/**
* {@inheritdoc}
*/
protected function valueForm(&$form, FormStateInterface $form_state) {
parent::valueForm($form, $form_state);
$form['value'] = [
'#type' => 'select',
'#options' => [
self::AVAILABLE_UPCOMING => $this->t('Available or upcoming'),
self::AVAILABLE => $this->t('Available'),
self::EXPIRED => $this->t('Expired'),
],
'#title' => $this->t('Availability'),
'#default_value' => $this->value,
];
}
/**
* {@inheritdoc}
*
* @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
* @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
*/
public function query() {
$media_storage = $this->entityTypeManager->getStorage('media');
// This will be limited to SQL storage backends, b/c it's highly SQL
// centric.
if (!$media_storage instanceof SqlContentEntityStorage) {
return;
}
try {
$this->addConditionOnBundle();
$this->addConditionOnAvailability();
}
catch (\RuntimeException $e) {
// Nothing can do.
}
}
/**
* Get the field names mapped to the mpx available and expired dates.
*
* @return array
* An array with the field name mapped to the mpx available date in the
* first index, and the field name mapped to the mpx expired date in the
* second index.
*
* @throws \RuntimeException
* Thrown when the available date and/or expiration date is not mapped.
* @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
* @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
*/
protected function getAvailableExpiredFieldNames() {
/** @var \Drupal\media\MediaTypeInterface $media_type */
$media_type = $this->entityTypeManager->getStorage('media_type')->load($this->definition['media_type']);
$field_map = $media_type->getFieldMap();
if (isset($field_map['Media:availableDate']) && isset($field_map['Media:expirationDate'])) {
return [
$field_map['Media:availableDate'],
$field_map['Media:expirationDate'],
];
}
throw new \RuntimeException(sprintf('mpx available date and/or mpx expiration date are not mapped for the %s media bundle.', $this->definition['media_type']));
}
/**
* Ensure that we are joined with the availability tables.
*
* @return array
* Array with available table alias in the first position and expired in the
* second position.
*
* @throws \RuntimeException
* Thrown when the available date and/or expiration date is not mapped.
* @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
* @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
*/
protected function ensureAvailabilityTables() {
[$available_table_name, $expired_table_name] = $this->getAvailableExpiredTableNames();
$available_table_alias = $this->query->ensureTable($available_table_name, $this->relationship);
$expired_table_alias = $this->query->ensureTable($expired_table_name, $this->relationship);
return [$available_table_alias, $expired_table_alias];
}
/**
* Get the available and expired table names, optionally with the column.
*
* @return array
* An array with the available table name in the first entry and the expired
* table name in the entry.
*
* @throws \RuntimeException
* Thrown when the available date and/or expiration date is not mapped.
* @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
* @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
*/
protected function getAvailableExpiredTableNames() {
[$available_field_storage, $expired_field_storage] = $this->getAvailableExpiredFieldStorage();
$media_storage = $this->entityTypeManager->getStorage('media');
$table_mapping = $media_storage->getTableMapping();
$available_table_name = $table_mapping->getDedicatedDataTableName($available_field_storage);
$expired_table_name = $table_mapping->getDedicatedDataTableName($expired_field_storage);
return [$available_table_name, $expired_table_name];
}
/**
* Get the available and expired field aliases.
*
* @return array
* Array with the available field alias in the first position and the
* expired field alias in the second position. Depending on the view
* configuration, for example if a relationship is being used, the alias
* views uses can be very different.
*
* @throws \RuntimeException
* Thrown when the available date and/or expiration date is not mapped.
* @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
* @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
*/
protected function getAvailableExpiredFieldAliases() {
[$available_table_alias, $expired_table_alias] = $this->ensureAvailabilityTables();
[$available_field_storage, $expired_field_storage] = $this->getAvailableExpiredFieldStorage();
$media_storage = $this->entityTypeManager->getStorage('media');
$table_mapping = $media_storage->getTableMapping();
$available_field_alias = sprintf('%s.%s', $available_table_alias, $table_mapping->getFieldColumnName($available_field_storage, 'value'));
$expired_field_alias = sprintf('%s.%s', $expired_table_alias, $table_mapping->getFieldColumnName($expired_field_storage, 'value'));
return [$available_field_alias, $expired_field_alias];
}
/**
* Get the available and expired field storage.
*
* @return \Drupal\Core\Field\FieldStorageDefinitionInterface[]
* An array with the available field storage in the first position and the
* expired field storage in the second position.
*
* @throws \RuntimeException
* Thrown when the available date and/or expiration date is not mapped.
* @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
* @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
*/
protected function getAvailableExpiredFieldStorage() {
[$available_field_name, $expired_field_name] = $this->getAvailableExpiredFieldNames();
$field_storage = $this->entityTypeManager->getStorage('field_storage_config');
/** @var \Drupal\Core\Field\FieldStorageDefinitionInterface $available_field_storage */
$available_field_storage = $field_storage->load('media.' . $available_field_name);
/** @var \Drupal\Core\Field\FieldStorageDefinitionInterface $expired_field_storage */
$expired_field_storage = $field_storage->load('media.' . $expired_field_name);
return [$available_field_storage, $expired_field_storage];
}
/**
* Add a condition to the query on the bundle this filter id for.
*
* @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
*/
protected function addConditionOnBundle() {
// Add a condition on the bundle that this filter is defined for.
$media_definition = $this->entityTypeManager->getDefinition('media');
$this->ensureMyTable();
$this->query->addWhere($this->options['group'], sprintf('%s.%s', $this->tableAlias, $media_definition->getKey('bundle')), $this->definition['media_type']);
}
/**
* Add a condition to the query for availability according to the selection.
*
* @throws \RuntimeException
* Thrown when the available date and/or expiration date is not mapped.
* @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
* @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
*/
protected function addConditionOnAvailability() {
if (empty($this->value) || $this->value === self::AVAILABLE_UPCOMING) {
$this->addConditionOnAvailableOrUpcoming();
}
elseif ($this->value === self::AVAILABLE) {
$this->addConditionOnAvailable();
}
elseif ($this->value === self::EXPIRED) {
$this->addConditionOnExpired();
}
}
/**
* Add a condition on available or upcoming content.
*
* @throws \RuntimeException
* Thrown when the available date and/or expiration date is not mapped.
* @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
* @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
*/
protected function addConditionOnAvailableOrUpcoming() {
[, $expired_field] = $this->getAvailableExpiredFieldAliases();
$condition = (new Condition('OR'))
->condition($expired_field, 0)
->condition($expired_field, NULL, 'IS NULL')
->condition($expired_field, $this->time->getRequestTime(), '>=');
$this->query->addWhere($this->options['group'], $condition);
}
/**
* Add a condition on available content.
*
* @throws \RuntimeException
* Thrown when the available date and/or expiration date is not mapped.
* @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
* @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
*/
protected function addConditionOnAvailable() {
[$available_field, $expired_field] = $this->getAvailableExpiredFieldAliases();
$available_condition = (new Condition('OR'))
->condition($available_field, 0)
->condition($available_field, NULL, 'IS NULL')
->condition($available_field, $this->time->getRequestTime(), '<=');
$this->query->addWhere($this->options['group'], $available_condition);
$expired_condition = (new Condition('OR'))
->condition($expired_field, 0)
->condition($expired_field, NULL, 'IS NULL')
->condition($expired_field, $this->time->getRequestTime(), '>=');
$this->query->addWhere($this->options['group'], $expired_condition);
}
/**
* Add a condition on expired content.
*
* @throws \RuntimeException
* Thrown when the available date and/or expiration date is not mapped.
* @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
* @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
*/
protected function addConditionOnExpired() {
[, $expired_field] = $this->getAvailableExpiredFieldAliases();
$condition = (new Condition('AND'))
->condition($expired_field, 0, '<>')
->condition($expired_field, NULL, 'IS NOT NULL')
->condition($expired_field, $this->time->getRequestTime(), '<=');
$this->query->addWhere($this->options['group'], $condition);
}
}
