View source
<?php
namespace Drupal\views;
use Drupal\Core\Database\Query\Condition;
use Drupal\Core\Form\FormStateInterface;
use Drupal\views\Plugin\views\HandlerBase;
class ManyToOneHelper {
public function __construct($handler) {
$this->handler = $handler;
}
public static function defineOptions(&$options) {
$options['reduce_duplicates'] = [
'default' => FALSE,
];
}
public function buildOptionsForm(&$form, FormStateInterface $form_state) {
$form['reduce_duplicates'] = [
'#type' => 'checkbox',
'#title' => t('Reduce duplicates'),
'#description' => t("This filter can cause items that have more than one of the selected options to appear as duplicate results. If this filter causes duplicate results to occur, this checkbox can reduce those duplicates; however, the more terms it has to search for, the less performant the query will be, so use this with caution. Shouldn't be set on single-value fields, as it may cause values to disappear from display, if used on an incompatible field."),
'#default_value' => !empty($this->handler->options['reduce_duplicates']),
'#weight' => 4,
];
}
public function getField() {
if (!empty($this->formula)) {
return $this->handler
->getFormula();
}
else {
return $this->handler->tableAlias . '.' . $this->handler->realField;
}
}
public function addTable($join = NULL, $alias = NULL) {
$field = $this->handler->relationship . '_' . $this->handler->table . '.' . $this->handler->field;
if (empty($join)) {
$join = $this
->getJoin();
}
$relationship = $this->handler->relationship;
if (empty($this->handler->query->relationships[$relationship])) {
$base_table = $this->handler->view->storage
->get('base_table');
}
else {
$base_table = $this->handler->query->relationships[$relationship]['base'];
}
$r_join = clone $join;
while ($r_join->leftTable != $base_table) {
$r_join = HandlerBase::getTableJoin($r_join->leftTable, $base_table);
}
if ($r_join->table != $join->table) {
$relationship = $this->handler->query
->addRelationship($this->handler->table . '_' . $r_join->table, $r_join, $r_join->table, $this->handler->relationship);
}
$alias = $this->handler->query
->addTable($this->handler->table, $relationship, $join, $alias);
if (empty($this->handler->view->many_to_one_tables[$field])) {
$this->handler->view->many_to_one_tables[$field] = $this->handler->value;
}
else {
$this->handler->view->many_to_one_tables[$field] = array_merge($this->handler->view->many_to_one_tables[$field], $this->handler->value);
}
return $alias;
}
public function getJoin() {
return $this->handler
->getJoin();
}
public function summaryJoin() {
$field = $this->handler->relationship . '_' . $this->handler->table . '.' . $this->handler->field;
$join = $this
->getJoin();
$options = $this->handler->options;
$view = $this->handler->view;
$query = $this->handler->query;
if (!empty($options['require_value'])) {
$join->type = 'INNER';
}
if (empty($options['add_table']) || empty($view->many_to_one_tables[$field])) {
return $query
->ensureTable($this->handler->table, $this->handler->relationship, $join);
}
else {
if (!empty($view->many_to_one_tables[$field])) {
foreach ($view->many_to_one_tables[$field] as $value) {
$join->extra = [
[
'field' => $this->handler->realField,
'operator' => '!=',
'value' => $value,
'numeric' => !empty($this->definition['numeric']),
],
];
}
}
return $this
->addTable($join);
}
}
public function ensureMyTable() {
if (!isset($this->handler->tableAlias)) {
$field = $this->handler->relationship . '_' . $this->handler->table . '.' . $this->handler->field;
if ($this->handler->operator == 'or' && empty($this->handler->options['reduce_duplicates'])) {
if (empty($this->handler->options['add_table']) && empty($this->handler->view->many_to_one_tables[$field])) {
$join = $this
->getJoin();
if (isset($join)) {
$join->type = 'INNER';
}
$this->handler->tableAlias = $this->handler->query
->ensureTable($this->handler->table, $this->handler->relationship, $join);
$this->handler->view->many_to_one_tables[$field] = $this->handler->value;
}
else {
$join = $this
->getJoin();
$join->type = 'LEFT';
if (!empty($this->handler->view->many_to_one_tables[$field])) {
foreach ($this->handler->view->many_to_one_tables[$field] as $value) {
$join->extra = [
[
'field' => $this->handler->realField,
'operator' => '!=',
'value' => $value,
'numeric' => !empty($this->handler->definition['numeric']),
],
];
}
}
$this->handler->tableAlias = $this
->addTable($join);
}
return $this->handler->tableAlias;
}
if ($this->handler->operator != 'not') {
$this->handler->tableAliases = [];
foreach ($this->handler->value as $value) {
$join = $this
->getJoin();
if ($this->handler->operator == 'and') {
$join->type = 'INNER';
}
$join->extra = [
[
'field' => $this->handler->realField,
'value' => $value,
'numeric' => !empty($this->handler->definition['numeric']),
],
];
if (!isset($this->handler->view->many_to_one_aliases[$field][$value])) {
if (!isset($this->handler->view->many_to_one_count[$this->handler->table])) {
$this->handler->view->many_to_one_count[$this->handler->table] = 0;
}
$this->handler->view->many_to_one_aliases[$field][$value] = $this->handler->table . '_value_' . $this->handler->view->many_to_one_count[$this->handler->table]++;
}
$this->handler->tableAliases[$value] = $this
->addTable($join, $this->handler->view->many_to_one_aliases[$field][$value]);
if (empty($this->handler->tableAlias)) {
$this->handler->tableAlias = $this->handler->tableAliases[$value];
}
}
}
else {
$join = $this
->getJoin();
$join->type = 'LEFT';
$join->extra = [];
$join->extraOperator = 'OR';
foreach ($this->handler->value as $value) {
$join->extra[] = [
'field' => $this->handler->realField,
'value' => $value,
'numeric' => !empty($this->handler->definition['numeric']),
];
}
$this->handler->tableAlias = $this
->addTable($join);
}
}
return $this->handler->tableAlias;
}
protected function placeholder() {
return $this->handler->query
->placeholder($this->handler->options['table'] . '_' . $this->handler->options['field']);
}
public function addFilter() {
if (empty($this->handler->value)) {
return;
}
$this->handler
->ensureMyTable();
$field = $this
->getField();
$options = $this->handler->options;
$operator = $this->handler->operator;
$formula = !empty($this->formula);
$value = $this->handler->value;
if (empty($options['group'])) {
$options['group'] = 0;
}
$add_condition = TRUE;
if ($operator == 'not') {
$value = NULL;
$operator = 'IS NULL';
$add_condition = FALSE;
}
elseif ($operator == 'or' && empty($options['reduce_duplicates'])) {
if (count($value) > 1) {
$operator = 'IN';
}
else {
$value = is_array($value) ? array_pop($value) : $value;
$operator = '=';
}
$add_condition = FALSE;
}
if (!$add_condition) {
if ($formula) {
$placeholder = $this
->placeholder();
if ($operator == 'IN') {
$operator = "{$operator} IN({$placeholder})";
}
else {
$operator = "{$operator} {$placeholder}";
}
$placeholders = [
$placeholder => $value,
];
$this->handler->query
->addWhereExpression($options['group'], "{$field} {$operator}", $placeholders);
}
else {
$placeholder = $this
->placeholder();
if (count($this->handler->value) > 1) {
$placeholder .= '[]';
if ($operator == 'IS NULL') {
$this->handler->query
->addWhereExpression(0, "{$field} {$operator}");
}
else {
$this->handler->query
->addWhereExpression(0, "{$field} {$operator}({$placeholder})", [
$placeholder => $value,
]);
}
}
else {
if ($operator == 'IS NULL') {
$this->handler->query
->addWhereExpression(0, "{$field} {$operator}");
}
else {
$this->handler->query
->addWhereExpression(0, "{$field} {$operator} {$placeholder}", [
$placeholder => $value,
]);
}
}
}
}
if ($add_condition) {
$field = $this->handler->realField;
$clause = $operator == 'or' ? new Condition('OR') : new Condition('AND');
foreach ($this->handler->tableAliases as $value => $alias) {
$clause
->condition("{$alias}.{$field}", $value);
}
$this->handler->query
->addWhere($options['group'], $clause);
}
}
}