/**
  * {@inheritDoc}
  */
 public function scope(Query $query, TokenInterface $token)
 {
     if ($token->negated()) {
         return $query;
     }
     $value = intval($token->value());
     if ($value > 0) {
         $query->limit($value);
     }
     return $query;
 }
 /**
  * {@inheritDoc}
  */
 public function scope(Query $query, TokenInterface $token)
 {
     $value = $token->value();
     if (empty($value)) {
         return $query;
     }
     return $query->matching('Tags', function ($q) use($value) {
         $value = explode(',', $value);
         $names = array_map('trim', (array) $value);
         return $q->where(['Tags.name IN' => empty($names) ? ['---'] : $names]);
     });
 }
 /**
  * {@inheritDoc}
  */
 public function scope(Query $query, TokenInterface $token)
 {
     $column = $this->config('field');
     $value = $token->value();
     if (!$column || empty($value)) {
         return $query;
     }
     $tableAlias = $this->_table->alias();
     $range = $this->_parseRange($token->value());
     if ($range['lower'] !== $range['upper']) {
         $conjunction = $token->negated() ? 'AND NOT' : 'AND';
         $conditions = ["{$conjunction}" => ["{$tableAlias}.{$column} >=" => $range['lower'], "{$tableAlias}.{$column} <=" => $range['upper']]];
     } else {
         $cmp = $token->negated() ? '<=' : '>=';
         $conditions = ["{$tableAlias}.{$column} {$cmp}" => $range['lower']];
     }
     if ($token->where() === 'or') {
         $query->orWhere($conditions);
     } elseif ($token->where() === 'and') {
         $query->andWhere($conditions);
     } else {
         $query->where($conditions);
     }
     return $query;
 }
 /**
  * {@inheritDoc}
  */
 public function scope(Query $query, TokenInterface $token)
 {
     $fields = $this->config('fields');
     if ($token->negated() || empty($fields)) {
         return $query;
     }
     $tableAlias = $this->_table->alias();
     $fields = $this->config('fields');
     $value = strtolower($token->value());
     if (is_string($fields)) {
         $fields = [$fields];
     }
     foreach (explode(';', $value) as $segment) {
         $parts = explode(',', $segment);
         if (in_array($parts[0], $fields)) {
             $dir = empty($parts[1]) || !in_array($parts[1], ['asc', 'desc']) ? 'asc' : $parts[1];
             $query->order(["{$tableAlias}.{$parts[0]}" => $dir]);
         }
     }
     return $query;
 }
 /**
  * Calculates the conjunction to use and the value to use with such conjunction
  * based on the given token.
  *
  * @param \Search\Parser\TokenInterface $token Token for which calculating the
  *  conjunction
  * @return array Numeric index array, where the first key (0) is the
  *  conjunction, and the second (1) is the value.
  */
 protected function _prepareConjunction(TokenInterface $token)
 {
     $value = $token->value();
     $conjunction = strtolower($this->config('conjunction'));
     if ($conjunction == 'auto') {
         $conjunction = strpos($value, ',') !== false ? 'in' : 'like';
     }
     if ($conjunction == 'in') {
         $value = array_slice(explode(',', $value), 0, $this->config('inSlice'));
         $conjunction = $token->negated() ? 'NOT IN' : 'IN';
     } elseif ($conjunction == 'like') {
         $value = str_replace(['*', '!'], ['%', '_'], $value);
         $conjunction = $token->negated() ? 'NOT LIKE' : 'LIKE';
     } elseif ($conjunction == '=') {
         $conjunction = $token->negated() ? '<>' : '';
     } elseif ($conjunction == '<>') {
         $conjunction = $token->negated() ? '' : '<>';
     }
     return [$conjunction, $value];
 }
 /**
  * Triggers an event for handling undefined operators. Event listeners may
  * capture this event and provide operator handling logic, such listeners should
  * alter the provided Query object and then return it back.
  *
  * The triggered event follows the pattern:
  *
  * ```
  * Search.operator<CamelCaseOperatorName>
  * ```
  *
  * For example, `Search.operatorAuthorName` will be triggered for
  * handling an operator named either `author-name` or `author_name`.
  *
  * @param \Cake\ORM\Query $query The query that is expected to be scoped
  * @param \Search\TokenInterface $token Token describing an operator. e.g
  *  `-op_name:op_value`
  * @return mixed Scoped query object expected or null if event was not captured
  *  by any listener
  */
 protected function _triggerOperator(Query $query, TokenInterface $token)
 {
     $eventName = 'Search.' . (string) Inflector::variable('operator_' . $token->name());
     $event = new Event($eventName, $this->_table, compact('query', 'token'));
     return EventManager::instance()->dispatch($event)->result;
 }
 /**
  * Handles "term" search operator.
  *
  *     term:term1-slug,term2-slug,...
  *
  * @param \Cake\ORM\Query $query The query object
  * @param \Search\Parser\TokenInterface $token Operator token
  * @return \Cake\ORM\Query
  */
 public function operatorterm(Query $query, TokenInterface $token)
 {
     $terms = explode(',', strtolower($token->value()));
     $conjunction = $token->negated() ? 'NOT IN' : 'IN';
     if (empty($terms)) {
         return $query;
     }
     $conditions = ["Contents.id {$conjunction}" => TableRegistry::get('Taxonomy.EntitiesTerms')->find()->select(['EntitiesTerms.entity_id'])->where(['EntitiesTerms.table_alias' => $this->alias()])->matching('Terms', function ($q) use($terms) {
         return $q->where(['Terms.slug IN' => $terms]);
     })];
     if (!empty($conditions)) {
         if ($token->where() === 'or') {
             $query->orWhere($conditions);
         } elseif ($token->where() === 'and') {
             $query->andWhere($conditions);
         } else {
             $query->where($conditions);
         }
     }
     return $query;
 }
 /**
  * Similar to "_scopeWords" but using MySQL's fulltext indexes.
  *
  * @param \Cake\ORM\Query $query The query to scope
  * @param \Search\TokenInterface $token Token describing a words sequence. e.g `this is a phrase`
  * @return \Cake\ORM\Query Scoped query
  */
 protected function _scopeWordsInFulltext(Query $query, TokenInterface $token)
 {
     $value = str_replace(['*', '!'], ['*', '*'], $token->value());
     $value = mb_strpos($value, '+') === 0 ? mb_substr($value, 1) : $value;
     if (empty($value) || in_array($value, $this->_stopWords())) {
         return $query;
     }
     $not = $token->negated() ? 'NOT' : '';
     $value = str_replace("'", '"', $value);
     $conditions = ["{$not} MATCH(SearchDatasets.words) AGAINST('{$value}' IN BOOLEAN MODE) > 0"];
     if ($token->where() === 'or') {
         $query->orWhere($conditions);
     } elseif ($token->where() === 'and') {
         $query->andWhere($conditions);
     } else {
         $query->where($conditions);
     }
     return $query;
 }