more_fields-2.2.19/src/Plugin/views/filter/MoreFieldsBaseFilter.php
src/Plugin/views/filter/MoreFieldsBaseFilter.php
<?php
namespace Drupal\more_fields\Plugin\views\filter;
use Drupal\mysql\Driver\Database\mysql\Select;
use Drupal\Core\Entity\Query\QueryInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\views\Views;
/**
* Ficher de base poour les filtres vues.
*
* @author stephane
*
*/
trait MoreFieldsBaseFilter {
/**
*
* @var \Drupal\views\Plugin\ViewsHandlerManager
*/
protected $ViewsHandlerManager;
/**
* Le clé alias qui va stoker le nombre de valeur.
*
* @var string
*/
protected $alias_count = 'count_termes';
/**
* Contient nombre d'entites par terms.
*
* @var array
*/
protected $countsTerms = [];
/**
*
* @var array
*/
protected $ViewsQuerySubstitutions = [];
/**
* On construit la requete de base pour le sql.
* Pour l'instant le cache ne fonctionne pas, il faudra voir pourquoi.
*
* @return \Drupal\mysql\Driver\Database\mysql\Select
*/
protected function buildBaseSql() {
// On met en cache le sql obtenu durant toute la requete.
static $drupal_static_fast;
if (!isset($drupal_static_fast)) {
$drupal_static_fast['buildBaseSql'] = &drupal_static(__FUNCTION__ . $this->view->id());
// on pourrait definir un systeme de cache avancé qui tienne compte de la
// requete et de l'id de la view.
}
$select_query = $drupal_static_fast['buildBaseSql'];
if (empty($select_query)) {
$select_query = $this->baseSql();
// Add all query substitutions as metadata.
if ($select_query instanceof \Drupal\mysql\Driver\Database\mysql\Select)
$select_query->addMetaData('views_substitutions', $this->buildViewsQuerySubstitutions());
}
return $select_query;
}
/**
* Retourne la requette de base.
*
* @return \Drupal\mysql\Driver\Database\mysql\Select|\Drupal\search_api\Query\Query
*/
protected function baseSql() {
// On charge une nouvelle instance de vue car on a un bug de surcharge
// entre les requetes.
$view_name = $this->view->id(); // valeur à remplacer
$view_display = $this->view->current_display; // valeur à remplacer
$viewInstance = Views::getView($view_name);
$viewInstance->args = $this->view->args;
$viewInstance->setDisplay($view_display);
// Execute view query.
$viewInstance->initHandlers();
// dump("Run buildBaseSql");
/**
* On initialise la vue, ie on construit la requete "select" de base.
*/
$viewInstance->initQuery();
// Build all the relationships first thing.
$viewInstance->_build('relationship');
// On applique le filter, ce dernier ajoute globalement le WHERE et
// certaines JOINTUREs.
$viewInstance->_build('filter', true);
// dump($viewInstance->query->query()->__toString());
// On construit les autres requetes.
$filters = $viewInstance->filter;
// dump($view_display, $filters);
// On recupere les valeurs exposeds à partir de la vue encours.
$exposed_inputs = $this->view->getExposedInput();
// On s'assure que la champs encours de traitement est effectivement dans
// les jointures.
if (!empty($filters[$this->field])) {
$filters[$this->field]->ensureMyTable();
}
// on ajoute les filtres statiques.
foreach ($filters as $filter) {
if (!$filter->isExposed()) {
$filter->ensureMyTable();
}
}
// On construit les arguments (inspirer par:
// \Drupal\views\Views_buildArguments()
// version D : 10.2.4
$position = -1;
if (!empty($viewInstance->argument)) {
foreach ($viewInstance->argument as $id => $argument) {
/**
*
* @var \Drupal\taxonomy\Plugin\views\argument\IndexTid $argument
*/
$position++;
if ($argument->broken()) {
continue;
}
$argument->setRelationship();
$arg = $viewInstance->args[$position] ?? NULL;
$argument->position = $position;
if (isset($arg) || $argument->hasDefaultArgument()) {
if (!isset($arg)) {
$arg = $argument->getDefaultArgument();
// make sure default args get put back.
if (isset($arg)) {
$viewInstance->args[$position] = $arg;
}
// remember that this argument was computed, not passed on the
// URL.
$argument->is_default = TRUE;
}
}
if (!$argument->setArgument($arg)) {
$argument->validateFail($arg);
break;
}
$argument->query();
}
}
// On construit les jointures uniquement avec les valeurs exposed.
foreach ($exposed_inputs as $id => $value) {
if (!empty($filters[$id])) {
$filter = $filters[$id];
$filter->ensureMyTable();
}
}
/**
* On recupere la requete select apres toutes les constructions.
* ( elle peut etre mise en cache pour une requete données ).
*/
return $viewInstance->query->query();
}
/**
*
* @return array
*/
protected function defineOptions() {
$options = parent::defineOptions();
$options['type'] = [
'default' => 'select'
];
$options['show_entities_numbers'] = [
'default' => true
];
// igonre la valeur selectionnée.
$options['ignore_default_value'] = [
'default' => false
];
return $options;
}
public function buildExposeForm(&$form, FormStateInterface $form_state) {
parent::buildExposeForm($form, $form_state);
// on ajoute la possibilite d'afficher ou pas le nombre d'entité
$form['show_entities_numbers'] = [
'#type' => 'checkbox',
'#title' => "Affiche le nombre d'entité par termes",
'#default_value' => $this->options['show_entities_numbers']
];
$form['ignore_default_value'] = [
'#type' => 'checkbox',
'#title' => "Ignore la valeur selectionnée",
'#default_value' => $this->options['ignore_default_value'],
'#description' => "Cela permet aux termes de fonctionner un peu comme un menu"
];
}
/**
* Permet de construire les de type joins.
* example :
* $configuration = [
* 'type' => 'INNER',
* 'table' => $table_field,
* 'field' => 'entity_id',
* 'left_table' => $base_table,
* 'left_field' => 'field_id',
* 'extra_operator' => 'AND',
* 'adjusted' => true
* ];
*
* @param Select $select
*/
protected function buildQueryJoin(Select $select, array $configuration) {
$select->addJoin($configuration['type'], $configuration['left_table'], $configuration['left_table'], $this->buildQueryJoinCondition($configuration));
$select->addTag('more_fields_checkbox_list__' . $configuration['left_table']);
}
private function buildQueryJoinCondition(array $configuration) {
return $configuration['left_table'] . '.' . $configuration['left_field'] . "=" . $configuration['table'] . '.' . $configuration['field'];
}
/**
* Construit les requetes statiques.
* ( permet d'ajouter ce prendre en compte les filtres definie au niveau de la
* vue ).
*
* @param Select $select_query
* @param array $filters
* @param string $base_table
*/
protected function buildStaticQueryByViewsJoin(Select &$select_query, array $filters, string $base_table) {
foreach ($filters as $currentFilter) {
/**
*
* @var \Drupal\views\Plugin\views\filter\FilterPluginBase $currentFilter
*/
if ($currentFilter->options['exposed'] === FALSE) {
$table = [
'table' => $currentFilter->table,
'num' => 1,
'alias' => $currentFilter->tableAlias ? $currentFilter->tableAlias : $currentFilter->table,
// 'join'=>
'relationship' => $base_table
];
// Le cas ou le champs est inclus dans la table principal.
if ($select_query->hasTag('more_fields_checkbox_list__' . $currentFilter->table)) {
$this->buildCondition($select_query, $table['alias'], $currentFilter->realField, $currentFilter->options['value'], $currentFilter->operator);
}
}
}
}
protected function buildCondition(\Drupal\Core\Database\Query\Select &$select_query, $alias, $field, $value, $operator) {
$AddCondition = true;
if ($operator == 'or') {
$operator = 'in';
if ($value === '' || $value === 'All')
$AddCondition = false;
// Specifique à or car les données sont censer etre dans un array.
if (!is_array($value))
$value = [
$value
];
}
elseif ($operator == 'contains') {
$operator = 'LIKE';
$value = '%' . $select_query->escapeLike($value) . '%';
}
elseif ($operator == 'between') {
if (!empty($value['min']) && empty($value['max'])) {
$operator = '>=';
$value = $value['min'];
}
elseif (empty($value['min']) && !empty($value['max'])) {
$operator = '<=';
$value = $value['max'];
}
elseif (empty($value['min']) && empty($value['max'])) {
$AddCondition = false;
}
}
elseif ($operator == 'in' && is_array($value) && $value[0] == 'All') {
$AddCondition = false;
}
// $db = [
// 'field' => $field,
// 'value' => $value,
// 'operateur' => $operator
// ];
if ($AddCondition)
$select_query->condition($alias . '.' . $field, $value, $operator);
}
/**
* On ajoute les filtres exposed ayant des valeurs.
*
* @param \Drupal\Core\Database\Query\Select $query
* @param array $filters
* @param string $base_table
* @param string $field_id
* @param array $exposed_inputs
*/
protected function buildFilterExposedQueryByViewsJoin(Select &$select_query, array $filters, string $base_table, string $field_id, array $exposed_inputs) {
foreach ($exposed_inputs as $filterId => $value) {
if (!empty($filters[$filterId])) {
/**
*
* @var \Drupal\views\Plugin\views\filter\FilterPluginBase $currentFilter
*/
$currentFilter = $filters[$filterId];
$configuration = [
'type' => 'INNER',
'table' => $currentFilter->table,
'field' => 'entity_id',
'left_table' => $base_table,
'left_field' => $field_id,
'extra_operator' => 'AND',
'adjusted' => true
];
$table = [
'table' => $currentFilter->table,
'num' => 1,
'alias' => $currentFilter->tableAlias ? $currentFilter->tableAlias : $currentFilter->table,
// 'join'=>
'relationship' => $base_table
];
/**
*
* @var \Drupal\views\Plugin\views\join\Standard $instance
*/
if (!$select_query->hasTag('more_fields_checkbox_list__' . $currentFilter->table)) {
$instance = $this->initViewsJoin()->createInstance("standard", $configuration);
$instance->buildJoin($select_query, $table, $this->view->query);
$select_query->addTag('more_fields_checkbox_list__' . $currentFilter->table);
}
$this->buildCondition($select_query, $table['alias'], $currentFilter->realField, $value, $currentFilter->operator);
}
}
}
/**
* Cette fonction n'est pas automatique, elle fonctionnera au cas par cas en
* attandant de la rendre dynamique.
*
* @param \Drupal\Core\Database\Query\Select $select_query
* @param array $arguments
* @param string $base_table
* @param string $field_id
*/
protected function buildFilterArguments(\Drupal\Core\Database\Query\Select &$select_query, array $arguments, array $args, string $base_table, string $field_id) {
$position = 0;
// cas : $base_table == node_field_data et argument => taxonomy_index
if ($base_table == 'node_field_data') {
foreach ($arguments as $argument) {
if (isset($args[$position])) {
$arg = $args[$position];
$position++;
}
// s'il nya pas d'argument on continue.
if (!isset($arg))
continue;
$configuration = [
'type' => 'INNER',
'table' => $argument->table,
'field' => 'nid',
'left_table' => $base_table,
'left_field' => $field_id,
'extra_operator' => 'AND',
'adjusted' => true
];
$table = [
'table' => $argument->table,
'num' => 1,
'alias' => $argument->tableAlias ? $argument->tableAlias : $argument->table,
// 'join'=>
'relationship' => $base_table
];
/**
*
* @var \Drupal\views\Plugin\views\argument\ArgumentPluginBase $argument
*/
if ($argument->table == 'taxonomy_index') {
/**
*
* @var \Drupal\views\Plugin\views\join\Standard $instance
*/
if (!$select_query->hasTag('more_fields_checkbox_list__' . $argument->table)) {
$instance = $this->initViewsJoin()->createInstance("standard", $configuration);
$instance->buildJoin($select_query, $table, $this->view->query);
$select_query->addTag('more_fields_checkbox_list__' . $argument->table);
}
$this->buildCondition($select_query, $table['alias'], $argument->realField, $arg, $argument->operator);
}
}
}
}
/**
* Ajoute dans la requetes les selections de l'utilisateur.
*
* @param select $select_query
*/
protected function buildAnothersQuery(select $select_query) {
$filters = $this->buildValidFilters();
$base_table = $this->getTableNameFromIndex($this->table);
$this->buildStaticQueryByViewsJoin($select_query, $filters, $base_table);
/**
* Liste des champs contenant les inputs present dans l'url.
*
* @var array $exposed_inputs
*/
$exposed_inputs = $this->view->getExposedInput();
if ($exposed_inputs)
$this->buildFilterExposedQueryByViewsJoin($select_query, $filters, $base_table, 'item_id', $exposed_inputs);
if (!empty($this->view->argument))
$this->buildFilterArguments($select_query, $this->view->argument, $this->view->args, $base_table, 'item_id');
// apply views_substitutions
\Drupal::moduleHandler()->loadInclude('views', "module");
views_query_views_alter($select_query);
}
/**
* Liste des filtres exposed.
*
* @return array
*/
protected function buildValidFilters() {
/**
* Contient les informations sur chaque filtre.
* On va ajouter les filtres statiques et aussi ajouter les filtre passé
* en paramettre via les filtres exposés.
*
* @var array $filters
*/
$defaultFilters = $this->view->filter;
$filters = [];
if ($defaultFilters) {
foreach ($defaultFilters as $currentFilter) {
/**
*
* @var \Drupal\views\Plugin\views\filter\ManyToOne $currentFilter
*/
if ($currentFilter->getPluginId() == $this->pluginId || !empty($currentFilter->options['exposed'])) {
$key = !empty($currentFilter->options['expose']['identifier']) ? $currentFilter->options['expose']['identifier'] : $currentFilter->realField;
$filters[$key] = $currentFilter;
}
}
}
return $filters;
}
/**
*
* @return array
*/
protected function buildViewsQuerySubstitutions() {
if (!$this->ViewsQuerySubstitutions) {
$this->ViewsQuerySubstitutions = \Drupal::moduleHandler()->invokeAll('views_query_substitutions', [
$this->view
]);
}
return $this->ViewsQuerySubstitutions;
}
/**
*
* @return \Drupal\views\Plugin\ViewsHandlerManager
*/
protected function initViewsJoin() {
if (!$this->ViewsHandlerManager) {
/**
*
* @var \Drupal\views\Plugin\ViewsHandlerManager $ViewsHandlerManager
*/
$this->ViewsHandlerManager = \Drupal::service('plugin.manager.views.join');
}
return $this->ViewsHandlerManager;
}
/**
* On va selectionner les entités qui possedent un terme dans le champs en
* question, les groupes par tid, ensuite recuperer la liste des tids.
*
* @param \Drupal\Core\Entity\Query\Sql\Query $query
* @see https://drupal.stackexchange.com/questions/184411/entityquery-group-by-clause
* @deprecated car n'est plus utiliser
*/
protected function FilterTermHasContent(QueryInterface &$query, \Drupal\mysql\Driver\Database\mysql\Select $queryEntity) {
$entities = $queryEntity->execute()->fetchAll(\PDO::FETCH_ASSOC);
if ($entities) {
$tids = [];
foreach ($entities as $value) {
$tids[] = $value[$this->configuration['field']];
$this->countsTerms[$value[$this->configuration['field']]] = $value[$this->alias_count];
}
$query->condition('tid', $tids, 'IN');
}
else {
// S'il nya pas de correspondance, on vide la requete.
// ( on verra si on peut faire cela autrement ).
$query->condition('tid', null, "IS NULL");
}
}
/**
* Contruit les requetes de la vue à partir du filtre.
* Ancinne approche,
*
* @deprecated cette fonction est deprecié ici, car on utilise une approche un
* peu plus proche de la logique de views.
*/
public function FilterCountEntitiesHasterm() {
/**
* Le nom de la colonne utile.
*
* @var string $colomn_name
*/
$colomn_name = $this->configuration['field'];
/**
* Contient les informations sur chaque filtre.
* On va ajouter les filtres statiques et aussi ajouter les filtre passé
* en paramettre via les filtres exposés.
*
* @var array $filters
*/
$filters = $this->view->filter;
$base_table = $this->view->storage->get('base_table');
$field_id = $this->view->storage->get('base_field');
$this->view->initDisplay();
/**
*
* @var \Drupal\views\Plugin\views\filter\FilterPluginBase $currentFilter
*/
$currentFilter = isset($filters['more_fields_' . $colomn_name]) ? $filters['more_fields_' . $colomn_name] : NULL;
if ($currentFilter) {
$configuration = [
'type' => 'INNER',
'table' => $currentFilter->table,
'field' => 'entity_id',
'left_table' => $base_table,
'left_field' => $field_id,
'extra_operator' => 'AND',
'adjusted' => true
];
$table = [
'table' => $currentFilter->table,
'num' => 1,
'alias' => $currentFilter->tableAlias ? $currentFilter->tableAlias : $currentFilter->table,
// 'join'=>
'relationship' => $this->view->storage->get('base_table')
];
// constructions à partir de l'object
/**
*
* @var \Drupal\mysql\Driver\Database\mysql\Select $select_query
*/
$select_query = \Drupal::database()->select($base_table, $base_table);
$select_query->fields($base_table, [
$field_id
]);
// On ajoute la table dans les tags et on y ajoute l'id du pludin afin
// d'eviter que d'autre module sy connecte.
$select_query->addTag('more_fields_checkbox_list__' . $base_table);
if (!$this->view->query)
$this->view->getQuery();
/**
*
* @var \Drupal\views\Plugin\views\join\Standard $instance
*/
$instance = $this->initViewsJoin()->createInstance("standard", $configuration);
$instance->buildJoin($select_query, $table, $this->view->query);
//
$select_query->addField($table['alias'], $colomn_name);
$select_query->addExpression("count($table[alias].$colomn_name)", $this->alias_count);
$select_query->groupBy($table['alias'] . '.' . $colomn_name);
$select_query->addTag('more_fields_checkbox_list__' . $currentFilter->table);
// Add all query substitutions as metadata.
$select_query->addMetaData('views_substitutions', $this->buildViewsQuerySubstitutions());
// build orther query.
$this->buildStaticQueryByViewsJoin($select_query, $filters, $base_table);
/**
* Tableau contennant les valeurs deja selectionner par l'utilisateur.
*
* @var array $exposed_inputs
*/
$exposed_inputs = $this->view->getExposedInput();
if ($exposed_inputs)
$this->buildFilterExposedQueryByViewsJoin($select_query, $filters, $base_table, $field_id, $exposed_inputs);
if (!empty($this->view->argument))
$this->buildFilterArguments($select_query, $this->view->argument, $this->view->args, $base_table, $field_id);
// apply views_substitutions
\Drupal::moduleHandler()->loadInclude('views', "module");
views_query_views_alter($select_query);
return $select_query;
}
}
}