View source
<?php
namespace Drupal\elasticsearch_connector_views\Plugin\views\query;
use Drupal\Core\Form\FormStateInterface;
use Drupal\elasticsearch_connector\Entity\Cluster;
use Drupal\views\Plugin\views\display\DisplayPluginBase;
use Drupal\views\Plugin\views\query\QueryPluginBase;
use Drupal\views\ResultRow;
use Drupal\views\ViewExecutable;
use Drupal\views\Views;
use Psr\Log\LoggerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
class ElasticsearchViewsQuery extends QueryPluginBase {
protected $limit;
protected $offset;
protected $index;
protected $elasticsearchTypes;
protected $elasticsearchCluster;
protected $elasticsearchClient;
protected $errors = array();
protected $abort = FALSE;
protected $retrievedProperties = array();
protected $conditions = array();
protected $groupOperator = 'AND';
protected $logger;
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
$plugin = parent::create($container, $configuration, $plugin_id, $plugin_definition);
$logger = $container
->get('logger.factory')
->get('elasticsearch_connector_views');
$plugin
->setLogger($logger);
return $plugin;
}
public function getLogger() {
return $this->logger ?: \Drupal::logger('elasticsearch_connector_views');
}
public function setLogger(LoggerInterface $logger) {
$this->logger = $logger;
return $this;
}
public function init(ViewExecutable $view, DisplayPluginBase $display, array &$options = NULL) {
try {
parent::init($view, $display, $options);
$view_id = $this->view->storage
->get('base_table');
$data = Views::viewsData()
->get($view_id);
$cluster_id = $data['table']['base']['cluster_id'];
$this->index = $data['table']['base']['index'];
$this->elasticsearchTypes[$data['table']['base']['type']] = $data['table']['base']['type'];
$this->elasticsearchCluster = Cluster::load($cluster_id);
$clientManager = \Drupal::service('elasticsearch_connector.client_manager');
$this->elasticsearchClient = $clientManager
->getClientForCluster($this->elasticsearchCluster);
} catch (\Exception $e) {
$this
->abort($e
->getMessage());
}
}
public function addField($table, $field, $alias = '', $params = array()) {
$this->fields[$field] = $field;
}
public function ensureTable($table, $relationship = NULL, JoinPluginBase $join = NULL) {
return NULL;
}
public function defineOptions() {
return parent::defineOptions() + array(
'bypass_access' => array(
'default' => FALSE,
),
'skip_access' => array(
'default' => FALSE,
),
'parse_mode' => array(
'default' => 'terms',
),
);
}
public function buildOptionsForm(&$form, FormStateInterface $form_state) {
parent::buildOptionsForm($form, $form_state);
$form['bypass_access'] = array(
'#type' => 'checkbox',
'#title' => $this
->t('Bypass access checks'),
'#description' => $this
->t('If the underlying search index has access checks enabled (e.g., through the "Content access" processor), this option allows you to disable them for this view. This will never disable any filters placed on this view.'),
'#default_value' => $this->options['bypass_access'],
);
if ($this
->getEntityTypes(TRUE)) {
$form['skip_access'] = array(
'#type' => 'checkbox',
'#title' => $this
->t('Skip entity access checks'),
'#description' => $this
->t("By default, an additional access check will be executed for each entity returned by the search query. However, since removing results this way will break paging and result counts, it is preferable to configure the view in a way that it will only return accessible results. If you are sure that only accessible results will be returned in the search, or if you want to show results to which the user normally wouldn't have access, you can enable this option to skip those additional access checks. This should be used with care."),
'#default_value' => $this->options['skip_access'],
'#weight' => -1,
);
$form['bypass_access']['#states']['visible'][':input[name="query[options][skip_access]"]']['checked'] = TRUE;
}
$form['parse_mode'] = array(
'#type' => 'select',
'#title' => $this
->t('Parse mode'),
'#description' => $this
->t('Choose how the search keys will be parsed.'),
'#options' => array(),
'#default_value' => $this->options['parse_mode'],
);
}
public function build(ViewExecutable $view) {
$this->view = $view;
$this->view = $view;
$view
->initPager();
$view->pager
->query();
if ($this
->shouldAbort()) {
return;
}
foreach ($view->field as $field_name => &$field) {
$field->field_alias = $field_name;
$field->aliases['entity_type'] = 'entity_type';
}
$this->params['fields'] = array_keys($view->field);
$this->params['fields'][] = '_source';
$params = array();
if (isset($this->params['q']) && !empty($this->params['q'])) {
if (count($this->params['fields']) > 1) {
$params['query']['multi_match'] = array(
'query' => $this->params['q'],
'fields' => array_values($this->params['fulltext_fields']),
);
}
else {
$params['query']['match'] = array(
reset($this->params['fulltext_fields']) => array(
'query' => $this->params['q'],
'operator' => $this->params['fulltext_operator'],
),
);
}
}
$params['size'] = $view->pager
->getItemsPerPage();
$params['from'] = $view->pager
->getCurrentPage() * $view->pager
->getItemsPerPage();
if ($params['size'] == 0) {
unset($params['size']);
}
$params['fields'] = array();
if (isset($this->params['fields'])) {
$params['fields'] = array_merge($params['fields'], $this->params['fields']);
}
$where = $this->where;
$params['filter'] = $this
->buildFilterArray($where);
if (empty($params['filter'])) {
unset($params['filter']);
}
if (isset($params['filter']) && isset($params['query'])) {
$temp = $params['query'];
unset($params['query']);
$params['query']['filtered'] = array(
'query' => $temp,
'filter' => $params['filter'],
);
unset($params['filter']);
}
if (!empty($this->sort_fields)) {
$params['sort'] = $this
->buildSortArray();
}
$this->query_params = $params;
$view->build_info['query'] = var_export($params, TRUE);
}
protected function buildSortArray() {
$sort = array();
foreach ($this->sort_fields as $field => $order) {
$sort[] = array(
$field => $order,
);
}
return $sort;
}
protected function buildFilterArray($where) {
$filter = array();
foreach ($where as $wh) {
foreach ($wh['conditions'] as $cond) {
$filter[drupal_strtolower($wh['type'])][] = $cond['field'];
}
}
if (count($filter) > 1) {
$filter = array(
drupal_strtolower($this->group_operator) => $filter,
);
}
return $filter;
}
public function alter(ViewExecutable $view) {
\Drupal::moduleHandler()
->invokeAll('views_query_alter', array(
$view,
$this,
));
}
public function execute(ViewExecutable $view) {
$view->result = array();
$view->total_rows = 0;
$view->execute_time = 0;
$index = $this
->getIndex();
$type = $this
->getSearchTypes();
try {
$start = microtime(TRUE);
$client = $this->elasticsearchClient;
if ($client) {
$view->execute_time = microtime(TRUE) - $start;
}
$response = $client
->search(array(
'index' => $index,
'type' => $type,
'body' => $this->query_params,
));
if (!empty($response['hits']['hits'])) {
$item_index = 0;
foreach ($response['hits']['hits'] as $doc) {
$result_doc = array();
foreach ($doc['fields'] as $field_name => $field_value) {
$result_doc[$field_name] = implode(' | ', $field_value);
}
$result_doc['_source'] = $doc['_source'];
$result_doc['index'] = $item_index;
$view->result[] = new ResultRow($result_doc);
$item_index++;
}
}
$view->pager->total_items = $view->total_rows = $response['hits']['total'];
$view->pager
->updatePageInfo();
$view->execute_time = $response['took'];
} catch (\Exception $e) {
$this->errors[] = $e
->getMessage();
}
if ($this->errors) {
foreach ($this->errors as $msg) {
drupal_set_message($msg, 'error');
}
$view->result = array();
$view->total_rows = 0;
$view->execute_time = 0;
}
}
public function abort($msg = NULL) {
if ($msg) {
$this->errors[] = $msg;
}
$this->abort = TRUE;
}
public function shouldAbort() {
return $this->abort;
}
public function getAccessAccount() {
return FALSE;
}
public function getSearchApiQuery() {
return $this->query;
}
public function calculateDependencies() {
$dependencies = parent::calculateDependencies();
return $dependencies;
}
public function getIndex() {
return $this->index;
}
public function getClusterId() {
return $this->elasticsearchCluster->cluster_id;
}
public function getSearchTypes() {
return implode(',', $this->elasticsearchTypes);
}
public function getElasticsearchClient() {
return $this->elasticsearchClient;
}
public function addOrderBy($table, $field = NULL, $order = 'ASC', $alias = '', $params = array()) {
}
}