From 7ea4f6aff99a2b989798ce459778e96c1cce73c1 Mon Sep 17 00:00:00 2001 From: Greg Brown Date: Sun, 14 Jun 2020 16:29:38 -0700 Subject: [PATCH] v2.0.0 __BREAKING CHANGES__ * Require php `>=7.4` * Uses php7 type hinting throughout with `declare(strict_types=1);` * Uses `"ruflin/elastica": "^7.0"` --- .codeclimate.yml | 18 -- .travis.yml | 3 +- CHANGELOG-2.x.md | 10 ++ README.md | 2 - composer.json | 12 +- src/Builder/AbstractQueryBuilder.php | 228 ++++---------------------- src/Builder/ElasticaQueryBuilder.php | 151 ++++------------- src/Builder/QueryBuilder.php | 46 +++--- src/Builder/XmlQueryBuilder.php | 72 +------- src/Enum/AbstractEnum.php | 157 ++++++++++++++++++ src/Enum/BoolOperator.php | 4 +- src/Enum/ComparisonOperator.php | 4 +- src/Node/Date.php | 59 ++----- src/Node/DateRange.php | 7 - src/Node/Emoji.php | 26 +-- src/Node/Emoticon.php | 26 +-- src/Node/Field.php | 53 +----- src/Node/Hashtag.php | 26 +-- src/Node/Mention.php | 26 +-- src/Node/Node.php | 93 ++--------- src/Node/NumberRange.php | 7 - src/Node/Numbr.php | 35 +--- src/Node/Phrase.php | 32 +--- src/Node/Range.php | 55 +------ src/Node/Subquery.php | 33 +--- src/Node/Url.php | 26 +-- src/Node/Word.php | 52 ++---- src/Node/WordRange.php | 7 - src/ParsedQuery.php | 32 +--- src/QueryParser.php | 123 +++----------- src/Token.php | 32 +--- src/TokenStream.php | 31 +--- src/Tokenizer.php | Bin 19911 -> 19811 bytes tests/Builder/XmlQueryBuilderTest.php | 14 +- tests/QueryParserTest.php | 8 +- tests/TokenizerTest.php | 8 +- 36 files changed, 412 insertions(+), 1106 deletions(-) delete mode 100644 .codeclimate.yml create mode 100644 CHANGELOG-2.x.md create mode 100644 src/Enum/AbstractEnum.php diff --git a/.codeclimate.yml b/.codeclimate.yml deleted file mode 100644 index a4067ef..0000000 --- a/.codeclimate.yml +++ /dev/null @@ -1,18 +0,0 @@ -exclude_paths: - - '/vendor/*' - -engines: - phpcodesniffer: - enabled: true - config: - file_extensions: 'php' - standard: 'PSR1,PSR2' - phpmd: - enabled: true - config: - file_extensions: 'php' - rulesets: 'cleancode,codesize,design,naming,unusedcode' - -ratings: - paths: - - '**.php' diff --git a/.travis.yml b/.travis.yml index b9b08fb..9acee62 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,8 +1,7 @@ language: php php: - - 7.1 - - 7.2 + - 7.4 before_script: - composer self-update diff --git a/CHANGELOG-2.x.md b/CHANGELOG-2.x.md new file mode 100644 index 0000000..b3e598d --- /dev/null +++ b/CHANGELOG-2.x.md @@ -0,0 +1,10 @@ +# CHANGELOG for 2.x +This changelog references the relevant changes done in 2.x versions. + + +## v2.0.0 +__BREAKING CHANGES__ + +* Require php `>=7.4` +* Uses php7 type hinting throughout with `declare(strict_types=1);` +* Uses `"ruflin/elastica": "^7.0"` diff --git a/README.md b/README.md index 4e604a7..e7126f8 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,6 @@ query-parser-php ============= [![Build Status](https://api.travis-ci.org/gdbots/query-parser-php.svg)](https://travis-ci.org/gdbots/query-parser-php) -[![Code Climate](https://codeclimate.com/github/gdbots/query-parser-php/badges/gpa.svg)](https://codeclimate.com/github/gdbots/query-parser-php) -[![Test Coverage](https://codeclimate.com/github/gdbots/query-parser-php/badges/coverage.svg)](https://codeclimate.com/github/gdbots/query-parser-php/coverage) Php library that converts search queries into words, phrases, hashtags, mentions, etc. diff --git a/composer.json b/composer.json index 1518098..4dae53c 100755 --- a/composer.json +++ b/composer.json @@ -5,12 +5,11 @@ "type": "library", "license": "Apache-2.0", "require": { - "php": ">=7.1", - "gdbots/common": "~0.1 || ^1.0" + "php": ">=7.4" }, "require-dev": { - "phpunit/phpunit": "~6.4", - "ruflin/elastica": "~5.3" + "phpunit/phpunit": "^9.2", + "ruflin/elastica": "^7.0" }, "autoload": { "psr-4": { @@ -24,10 +23,5 @@ }, "scripts": { "test": "vendor/bin/phpunit" - }, - "extra": { - "branch-alias": { - "dev-master": "0.3.x-dev" - } } } diff --git a/src/Builder/AbstractQueryBuilder.php b/src/Builder/AbstractQueryBuilder.php index 6767f3e..e430322 100755 --- a/src/Builder/AbstractQueryBuilder.php +++ b/src/Builder/AbstractQueryBuilder.php @@ -21,20 +21,11 @@ abstract class AbstractQueryBuilder implements QueryBuilder { - /** @var Field */ - private $currentField; - - /** @var bool */ - private $queryOnFieldIsCacheable = false; - - /** @var bool */ - private $inField = false; - - /** @var bool */ - private $inRange = false; - - /** @var bool */ - private $inSubquery = false; + private ?Field $currentField = null; + private bool $queryOnFieldIsCacheable = false; + private bool $inField = false; + private bool $inRange = false; + private bool $inSubquery = false; /** * Array of field names which support full text queries. This value is @@ -42,7 +33,8 @@ abstract class AbstractQueryBuilder implements QueryBuilder * * @var array */ - private $fullTextSearchFields = [ + private array $fullTextSearchFields = [ + 'd__all' => true, '_all' => true, 'title' => true, 'tiny_title' => true, @@ -101,133 +93,83 @@ abstract class AbstractQueryBuilder implements QueryBuilder 'ctx_ip_geo.city' => true, ]; - /** @var string */ - protected $defaultFieldName; - - /** @var string */ - protected $emojiFieldName; - - /** @var string */ - protected $emoticonFieldName; - - /** @var string */ - protected $hashtagFieldName; + protected string $defaultFieldName = '_all'; + protected ?string $emojiFieldName = null; + protected ?string $emoticonFieldName = null; + protected ?string $hashtagFieldName = null; + protected ?string $mentionFieldName = null; + protected ?\DateTimeZone $localTimeZone = null; - /** @var string */ - protected $mentionFieldName; - - /** @var \DateTimeZone */ - protected $localTimeZone; - - /** - * {@inheritdoc} - */ - public function clear(): QueryBuilder + public function clear(): self { return $this; } - /** - * {@inheritdoc} - */ - final public function setFullTextSearchFields(array $fields): QueryBuilder + final public function setFullTextSearchFields(array $fields): self { $this->fullTextSearchFields = array_flip($fields); return $this; } - /** - * {@inheritdoc} - */ - final public function addFullTextSearchField(string $fieldName): QueryBuilder + final public function addFullTextSearchField(string $fieldName): self { $this->fullTextSearchFields[$fieldName] = true; return $this; } - /** - * {@inheritdoc} - */ - final public function removeFullTextSearchField(string $fieldName): QueryBuilder + final public function removeFullTextSearchField(string $fieldName): self { unset($this->fullTextSearchFields[$fieldName]); return $this; } - /** - * {@inheritdoc} - */ final public function getFullTextSearchFields(): array { return array_keys($this->fullTextSearchFields); } - /** - * {@inheritdoc} - */ final public function supportsFullTextSearch(string $fieldName): bool { return isset($this->fullTextSearchFields[trim(strtolower($fieldName))]); } - /** - * {@inheritdoc} - */ - final public function setDefaultFieldName(string $fieldName): QueryBuilder + final public function setDefaultFieldName(string $fieldName): self { $this->defaultFieldName = $fieldName; return $this; } - /** - * {@inheritdoc} - */ - final public function setEmojiFieldName(string $fieldName): QueryBuilder + final public function setEmojiFieldName(string $fieldName): self { $this->emojiFieldName = $fieldName; return $this; } - /** - * {@inheritdoc} - */ - final public function setEmoticonFieldName(string $fieldName): QueryBuilder + final public function setEmoticonFieldName(string $fieldName): self { $this->emoticonFieldName = $fieldName; return $this; } - /** - * {@inheritdoc} - */ - final public function setHashtagFieldName(string $fieldName): QueryBuilder + final public function setHashtagFieldName(string $fieldName): self { $this->hashtagFieldName = $fieldName; return $this; } - /** - * {@inheritdoc} - */ - final public function setMentionFieldName(string $fieldName): QueryBuilder + final public function setMentionFieldName(string $fieldName): self { $this->mentionFieldName = $fieldName; return $this; } - /** - * {@inheritdoc} - */ - final public function setLocalTimeZone(\DateTimeZone $timeZone): QueryBuilder + final public function setLocalTimeZone(\DateTimeZone $timeZone): self { $this->localTimeZone = $timeZone; return $this; } - /** - * {@inheritdoc} - */ - final public function addParsedQuery(ParsedQuery $parsedQuery): QueryBuilder + final public function addParsedQuery(ParsedQuery $parsedQuery): self { foreach ($parsedQuery->getNodes() as $node) { $node->acceptBuilder($this); @@ -236,19 +178,13 @@ final public function addParsedQuery(ParsedQuery $parsedQuery): QueryBuilder return $this; } - /** - * {@inheritdoc} - */ - final public function addDate(Date $date): QueryBuilder + final public function addDate(Date $date): self { $this->handleTerm($date); return $this; } - /** - * {@inheritdoc} - */ - final public function addEmoji(Emoji $emoji): QueryBuilder + final public function addEmoji(Emoji $emoji): self { if ($this->inField || null === $this->emojiFieldName) { $this->handleTerm($emoji); @@ -266,10 +202,7 @@ final public function addEmoji(Emoji $emoji): QueryBuilder return $this->addField($field); } - /** - * {@inheritdoc} - */ - final public function addEmoticon(Emoticon $emoticon): QueryBuilder + final public function addEmoticon(Emoticon $emoticon): self { if ($this->inField || null === $this->emoticonFieldName) { $this->handleTerm($emoticon); @@ -287,10 +220,7 @@ final public function addEmoticon(Emoticon $emoticon): QueryBuilder return $this->addField($field); } - /** - * {@inheritdoc} - */ - final public function addField(Field $field): QueryBuilder + final public function addField(Field $field): self { if ($this->inField || $this->inRange) { throw new \LogicException('A Field cannot be nested in another Field or Range.'); @@ -308,10 +238,7 @@ final public function addField(Field $field): QueryBuilder return $this; } - /** - * {@inheritdoc} - */ - final public function addHashtag(Hashtag $hashtag): QueryBuilder + final public function addHashtag(Hashtag $hashtag): self { if ($this->inField || null === $this->hashtagFieldName) { $this->handleTerm($hashtag); @@ -329,10 +256,7 @@ final public function addHashtag(Hashtag $hashtag): QueryBuilder return $this->addField($field); } - /** - * {@inheritdoc} - */ - final public function addMention(Mention $mention): QueryBuilder + final public function addMention(Mention $mention): self { if ($this->inField || null === $this->mentionFieldName) { $this->handleTerm($mention); @@ -350,28 +274,19 @@ final public function addMention(Mention $mention): QueryBuilder return $this->addField($field); } - /** - * {@inheritdoc} - */ - final public function addNumber(Numbr $number): QueryBuilder + final public function addNumber(Numbr $number): self { $this->handleTerm($number); return $this; } - /** - * {@inheritdoc} - */ - final public function addPhrase(Phrase $phrase): QueryBuilder + final public function addPhrase(Phrase $phrase): self { $this->handleText($phrase); return $this; } - /** - * {@inheritdoc} - */ - final public function addRange(Range $range): QueryBuilder + final public function addRange(Range $range): self { if (!$this->inField || $this->inRange || $this->inSubquery) { throw new \LogicException('A Range can only be used within a field. e.g. rating:[1..5]'); @@ -383,10 +298,7 @@ final public function addRange(Range $range): QueryBuilder return $this; } - /** - * {@inheritdoc} - */ - final public function addSubquery(Subquery $subquery): QueryBuilder + final public function addSubquery(Subquery $subquery): self { if ($this->inRange || $this->inSubquery) { throw new \LogicException('A Subquery cannot be nested or within a Range.'); @@ -405,51 +317,33 @@ final public function addSubquery(Subquery $subquery): QueryBuilder return $this; } - /** - * {@inheritdoc} - */ - final public function addUrl(Url $url): QueryBuilder + final public function addUrl(Url $url): self { $this->handleTerm($url); return $this; } - /** - * {@inheritdoc} - */ - final public function addWord(Word $word): QueryBuilder + final public function addWord(Word $word): self { $this->handleText($word); return $this; } - /** - * @return bool - */ final protected function inField(): bool { return $this->inField; } - /** - * @return bool - */ final protected function inRange(): bool { return $this->inRange; } - /** - * @return bool - */ final protected function inSubquery(): bool { return $this->inSubquery; } - /** - * @param Node $node - */ private function handleText(Node $node): void { if ($this->inField && !$this->supportsFullTextSearch($this->currentField->getName())) { @@ -484,9 +378,6 @@ private function handleText(Node $node): void $this->mustNotMatch($node, $this->currentField); } - /** - * @param Node $node - */ private function handleTerm(Node $node): void { /* @@ -548,80 +439,33 @@ protected function queryOnFieldIsCacheable(Field $field): bool return true; } - /** - * @param Field $field - * @param bool $cacheable - */ protected function startField(Field $field, bool $cacheable = false): void { } - /** - * @param Field $field - * @param bool $cacheable - */ protected function endField(Field $field, bool $cacheable = false): void { } - /** - * @param Subquery $subquery - * @param Field $field - */ protected function startSubquery(Subquery $subquery, ?Field $field = null): void { } - /** - * @param Subquery $subquery - * @param Field $field - */ protected function endSubquery(Subquery $subquery, ?Field $field = null): void { } - /** - * @param Range $range - * @param Field $field - * @param bool $cacheable - */ abstract protected function handleRange(Range $range, Field $field, bool $cacheable = false): void; - /** - * @param Node $node - * @param Field $field - */ abstract protected function mustMatch(Node $node, ?Field $field = null): void; - /** - * @param Node $node - * @param Field $field - */ abstract protected function shouldMatch(Node $node, ?Field $field = null): void; - /** - * @param Node $node - * @param Field $field - */ abstract protected function mustNotMatch(Node $node, ?Field $field = null): void; - /** - * @param Node $node - * @param Field $field - * @param bool $cacheable - */ abstract protected function mustMatchTerm(Node $node, ?Field $field = null, bool $cacheable = false): void; - /** - * @param Node $node - * @param Field $field - */ abstract protected function shouldMatchTerm(Node $node, ?Field $field = null): void; - /** - * @param Node $node - * @param Field $field - * @param bool $cacheable - */ abstract protected function mustNotMatchTerm(Node $node, ?Field $field = null, bool $cacheable = false): void; } diff --git a/src/Builder/ElasticaQueryBuilder.php b/src/Builder/ElasticaQueryBuilder.php index 4bbd09e..74cdf44 100755 --- a/src/Builder/ElasticaQueryBuilder.php +++ b/src/Builder/ElasticaQueryBuilder.php @@ -25,11 +25,8 @@ class ElasticaQueryBuilder extends AbstractQueryBuilder { - /** @var RuflinQueryBuilder */ - protected $qb; - - /** @var BoolQuery */ - protected $boolQuery; + protected RuflinQueryBuilder $qb; + protected BoolQuery $boolQuery; /** * When a subquery is entered we'll take the current query @@ -38,19 +35,11 @@ class ElasticaQueryBuilder extends AbstractQueryBuilder * * @var BoolQuery */ - protected $outerBoolQuery; - - /** @var bool */ - protected $ignoreEmojis = true; - - /** @var bool */ - protected $ignoreEmoticons = true; - - /** @var bool */ - protected $ignoreStopWords = true; - - /** @var bool */ - protected $lowerCaseTerms = true; + protected BoolQuery $outerBoolQuery; + protected bool $ignoreEmojis = true; + protected bool $ignoreEmoticons = true; + protected bool $ignoreStopWords = true; + protected bool $lowerCaseTerms = true; /** * Array of field names which are nested objects in ElasticSearch and @@ -60,7 +49,7 @@ class ElasticaQueryBuilder extends AbstractQueryBuilder * * @var string[] */ - protected $nestedFields = []; + protected array $nestedFields = []; /** * Any fields encountered that are nested are stored as a nested query @@ -71,21 +60,16 @@ class ElasticaQueryBuilder extends AbstractQueryBuilder * * @var Nested[] */ - protected $nestedQueries = []; + protected array $nestedQueries = []; - /** - * ElasticaQueryBuilder constructor. - */ public function __construct() { + $this->defaultFieldName = '_all'; $this->qb = new RuflinQueryBuilder(); $this->clear(); } - /** - * {@inheritdoc} - */ - public function clear(): QueryBuilder + public function clear(): self { $this->boolQuery = $this->qb->query()->bool(); $this->outerBoolQuery = $this->boolQuery; @@ -93,94 +77,53 @@ public function clear(): QueryBuilder return $this; } - /** - * @param bool $ignoreEmojis - * - * @return static - */ public function ignoreEmojis(bool $ignoreEmojis = true): self { $this->ignoreEmojis = $ignoreEmojis; return $this; } - /** - * @param bool $ignoreEmoticons - * - * @return static - */ public function ignoreEmoticons(bool $ignoreEmoticons = true): self { $this->ignoreEmoticons = $ignoreEmoticons; return $this; } - /** - * @param bool $ignoreStopWords - * - * @return static - */ public function ignoreStopWords(bool $ignoreStopWords = true): self { $this->ignoreStopWords = $ignoreStopWords; return $this; } - /** - * @param bool $lowerCaseTerms - * - * @return static - */ public function lowerCaseTerms(bool $lowerCaseTerms = true): self { $this->lowerCaseTerms = $lowerCaseTerms; return $this; } - /** - * @param string[] $fields - * - * @return static - */ public function setNestedFields(array $fields): self { $this->nestedFields = array_flip($fields); return $this; } - /** - * @param string $fieldName - * - * @return static - */ public function addNestedField(string $fieldName): self { $this->nestedFields[$fieldName] = true; return $this; } - /** - * @param string $fieldName - * - * @return static - */ public function removeNestedField(string $fieldName): self { unset($this->nestedFields[$fieldName]); return $this; } - /** - * @return array - */ public function getNestedFields(): array { return array_keys($this->nestedFields); } - /** - * @return BoolQuery - */ public function getBoolQuery(): BoolQuery { if ($this->boolQuery->hasParam('must')) { @@ -191,9 +134,6 @@ public function getBoolQuery(): BoolQuery return $this->boolQuery->setMinimumShouldMatch('2<80%'); } - /** - * {@inheritdoc} - */ protected function handleRange(Range $range, Field $field, bool $cacheable = false): void { $useBoost = $field->useBoost(); @@ -256,18 +196,12 @@ protected function handleRange(Range $range, Field $field, bool $cacheable = fal $this->addToBoolQuery($method, $field->getName(), $this->qb->query()->range($field->getName(), $data)); } - /** - * {@inheritdoc} - */ protected function startSubquery(Subquery $subquery, ?Field $field = null): void { $this->outerBoolQuery = $this->boolQuery; $this->boolQuery = $this->qb->query()->bool(); } - /** - * {@inheritdoc} - */ protected function endSubquery(Subquery $subquery, ?Field $field = null): void { $params = $this->boolQuery->getParams(); @@ -300,32 +234,23 @@ protected function endSubquery(Subquery $subquery, ?Field $field = null): void $this->boolQuery = $this->outerBoolQuery; } - /** - * {@inheritdoc} - */ protected function mustMatch(Node $node, ?Field $field = null): void { $this->addTextToQuery('addMust', $node, $field); } - /** - * {@inheritdoc} - */ protected function shouldMatch(Node $node, ?Field $field = null): void { $this->addTextToQuery('addShould', $node, $field); } - /** - * {@inheritdoc} - */ protected function mustNotMatch(Node $node, ?Field $field = null): void { $this->addTextToQuery('addMustNot', $node, $field); } /** - * Adds a text node to the active query. These all use the "match" when full + * Adds a text node to the active query. These all use the "match" when full * text searching is needed/supported. * * @param string $method @@ -365,31 +290,31 @@ protected function addTextToQuery(string $method, Node $node, ?Field $field = nu $fuzzy = 1; } - if ($useFuzzy && $node instanceof Phrase) { - $data = [ - 'query' => $node->getValue(), - 'type' => Phrase::NODE_TYPE, - 'lenient' => true, - 'phrase_slop' => $fuzzy, - ]; + if ($node instanceof Phrase) { + $data = ['query' => $node->getValue()]; if ($useBoost) { $data['boost'] = $boost; } - $query = $this->qb->query()->match(); - $query->setField($fieldName, $data); + if ($useFuzzy) { + $data['slop'] = $fuzzy; + } + + $query = $this->qb->query()->match_phrase($fieldName, $data); } elseif ($useFuzzy) { - $query = $this->qb->query()->fuzzy(); - $query->setField($fieldName, $node->getValue()); + $query = $this->qb->query()->fuzzy($fieldName, $node->getValue()); $query->setFieldOption('fuzziness', $fuzzy); if ($useBoost) { $query->setFieldOption('boost', $boost); } } elseif ($node instanceof Word && $node->hasTrailingWildcard()) { - $query = $this->qb->query()->wildcard(); - $query->setValue($fieldName, strtolower($node->getValue()) . '*', $useBoost ? $boost : Word::DEFAULT_BOOST); + $query = $this->qb->query()->wildcard( + $fieldName, + strtolower($node->getValue()) . '*', + $useBoost ? $boost : Word::DEFAULT_BOOST + ); } else { $data = ['query' => $node->getValue(), 'operator' => 'and', 'lenient' => true]; @@ -397,43 +322,29 @@ protected function addTextToQuery(string $method, Node $node, ?Field $field = nu $data['boost'] = $boost; } - if ($node instanceof Phrase) { - $data['type'] = Phrase::NODE_TYPE; - } - - $query = $this->qb->query()->match(); - $query->setField($fieldName, $data); + $query = $this->qb->query()->match($fieldName, $data); } $this->addToBoolQuery($method, $fieldName, $query); } - /** - * {@inheritdoc} - */ protected function mustMatchTerm(Node $node, ?Field $field = null, bool $cacheable = false): void { $this->addTermToQuery('addMust', $node, $field, $cacheable); } - /** - * {@inheritdoc} - */ protected function shouldMatchTerm(Node $node, ?Field $field = null): void { $this->addTermToQuery('addShould', $node, $field); } - /** - * {@inheritdoc} - */ protected function mustNotMatchTerm(Node $node, ?Field $field = null, bool $cacheable = false): void { $this->addTermToQuery('addMustNot', $node, $field, $cacheable); } /** - * Adds a term to the bool query or filter context. Filter context is used when the + * Adds a term to the bool query or filter context. Filter context is used when the * request for that item could be cached, like documents with hashtag of cats. * * @param string $method @@ -540,11 +451,6 @@ protected function createDateRangeForSingleNode( return $this->qb->query()->range($fieldName, $data); } - /** - * @param string $method - * @param string $fieldName - * @param AbstractQuery $query - */ protected function addToBoolQuery(string $method, string $fieldName, AbstractQuery $query): void { if (false === strpos($fieldName, '.')) { @@ -563,7 +469,8 @@ protected function addToBoolQuery(string $method, string $fieldName, AbstractQue if (!isset($this->nestedQueries[$nestedQuery])) { $this->nestedQueries[$nestedQuery] = (new Nested()) ->setQuery($this->qb->query()->bool()->setMinimumShouldMatch('2<80%')) - ->setPath($nestedPath); + ->setPath($nestedPath) + ->setParam('ignore_unmapped', true); $this->boolQuery->$method($this->nestedQueries[$nestedQuery]); } diff --git a/src/Builder/QueryBuilder.php b/src/Builder/QueryBuilder.php index 3896ce8..e9fd771 100755 --- a/src/Builder/QueryBuilder.php +++ b/src/Builder/QueryBuilder.php @@ -26,7 +26,7 @@ interface QueryBuilder * * @return static */ - public function clear(): QueryBuilder; + public function clear(): self; /** * Sets the fields that this builder will enable for full text search. @@ -35,7 +35,7 @@ public function clear(): QueryBuilder; * * @return static */ - public function setFullTextSearchFields(array $fields): QueryBuilder; + public function setFullTextSearchFields(array $fields): self; /** * Adds a field that this builder will enable for full text search. @@ -44,7 +44,7 @@ public function setFullTextSearchFields(array $fields): QueryBuilder; * * @return static */ - public function addFullTextSearchField(string $fieldName): QueryBuilder; + public function addFullTextSearchField(string $fieldName): self; /** * Removes a field that was previously enabled for full text search. @@ -53,7 +53,7 @@ public function addFullTextSearchField(string $fieldName): QueryBuilder; * * @return static */ - public function removeFullTextSearchField(string $fieldName): QueryBuilder; + public function removeFullTextSearchField(string $fieldName): self; /** * Gets the fields enabled for full text search. @@ -79,70 +79,70 @@ public function supportsFullTextSearch(string $fieldName): bool; * * @return static */ - public function setDefaultFieldName(string $fieldName): QueryBuilder; + public function setDefaultFieldName(string $fieldName): self; /** * @param string $fieldName * * @return static */ - public function setEmojiFieldName(string $fieldName): QueryBuilder; + public function setEmojiFieldName(string $fieldName): self; /** * @param string $fieldName * * @return static */ - public function setEmoticonFieldName(string $fieldName): QueryBuilder; + public function setEmoticonFieldName(string $fieldName): self; /** * @param string $fieldName * * @return static */ - public function setHashtagFieldName(string $fieldName): QueryBuilder; + public function setHashtagFieldName(string $fieldName): self; /** * @param string $fieldName * * @return static */ - public function setMentionFieldName(string $fieldName): QueryBuilder; + public function setMentionFieldName(string $fieldName): self; /** * @param \DateTimeZone $timeZone * * @return static */ - public function setLocalTimeZone(\DateTimeZone $timeZone): QueryBuilder; + public function setLocalTimeZone(\DateTimeZone $timeZone): self; /** * @param ParsedQuery $parsedQuery * * @return static */ - public function addParsedQuery(ParsedQuery $parsedQuery): QueryBuilder; + public function addParsedQuery(ParsedQuery $parsedQuery): self; /** * @param Date $date * * @return static */ - public function addDate(Date $date): QueryBuilder; + public function addDate(Date $date): self; /** * @param Emoji $emoji * * @return static */ - public function addEmoji(Emoji $emoji): QueryBuilder; + public function addEmoji(Emoji $emoji): self; /** * @param Emoticon $emoticon * * @return static */ - public function addEmoticon(Emoticon $emoticon): QueryBuilder; + public function addEmoticon(Emoticon $emoticon): self; /** * @param Field $field @@ -151,35 +151,35 @@ public function addEmoticon(Emoticon $emoticon): QueryBuilder; * * @throws \LogicException */ - public function addField(Field $field): QueryBuilder; + public function addField(Field $field): self; /** * @param Hashtag $hashtag * * @return static */ - public function addHashtag(Hashtag $hashtag): QueryBuilder; + public function addHashtag(Hashtag $hashtag): self; /** * @param Mention $mention * * @return static */ - public function addMention(Mention $mention): QueryBuilder; + public function addMention(Mention $mention): self; /** * @param Numbr $number * * @return static */ - public function addNumber(Numbr $number): QueryBuilder; + public function addNumber(Numbr $number): self; /** * @param Phrase $phrase * * @return static */ - public function addPhrase(Phrase $phrase): QueryBuilder; + public function addPhrase(Phrase $phrase): self; /** * @param Range $range @@ -188,7 +188,7 @@ public function addPhrase(Phrase $phrase): QueryBuilder; * * @throws \LogicException */ - public function addRange(Range $range): QueryBuilder; + public function addRange(Range $range): self; /** * @param Subquery $subquery @@ -197,19 +197,19 @@ public function addRange(Range $range): QueryBuilder; * * @throws \LogicException */ - public function addSubquery(Subquery $subquery): QueryBuilder; + public function addSubquery(Subquery $subquery): self; /** * @param Url $url * * @return static */ - public function addUrl(Url $url): QueryBuilder; + public function addUrl(Url $url): self; /** * @param Word $word * * @return static */ - public function addWord(Word $word): QueryBuilder; + public function addWord(Word $word): self; } diff --git a/src/Builder/XmlQueryBuilder.php b/src/Builder/XmlQueryBuilder.php index 5bae0e4..142bd31 100755 --- a/src/Builder/XmlQueryBuilder.php +++ b/src/Builder/XmlQueryBuilder.php @@ -3,7 +3,6 @@ namespace Gdbots\QueryParser\Builder; -use Gdbots\Common\Util\StringUtils; use Gdbots\QueryParser\Enum\ComparisonOperator; use Gdbots\QueryParser\Node\Date; use Gdbots\QueryParser\Node\Field; @@ -24,38 +23,26 @@ */ class XmlQueryBuilder extends AbstractQueryBuilder { - /** @var string */ - protected $result; + protected string $result = ''; + protected int $indent = 2; - /** @var int */ - protected $indent = 2; - - /** - * {@inheritdoc} - */ - public function clear(): QueryBuilder + public function clear(): self { $this->result = ''; $this->indent = 2; return $this; } - /** - * @return string - */ public function toXmlString(): string { return '' . PHP_EOL . '' . PHP_EOL . rtrim((string)$this->result) . PHP_EOL . ''; } - /** - * @return \SimpleXMLElement - */ public function toSimpleXmlElement(): \SimpleXMLElement { try { $xml = new \SimpleXMLElement($this->toXmlString()); - } catch (\Exception $e) { + } catch (\Throwable $e) { $xml = null; } @@ -66,9 +53,6 @@ public function toSimpleXmlElement(): \SimpleXMLElement return new \SimpleXMLElement(''); } - /** - * {@inheritdoc} - */ protected function startField(Field $field, bool $cacheable = false): void { $tag = sprintf('field name="%s"', $field->getName()); @@ -89,18 +73,12 @@ protected function startField(Field $field, bool $cacheable = false): void $this->indent(); } - /** - * {@inheritdoc} - */ protected function endField(Field $field, bool $cacheable = false): void { $this->outdent(); $this->printLine(''); } - /** - * {@inheritdoc} - */ protected function handleRange(Range $range, Field $field, bool $cacheable = false): void { $this->printLine( @@ -134,9 +112,6 @@ protected function handleRange(Range $range, Field $field, bool $cacheable = fal $this->printLine(''); } - /** - * {@inheritdoc} - */ protected function startSubquery(Subquery $subquery, ?Field $field = null): void { $tag = $subquery::NODE_TYPE; @@ -150,68 +125,42 @@ protected function startSubquery(Subquery $subquery, ?Field $field = null): void $this->indent(); } - /** - * {@inheritdoc} - */ protected function endSubquery(Subquery $subquery, ?Field $field = null): void { $this->outdent(); $this->printLine(''); } - /** - * {@inheritdoc} - */ protected function mustMatch(Node $node, ?Field $field = null): void { $this->printSimpleNode(__FUNCTION__, $node, $field); } - /** - * {@inheritdoc} - */ protected function shouldMatch(Node $node, ?Field $field = null): void { $this->printSimpleNode(__FUNCTION__, $node, $field); } - /** - * {@inheritdoc} - */ protected function mustNotMatch(Node $node, ?Field $field = null): void { $this->printSimpleNode(__FUNCTION__, $node, $field); } - /** - * {@inheritdoc} - */ protected function mustMatchTerm(Node $node, ?Field $field = null, bool $cacheable = false): void { $this->printSimpleNode(__FUNCTION__, $node, $field); } - /** - * {@inheritdoc} - */ protected function shouldMatchTerm(Node $node, ?Field $field = null): void { $this->printSimpleNode(__FUNCTION__, $node, $field); } - /** - * {@inheritdoc} - */ protected function mustNotMatchTerm(Node $node, ?Field $field = null, bool $cacheable = false): void { $this->printSimpleNode(__FUNCTION__, $node, $field); } - /** - * @param string $rule - * @param Node $node - * @param Field $field - */ protected function printSimpleNode(string $rule, Node $node, ?Field $field = null): void { if ($this->inRange()) { @@ -235,7 +184,8 @@ protected function printSimpleNode(string $rule, Node $node, ?Field $field = nul } } - $tag .= sprintf(' rule="%s"', StringUtils::toSnakeFromCamel($rule)); + $snaked = trim(strtolower(preg_replace('/([A-Z])/', '_$1', $rule)), '_'); + $tag .= sprintf(' rule="%s"', $snaked); if ($node instanceof Numbr || $node instanceof Date) { switch ($node->getComparisonOperator()->getValue()) { @@ -273,26 +223,16 @@ protected function printSimpleNode(string $rule, Node $node, ?Field $field = nul $this->printLine(sprintf('<%s>%s', $tag, $value, $node::NODE_TYPE)); } - /** - * @param string $line - * @param bool $newLine - */ protected function printLine(string $line, bool $newLine = true): void { $this->result .= str_repeat(' ', $this->indent) . $line . ($newLine ? PHP_EOL : ''); } - /** - * @param int $step - */ protected function indent(int $step = 2): void { $this->indent += $step; } - /** - * @param int $step - */ protected function outdent(int $step = 2): void { $this->indent -= $step; diff --git a/src/Enum/AbstractEnum.php b/src/Enum/AbstractEnum.php new file mode 100644 index 0000000..7ec84fd --- /dev/null +++ b/src/Enum/AbstractEnum.php @@ -0,0 +1,157 @@ +value = $value; + } + + /** + * @param string|int $value + * + * @return static + * @throws \UnexpectedValueException + */ + final public static function create($value): self + { + $key = static::class . $value; + + if (isset(self::$instances[$key])) { + return self::$instances[$key]; + } + + $values = static::values(); + if (!in_array($value, $values)) { + throw new \UnexpectedValueException("Value '$value' is not part of the enum " . static::class); + } + + self::$instances[$key] = new static($value); + return self::$instances[$key]; + } + + /** + * Returns the name/key of the constant this enum value matches. Note that this + * may not return the exact constant name you'd expect if you have multiple + * constants that share the same value. + * + * @return string + */ + final public function getName(): string + { + return array_flip(static::values())[$this->value]; + } + + /** + * @return int|string + */ + final public function getValue() + { + return $this->value; + } + + final public function __toString() + { + return (string)$this->value; + } + + final public function jsonSerialize() + { + return $this->value; + } + + /** + * Returns the names (or keys) of all of constants in the enum + * + * @return string[] + */ + final public static function keys(): array + { + return array_keys(static::values()); + } + + /** + * Return the names and values of all the constants in the enum + * + * @return array + */ + final public static function values(): array + { + $class = static::class; + + if (!isset(self::$values[$class])) { + self::$values[$class] = (new \ReflectionClass($class))->getConstants(); + } + + return self::$values[$class]; + } + + /** + * Compares this enum (which has a value) to the value provided. If the value + * is itself an Enum then we'll get the value of the provided enum and compare + * it to our value. + * + * @param self|int|string $value + * + * @return bool + */ + final public function equals($value): bool + { + if ($value instanceof AbstractEnum) { + return $this->value == $value->getValue(); + } + + return $this->value == $value; + } + + /** + * Returns a value when called statically like so: MyEnum::SOME_VALUE() given SOME_VALUE is a class constant + * + * @param string $name + * @param array $arguments + * + * @return static + * @throws \BadMethodCallException + */ + final public static function __callStatic($name, $arguments) + { + if (defined("static::$name")) { + return static::create(constant("static::$name")); + } + + throw new \BadMethodCallException("No static method or enum constant '$name' in class " . static::class); + } +} diff --git a/src/Enum/BoolOperator.php b/src/Enum/BoolOperator.php index bdf983a..aa42681 100644 --- a/src/Enum/BoolOperator.php +++ b/src/Enum/BoolOperator.php @@ -3,14 +3,12 @@ namespace Gdbots\QueryParser\Enum; -use Gdbots\Common\Enum; - /** * @method static BoolOperator OPTIONAL() * @method static BoolOperator REQUIRED() * @method static BoolOperator PROHIBITED() */ -final class BoolOperator extends Enum +final class BoolOperator extends AbstractEnum { const OPTIONAL = 0; const REQUIRED = 1; diff --git a/src/Enum/ComparisonOperator.php b/src/Enum/ComparisonOperator.php index ae4e1ca..a114e45 100644 --- a/src/Enum/ComparisonOperator.php +++ b/src/Enum/ComparisonOperator.php @@ -3,8 +3,6 @@ namespace Gdbots\QueryParser\Enum; -use Gdbots\Common\Enum; - /** * @method static ComparisonOperator EQ() * @method static ComparisonOperator GT() @@ -12,7 +10,7 @@ * @method static ComparisonOperator LT() * @method static ComparisonOperator LTE() */ -final class ComparisonOperator extends Enum +final class ComparisonOperator extends AbstractEnum { const EQ = 'eq'; const GT = 'gt'; diff --git a/src/Node/Date.php b/src/Node/Date.php index 93d393f..3c6fc45 100755 --- a/src/Node/Date.php +++ b/src/Node/Date.php @@ -17,23 +17,9 @@ final class Date extends Node const MAX_FUZZY = 5; */ - /** @var \DateTimeZone */ - private static $utc; + private static ?\DateTimeZone $utc = null; + private ComparisonOperator $comparisonOperator; - /** @var ComparisonOperator */ - private $comparisonOperator; - - /** - * Date constructor. - * - * @param string $value - * @param BoolOperator $boolOperator - * @param bool $useBoost - * @param float $boost - * @param bool $useFuzzy - * @param int $fuzzy - * @param ComparisonOperator $comparisonOperator - */ public function __construct( string $value, ?BoolOperator $boolOperator = null, @@ -47,38 +33,30 @@ public function __construct( $this->comparisonOperator = $comparisonOperator ?: ComparisonOperator::EQ(); } - /** - * @param array $data - * - * @return self - */ - public static function fromArray(array $data = []) + public static function fromArray(array $data = []): self { - $value = isset($data['value']) ? $data['value'] : ''; - $useBoost = isset($data['use_boost']) ? (bool)$data['use_boost'] : false; - $boost = isset($data['boost']) ? (float)$data['boost'] : self::DEFAULT_BOOST; - $useFuzzy = isset($data['use_fuzzy']) ? (bool)$data['use_fuzzy'] : false; - $fuzzy = isset($data['fuzzy']) ? (int)$data['fuzzy'] : self::DEFAULT_FUZZY; + $value = $data['value'] ?? ''; + $useBoost = (bool)($data['use_boost'] ?? false); + $boost = (float)($data['boost'] ?? self::DEFAULT_BOOST); + $useFuzzy = (bool)($data['use_fuzzy'] ?? false); + $fuzzy = (int)($data['fuzzy'] ?? self::DEFAULT_FUZZY); try { $boolOperator = isset($data['bool_operator']) ? BoolOperator::create($data['bool_operator']) : null; - } catch (\Exception $e) { + } catch (\Throwable $e) { $boolOperator = null; } try { $comparisonOperator = isset($data['comparison_operator']) ? ComparisonOperator::create($data['comparison_operator']) : null; - } catch (\Exception $e) { + } catch (\Throwable $e) { $comparisonOperator = null; } return new self($value, $boolOperator, $useBoost, $boost, $useFuzzy, $fuzzy, $comparisonOperator); } - /** - * @return array - */ - public function toArray() + public function toArray(): array { $array = parent::toArray(); if ($this->comparisonOperator->equals(ComparisonOperator::EQ())) { @@ -89,17 +67,11 @@ public function toArray() return $array; } - /** - * @return bool - */ public function useComparisonOperator(): bool { return !$this->comparisonOperator->equals(ComparisonOperator::EQ()); } - /** - * @return ComparisonOperator - */ public function getComparisonOperator(): ComparisonOperator { return $this->comparisonOperator; @@ -111,16 +83,16 @@ public function getComparisonOperator(): ComparisonOperator * * @param \DateTimeZone $timeZone * - * @return \DateTime + * @return \DateTimeInterface */ - public function toDateTime(\DateTimeZone $timeZone = null): \DateTime + public function toDateTime(?\DateTimeZone $timeZone = null): \DateTimeInterface { if (null === self::$utc) { self::$utc = new \DateTimeZone('UTC'); } $date = \DateTime::createFromFormat('!Y-m-d', $this->getValue(), $timeZone ?: self::$utc); - if (!$date instanceof \DateTime) { + if (!$date instanceof \DateTimeInterface) { $date = \DateTime::createFromFormat('!Y-m-d', (new \DateTime())->format('Y-m-d'), $timeZone ?: self::$utc); } @@ -131,9 +103,6 @@ public function toDateTime(\DateTimeZone $timeZone = null): \DateTime return $date; } - /** - * @param QueryBuilder $builder - */ public function acceptBuilder(QueryBuilder $builder): void { $builder->addDate($this); diff --git a/src/Node/DateRange.php b/src/Node/DateRange.php index 6183642..892bdf4 100755 --- a/src/Node/DateRange.php +++ b/src/Node/DateRange.php @@ -8,13 +8,6 @@ final class DateRange extends Range const NODE_TYPE = 'date_range'; const COMPOUND_NODE = true; - /** - * DateRange constructor. - * - * @param Date $lowerNode - * @param Date $upperNode - * @param bool $exclusive - */ public function __construct(?Date $lowerNode = null, ?Date $upperNode = null, bool $exclusive = false) { parent::__construct($lowerNode, $upperNode, $exclusive); diff --git a/src/Node/Emoji.php b/src/Node/Emoji.php index 3efb280..918e97e 100755 --- a/src/Node/Emoji.php +++ b/src/Node/Emoji.php @@ -10,14 +10,6 @@ final class Emoji extends Node { const NODE_TYPE = 'emoji'; - /** - * Emoji constructor. - * - * @param string $value - * @param BoolOperator $boolOperator - * @param bool $useBoost - * @param float $boost - */ public function __construct( string $value, ?BoolOperator $boolOperator = null, @@ -27,29 +19,21 @@ public function __construct( parent::__construct($value, $boolOperator, $useBoost, $boost); } - /** - * @param array $data - * - * @return self - */ - public static function fromArray(array $data = []) + public static function fromArray(array $data = []): self { - $value = isset($data['value']) ? $data['value'] : ''; - $useBoost = isset($data['use_boost']) ? (bool)$data['use_boost'] : false; - $boost = isset($data['boost']) ? (float)$data['boost'] : self::DEFAULT_BOOST; + $value = $data['value'] ?? ''; + $useBoost = (bool)($data['use_boost'] ?? false); + $boost = (float)($data['boost'] ?? self::DEFAULT_BOOST); try { $boolOperator = isset($data['bool_operator']) ? BoolOperator::create($data['bool_operator']) : null; - } catch (\Exception $e) { + } catch (\Throwable $e) { $boolOperator = null; } return new self($value, $boolOperator, $useBoost, $boost); } - /** - * @param QueryBuilder $builder - */ public function acceptBuilder(QueryBuilder $builder): void { $builder->addEmoji($this); diff --git a/src/Node/Emoticon.php b/src/Node/Emoticon.php index 767c17c..5c84ca2 100755 --- a/src/Node/Emoticon.php +++ b/src/Node/Emoticon.php @@ -10,14 +10,6 @@ final class Emoticon extends Node { const NODE_TYPE = 'emoticon'; - /** - * Emoticon constructor. - * - * @param string $value - * @param BoolOperator $boolOperator - * @param bool $useBoost - * @param float $boost - */ public function __construct( string $value, ?BoolOperator $boolOperator = null, @@ -27,29 +19,21 @@ public function __construct( parent::__construct($value, $boolOperator, $useBoost, $boost); } - /** - * @param array $data - * - * @return self - */ - public static function fromArray(array $data = []) + public static function fromArray(array $data = []): self { - $value = isset($data['value']) ? $data['value'] : ''; - $useBoost = isset($data['use_boost']) ? (bool)$data['use_boost'] : false; - $boost = isset($data['boost']) ? (float)$data['boost'] : self::DEFAULT_BOOST; + $value = $data['value'] ?? ''; + $useBoost = (bool)($data['use_boost'] ?? false); + $boost = (float)($data['boost'] ?? self::DEFAULT_BOOST); try { $boolOperator = isset($data['bool_operator']) ? BoolOperator::create($data['bool_operator']) : null; - } catch (\Exception $e) { + } catch (\Throwable $e) { $boolOperator = null; } return new self($value, $boolOperator, $useBoost, $boost); } - /** - * @param QueryBuilder $builder - */ public function acceptBuilder(QueryBuilder $builder): void { $builder->addEmoticon($this); diff --git a/src/Node/Field.php b/src/Node/Field.php index 7b3da4d..b15476d 100755 --- a/src/Node/Field.php +++ b/src/Node/Field.php @@ -17,22 +17,9 @@ final class Field extends Node * * @var array */ - public static $aliases = []; + public static array $aliases = []; + private Node $node; - /** @var Node */ - private $node; - - /** - * Field constructor. - * - * @param string $fieldName - * @param Node $node - * @param BoolOperator $boolOperator - * @param bool $useBoost - * @param float $boost - * - * @throws \LogicException - */ public function __construct( string $fieldName, Node $node, @@ -52,20 +39,15 @@ public function __construct( } } - /** - * @param array $data - * - * @return static - */ - public static function fromArray(array $data = []) + public static function fromArray(array $data = []): self { - $value = isset($data['value']) ? $data['value'] : ''; - $useBoost = isset($data['use_boost']) ? (bool)$data['use_boost'] : false; - $boost = isset($data['boost']) ? (float)$data['boost'] : self::DEFAULT_BOOST; + $value = $data['value'] ?? ''; + $useBoost = (bool)($data['use_boost'] ?? false); + $boost = (float)($data['boost'] ?? self::DEFAULT_BOOST); try { $boolOperator = isset($data['bool_operator']) ? BoolOperator::create($data['bool_operator']) : null; - } catch (\Exception $e) { + } catch (\Throwable $e) { $boolOperator = null; } @@ -75,45 +57,28 @@ public static function fromArray(array $data = []) return new self($value, $node, $boolOperator, $useBoost, $boost); } - /** - * @return array - */ - public function toArray() + public function toArray(): array { $array = parent::toArray(); $array['node'] = $this->node->toArray(); return $array; } - /** - * @return string - */ public function getName(): string { - /** @var string $name */ - $name = $this->getValue(); - return $name; + return $this->getValue(); } - /** - * @return Node - */ public function getNode(): Node { return $this->node; } - /** - * @return bool - */ public function hasCompoundNode(): bool { return $this->node->isCompoundNode(); } - /** - * @param QueryBuilder $builder - */ public function acceptBuilder(QueryBuilder $builder): void { $builder->addField($this); diff --git a/src/Node/Hashtag.php b/src/Node/Hashtag.php index 4ebfd76..23c5192 100755 --- a/src/Node/Hashtag.php +++ b/src/Node/Hashtag.php @@ -10,14 +10,6 @@ final class Hashtag extends Node { const NODE_TYPE = 'hashtag'; - /** - * Hashtag constructor. - * - * @param string $value - * @param BoolOperator $boolOperator - * @param bool $useBoost - * @param float $boost - */ public function __construct( string $value, ?BoolOperator $boolOperator = null, @@ -27,29 +19,21 @@ public function __construct( parent::__construct($value, $boolOperator, $useBoost, $boost); } - /** - * @param array $data - * - * @return self - */ - public static function fromArray(array $data = []) + public static function fromArray(array $data = []): self { - $value = isset($data['value']) ? $data['value'] : ''; - $useBoost = isset($data['use_boost']) ? (bool)$data['use_boost'] : false; - $boost = isset($data['boost']) ? (float)$data['boost'] : self::DEFAULT_BOOST; + $value = $data['value'] ?? ''; + $useBoost = (bool)($data['use_boost'] ?? false); + $boost = (float)($data['boost'] ?? self::DEFAULT_BOOST); try { $boolOperator = isset($data['bool_operator']) ? BoolOperator::create($data['bool_operator']) : null; - } catch (\Exception $e) { + } catch (\Throwable $e) { $boolOperator = null; } return new self($value, $boolOperator, $useBoost, $boost); } - /** - * @param QueryBuilder $builder - */ public function acceptBuilder(QueryBuilder $builder): void { $builder->addHashtag($this); diff --git a/src/Node/Mention.php b/src/Node/Mention.php index 8b35a58..82b5cda 100755 --- a/src/Node/Mention.php +++ b/src/Node/Mention.php @@ -10,14 +10,6 @@ final class Mention extends Node { const NODE_TYPE = 'mention'; - /** - * Mention constructor. - * - * @param string $value - * @param BoolOperator $boolOperator - * @param bool $useBoost - * @param float $boost - */ public function __construct( string $value, ?BoolOperator $boolOperator = null, @@ -27,29 +19,21 @@ public function __construct( parent::__construct($value, $boolOperator, $useBoost, $boost); } - /** - * @param array $data - * - * @return self - */ - public static function fromArray(array $data = []) + public static function fromArray(array $data = []): self { - $value = isset($data['value']) ? $data['value'] : ''; - $useBoost = isset($data['use_boost']) ? (bool)$data['use_boost'] : false; - $boost = isset($data['boost']) ? (float)$data['boost'] : self::DEFAULT_BOOST; + $value = $data['value'] ?? ''; + $useBoost = (bool)($data['use_boost'] ?? false); + $boost = (float)($data['boost'] ?? self::DEFAULT_BOOST); try { $boolOperator = isset($data['bool_operator']) ? BoolOperator::create($data['bool_operator']) : null; - } catch (\Exception $e) { + } catch (\Throwable $e) { $boolOperator = null; } return new self($value, $boolOperator, $useBoost, $boost); } - /** - * @param QueryBuilder $builder - */ public function acceptBuilder(QueryBuilder $builder): void { $builder->addMention($this); diff --git a/src/Node/Node.php b/src/Node/Node.php index e99c0e9..b14595b 100755 --- a/src/Node/Node.php +++ b/src/Node/Node.php @@ -3,14 +3,10 @@ namespace Gdbots\QueryParser\Node; -use Gdbots\Common\FromArray; -use Gdbots\Common\ToArray; -use Gdbots\Common\Util\NumberUtils; -use Gdbots\Common\Util\StringUtils; use Gdbots\QueryParser\Builder\QueryBuilder; use Gdbots\QueryParser\Enum\BoolOperator; -abstract class Node implements FromArray, ToArray, \JsonSerializable +abstract class Node implements \JsonSerializable { const NODE_TYPE = 'node'; const COMPOUND_NODE = false; @@ -30,31 +26,12 @@ abstract class Node implements FromArray, ToArray, \JsonSerializable /** @var mixed */ private $value = null; - /** @var BoolOperator */ - private $boolOperator; + private BoolOperator $boolOperator; + private bool $useBoost = false; + private float $boost = self::DEFAULT_BOOST; + private bool $useFuzzy = false; + private int $fuzzy = self::DEFAULT_FUZZY; - /** @var bool */ - private $useBoost = false; - - /** @var float */ - private $boost = self::DEFAULT_BOOST; - - /** @var bool */ - private $useFuzzy = false; - - /** @var int */ - private $fuzzy = self::DEFAULT_FUZZY; - - /** - * Node constructor. - * - * @param mixed $value - * @param BoolOperator $boolOperator - * @param bool $useBoost - * @param float $boost - * @param bool $useFuzzy - * @param int $fuzzy - */ public function __construct( $value, ?BoolOperator $boolOperator = null, @@ -80,16 +57,10 @@ public function __construct( $this->useFuzzy = $useFuzzy && static::SUPPORTS_FUZZY && $this->boolOperator === BoolOperator::OPTIONAL(); if ($this->useFuzzy) { - $this->fuzzy = NumberUtils::bound($fuzzy, static::MIN_FUZZY, static::MAX_FUZZY); + $this->fuzzy = min(max($fuzzy, static::MIN_FUZZY), static::MAX_FUZZY); } } - /** - * @param array $data - * - * @return static - * @throws \InvalidArgumentException - */ public static function factory(array $data = []): self { $type = $data['type']; @@ -99,7 +70,8 @@ public static function factory(array $data = []): self } /** @var Node $class */ - $class = 'Gdbots\QueryParser\Node\\' . StringUtils::toCamelFromSnake($type); + $camel = str_replace(' ', '', ucwords(str_replace('_', ' ', $type))); + $class = 'Gdbots\QueryParser\Node\\' . $camel; if (!class_exists($class)) { throw new \InvalidArgumentException(sprintf('Node type [%s] does not exist.', $type)); } @@ -107,10 +79,7 @@ public static function factory(array $data = []): self return $class::fromArray($data); } - /** - * @return array - */ - public function toArray() + public function toArray(): array { $array = ['type' => static::NODE_TYPE]; @@ -135,113 +104,71 @@ public function toArray() return $array; } - /** - * @return array - */ final public function jsonSerialize() { return $this->toArray(); } - /** - * @return bool - */ final public function hasValue(): bool { return null !== $this->value && '' !== $this->value; } - /** - * @return mixed - */ final public function getValue() { return $this->value; } - /** - * @return BoolOperator - */ final public function getBoolOperator(): BoolOperator { return $this->boolOperator; } - /** - * @return bool - */ final public function isOptional(): bool { return $this->boolOperator->equals(BoolOperator::OPTIONAL()); } - /** - * @return bool - */ final public function isRequired(): bool { return $this->boolOperator->equals(BoolOperator::REQUIRED()); } - /** - * @return bool - */ final public function isProhibited(): bool { return $this->boolOperator->equals(BoolOperator::PROHIBITED()); } - /** - * @return bool - */ final public function isCompoundNode(): bool { return static::COMPOUND_NODE; } - /** - * @return bool - */ public function useComparisonOperator(): bool { return false; } - /** - * @return bool - */ final public function useBoost(): bool { return $this->useBoost; } - /** - * @return float - */ final public function getBoost(): float { return $this->boost; } - /** - * @return bool - */ final public function useFuzzy(): bool { return $this->useFuzzy; } - /** - * @return int - */ final public function getFuzzy(): int { return $this->fuzzy; } - /** - * @param QueryBuilder $builder - */ public function acceptBuilder(QueryBuilder $builder): void { // do nothing diff --git a/src/Node/NumberRange.php b/src/Node/NumberRange.php index c4543c2..48e238a 100755 --- a/src/Node/NumberRange.php +++ b/src/Node/NumberRange.php @@ -8,13 +8,6 @@ final class NumberRange extends Range const NODE_TYPE = 'number_range'; const COMPOUND_NODE = true; - /** - * NumberRange constructor. - * - * @param Numbr $lowerNode - * @param Numbr $upperNode - * @param bool $exclusive - */ public function __construct(?Numbr $lowerNode = null, ?Numbr $upperNode = null, bool $exclusive = false) { parent::__construct($lowerNode, $upperNode, $exclusive); diff --git a/src/Node/Numbr.php b/src/Node/Numbr.php index 5c5fe52..2c37df9 100755 --- a/src/Node/Numbr.php +++ b/src/Node/Numbr.php @@ -12,44 +12,28 @@ final class Numbr extends Node { const NODE_TYPE = 'number'; + private ComparisonOperator $comparisonOperator; - /** @var ComparisonOperator */ - private $comparisonOperator; - - /** - * Numbr constructor. - * - * @param float $value - * @param ComparisonOperator $comparisonOperator - */ public function __construct(float $value, ?ComparisonOperator $comparisonOperator = null) { parent::__construct($value, null); $this->comparisonOperator = $comparisonOperator ?: ComparisonOperator::EQ(); } - /** - * @param array $data - * - * @return self - */ - public static function fromArray(array $data = []) + public static function fromArray(array $data = []): self { - $value = isset($data['value']) ? (float)$data['value'] : 0.0; + $value = (float)($data['value'] ?? 0.0); try { $comparisonOperator = isset($data['comparison_operator']) ? ComparisonOperator::create($data['comparison_operator']) : null; - } catch (\Exception $e) { + } catch (\Throwable $e) { $comparisonOperator = null; } return new self($value, $comparisonOperator); } - /** - * @return array - */ - public function toArray() + public function toArray(): array { $array = parent::toArray(); if ($this->comparisonOperator->equals(ComparisonOperator::EQ())) { @@ -60,25 +44,16 @@ public function toArray() return $array; } - /** - * @return bool - */ public function useComparisonOperator(): bool { return !$this->comparisonOperator->equals(ComparisonOperator::EQ()); } - /** - * @return ComparisonOperator - */ public function getComparisonOperator(): ComparisonOperator { return $this->comparisonOperator; } - /** - * @param QueryBuilder $builder - */ public function acceptBuilder(QueryBuilder $builder): void { $builder->addNumber($this); diff --git a/src/Node/Phrase.php b/src/Node/Phrase.php index d7620e7..c836691 100755 --- a/src/Node/Phrase.php +++ b/src/Node/Phrase.php @@ -11,16 +11,6 @@ final class Phrase extends Node const NODE_TYPE = 'phrase'; const SUPPORTS_FUZZY = true; - /** - * Phrase constructor. - * - * @param string $value - * @param BoolOperator $boolOperator - * @param bool $useBoost - * @param float $boost - * @param bool $useFuzzy - * @param int $fuzzy - */ public function __construct( string $value, ?BoolOperator $boolOperator = null, @@ -32,31 +22,23 @@ public function __construct( parent::__construct($value, $boolOperator, $useBoost, $boost, $useFuzzy, $fuzzy); } - /** - * @param array $data - * - * @return static - */ - public static function fromArray(array $data = []) + public static function fromArray(array $data = []): self { - $value = isset($data['value']) ? $data['value'] : ''; - $useBoost = isset($data['use_boost']) ? (bool)$data['use_boost'] : false; - $boost = isset($data['boost']) ? (float)$data['boost'] : static::DEFAULT_BOOST; - $useFuzzy = isset($data['use_fuzzy']) ? (bool)$data['use_fuzzy'] : false; - $fuzzy = isset($data['fuzzy']) ? (int)$data['fuzzy'] : static::DEFAULT_FUZZY; + $value = $data['value'] ?? ''; + $useBoost = (bool)($data['use_boost'] ?? false); + $boost = (float)($data['boost'] ?? self::DEFAULT_BOOST); + $useFuzzy = (bool)($data['use_fuzzy'] ?? false); + $fuzzy = (int)($data['fuzzy'] ?? self::DEFAULT_FUZZY); try { $boolOperator = isset($data['bool_operator']) ? BoolOperator::create($data['bool_operator']) : null; - } catch (\Exception $e) { + } catch (\Throwable $e) { $boolOperator = null; } return new self($value, $boolOperator, $useBoost, $boost, $useFuzzy, $fuzzy); } - /** - * @param QueryBuilder $builder - */ public function acceptBuilder(QueryBuilder $builder): void { $builder->addPhrase($this); diff --git a/src/Node/Range.php b/src/Node/Range.php index b9964f0..b7d34b1 100755 --- a/src/Node/Range.php +++ b/src/Node/Range.php @@ -10,24 +10,10 @@ abstract class Range extends Node const SUPPORTS_BOOST = false; const COMPOUND_NODE = true; - /** @var Node */ - private $lowerNode; - - /** @var Node */ - private $upperNode; - - /** @var bool */ - private $exclusive = false; - - /** - * Range constructor. - * - * @param Node $lowerNode - * @param Node $upperNode - * @param bool $exclusive - * - * @throws \LogicException - */ + private ?Node $lowerNode = null; + private ?Node $upperNode = null; + private bool $exclusive = false; + public function __construct(?Node $lowerNode = null, ?Node $upperNode = null, bool $exclusive = false) { parent::__construct(null); @@ -40,12 +26,7 @@ public function __construct(?Node $lowerNode = null, ?Node $upperNode = null, bo } } - /** - * @param array $data - * - * @return self - */ - final public static function fromArray(array $data = []) + final public static function fromArray(array $data = []): self { $lowerNode = isset($data['lower_node']) ? self::factory($data['lower_node']) : null; $upperNode = isset($data['upper_node']) ? self::factory($data['upper_node']) : null; @@ -53,10 +34,7 @@ final public static function fromArray(array $data = []) return new static($lowerNode, $upperNode, $exclusive); } - /** - * @return array - */ - final public function toArray() + final public function toArray(): array { $array = parent::toArray(); @@ -75,57 +53,36 @@ final public function toArray() return $array; } - /** - * @return bool - */ final public function hasLowerNode(): bool { return null !== $this->lowerNode; } - /** - * @return Node - */ public function getLowerNode(): ?Node { return $this->lowerNode; } - /** - * @return bool - */ final public function hasUpperNode(): bool { return null !== $this->upperNode; } - /** - * @return Node - */ public function getUpperNode(): ?Node { return $this->upperNode; } - /** - * @return bool - */ final public function isInclusive(): bool { return !$this->exclusive; } - /** - * @return bool - */ final public function isExclusive(): bool { return $this->exclusive; } - /** - * @param QueryBuilder $builder - */ final public function acceptBuilder(QueryBuilder $builder): void { $builder->addRange($this); diff --git a/src/Node/Subquery.php b/src/Node/Subquery.php index ef48c95..16e212a 100755 --- a/src/Node/Subquery.php +++ b/src/Node/Subquery.php @@ -12,18 +12,8 @@ final class Subquery extends Node const COMPOUND_NODE = true; /** @var Node[] */ - private $nodes = []; + private array $nodes = []; - /** - * Subquery constructor. - * - * @param Node[] $nodes - * @param BoolOperator $boolOperator - * @param bool $useBoost - * @param float $boost - * - * @throws \LogicException - */ public function __construct( array $nodes, ?BoolOperator $boolOperator = null, @@ -40,15 +30,10 @@ public function __construct( } } - /** - * @param array $data - * - * @return self - */ - public static function fromArray(array $data = []) + public static function fromArray(array $data = []): self { - $useBoost = isset($data['use_boost']) ? (bool)$data['use_boost'] : false; - $boost = isset($data['boost']) ? (float)$data['boost'] : self::DEFAULT_BOOST; + $useBoost = (bool)($data['use_boost'] ?? false); + $boost = (float)($data['boost'] ?? self::DEFAULT_BOOST); $nodes = []; if (isset($data['nodes'])) { @@ -59,17 +44,14 @@ public static function fromArray(array $data = []) try { $boolOperator = isset($data['bool_operator']) ? BoolOperator::create($data['bool_operator']) : null; - } catch (\Exception $e) { + } catch (\Throwable $e) { $boolOperator = null; } return new self($nodes, $boolOperator, $useBoost, $boost); } - /** - * @return array - */ - public function toArray() + public function toArray(): array { $array = parent::toArray(); $array['nodes'] = []; @@ -89,9 +71,6 @@ public function getNodes(): array return $this->nodes; } - /** - * @param QueryBuilder $builder - */ public function acceptBuilder(QueryBuilder $builder): void { $builder->addSubquery($this); diff --git a/src/Node/Url.php b/src/Node/Url.php index e31ee6f..574e50c 100755 --- a/src/Node/Url.php +++ b/src/Node/Url.php @@ -10,14 +10,6 @@ final class Url extends Node { const NODE_TYPE = 'url'; - /** - * Url constructor. - * - * @param string $value - * @param BoolOperator $boolOperator - * @param bool $useBoost - * @param float $boost - */ public function __construct( string $value, ?BoolOperator $boolOperator = null, @@ -27,29 +19,21 @@ public function __construct( parent::__construct($value, $boolOperator, $useBoost, $boost); } - /** - * @param array $data - * - * @return self - */ - public static function fromArray(array $data = []) + public static function fromArray(array $data = []): self { - $value = isset($data['value']) ? $data['value'] : ''; - $useBoost = isset($data['use_boost']) ? (bool)$data['use_boost'] : false; - $boost = isset($data['boost']) ? (float)$data['boost'] : self::DEFAULT_BOOST; + $value = $data['value'] ?? ''; + $useBoost = (bool)($data['use_boost'] ?? false); + $boost = (float)($data['boost'] ?? self::DEFAULT_BOOST); try { $boolOperator = isset($data['bool_operator']) ? BoolOperator::create($data['bool_operator']) : null; - } catch (\Exception $e) { + } catch (\Throwable $e) { $boolOperator = null; } return new self($value, $boolOperator, $useBoost, $boost); } - /** - * @param QueryBuilder $builder - */ public function acceptBuilder(QueryBuilder $builder): void { $builder->addUrl($this); diff --git a/src/Node/Word.php b/src/Node/Word.php index 3df27c4..f17c771 100755 --- a/src/Node/Word.php +++ b/src/Node/Word.php @@ -11,27 +11,14 @@ final class Word extends Node const NODE_TYPE = 'word'; const SUPPORTS_FUZZY = true; - /** @var array */ - public static $stopWords = [ + public static array $stopWords = [ 'a', 'an', 'and', 'are', 'as', 'at', 'be', 'but', 'by', 'for', 'if', 'in', 'into', 'is', 'it', 'no', 'not', 'of', 'on', 'or', 'such', 'that', 'the', 'their', 'then', 'there', 'these', 'they', 'this', 'to', 'was', 'will', 'with', ]; - /** @var bool */ - private $trailingWildcard = false; + private bool $trailingWildcard = false; - /** - * Word constructor. - * - * @param string $value - * @param BoolOperator $boolOperator - * @param bool $useBoost - * @param float $boost - * @param bool $useFuzzy - * @param int $fuzzy - * @param bool $trailingWildcard - */ public function __construct( string $value, ?BoolOperator $boolOperator = null, @@ -45,33 +32,25 @@ public function __construct( $this->trailingWildcard = $trailingWildcard; } - /** - * @param array $data - * - * @return self - */ - public static function fromArray(array $data = []) + public static function fromArray(array $data = []): self { - $value = isset($data['value']) ? $data['value'] : ''; - $useBoost = isset($data['use_boost']) ? (bool)$data['use_boost'] : false; - $boost = isset($data['boost']) ? (float)$data['boost'] : self::DEFAULT_BOOST; - $useFuzzy = isset($data['use_fuzzy']) ? (bool)$data['use_fuzzy'] : false; - $fuzzy = isset($data['fuzzy']) ? (int)$data['fuzzy'] : self::DEFAULT_FUZZY; - $trailingWildcard = isset($data['trailing_wildcard']) ? (bool)$data['trailing_wildcard'] : false; + $value = $data['value'] ?? ''; + $useBoost = (bool)($data['use_boost'] ?? false); + $boost = (float)($data['boost'] ?? self::DEFAULT_BOOST); + $useFuzzy = (bool)($data['use_fuzzy'] ?? false); + $fuzzy = (int)($data['fuzzy'] ?? self::DEFAULT_FUZZY); + $trailingWildcard = (bool)($data['trailing_wildcard'] ?? false); try { $boolOperator = isset($data['bool_operator']) ? BoolOperator::create($data['bool_operator']) : null; - } catch (\Exception $e) { + } catch (\Throwable $e) { $boolOperator = null; } return new self($value, $boolOperator, $useBoost, $boost, $useFuzzy, $fuzzy, $trailingWildcard); } - /** - * @return array - */ - public function toArray() + public function toArray(): array { $array = parent::toArray(); if (!$this->trailingWildcard) { @@ -82,25 +61,16 @@ public function toArray() return $array; } - /** - * @return bool - */ public function hasTrailingWildcard(): bool { return $this->trailingWildcard; } - /** - * @return bool - */ public function isStopWord(): bool { return in_array(strtolower($this->getValue()), self::$stopWords); } - /** - * @param QueryBuilder $builder - */ public function acceptBuilder(QueryBuilder $builder): void { $builder->addWord($this); diff --git a/src/Node/WordRange.php b/src/Node/WordRange.php index 5d25cd9..c7afa42 100755 --- a/src/Node/WordRange.php +++ b/src/Node/WordRange.php @@ -8,13 +8,6 @@ final class WordRange extends Range const NODE_TYPE = 'word_range'; const COMPOUND_NODE = true; - /** - * WordRange constructor. - * - * @param Word $lowerNode - * @param Word $upperNode - * @param bool $exclusive - */ public function __construct(?Word $lowerNode = null, ?Word $upperNode = null, bool $exclusive = false) { parent::__construct($lowerNode, $upperNode, $exclusive); diff --git a/src/ParsedQuery.php b/src/ParsedQuery.php index 3bf3601..9652307 100755 --- a/src/ParsedQuery.php +++ b/src/ParsedQuery.php @@ -3,25 +3,15 @@ namespace Gdbots\QueryParser; -use Gdbots\Common\FromArray; -use Gdbots\Common\ToArray; use Gdbots\QueryParser\Node\Field; use Gdbots\QueryParser\Node\Node; -class ParsedQuery implements FromArray, ToArray, \JsonSerializable +final class ParsedQuery implements \JsonSerializable { - /** @var Node[] */ - private $nodes = []; + private array $nodes = []; + private array $nodesByType = []; - /** @var array */ - private $nodesByType = []; - - /** - * @param array $data - * - * @return static - */ - public static function fromArray(array $data = []) + public static function fromArray(array $data = []): self { $obj = new static(); @@ -32,17 +22,11 @@ public static function fromArray(array $data = []) return $obj; } - /** - * @return array - */ - public function toArray() + public function toArray(): array { return $this->nodes; } - /** - * @return array - */ public function jsonSerialize() { return $this->toArray(); @@ -51,7 +35,7 @@ public function jsonSerialize() /** * @param Node[] $nodes * - * @return static + * @return self */ public function addNodes(array $nodes): self { @@ -65,7 +49,7 @@ public function addNodes(array $nodes): self /** * @param Node $node * - * @return static + * @return self */ public function addNode(Node $node): self { @@ -114,7 +98,7 @@ public function hasAMatchableNode(): bool * Returns an array of fields (specifically the field names) that are * used in this query. e.g. "status:active", "status" is the field name. * - * @return array + * @return string[] */ public function getFieldsUsed(): array { diff --git a/src/QueryParser.php b/src/QueryParser.php index 538fb5c..d5f9af9 100755 --- a/src/QueryParser.php +++ b/src/QueryParser.php @@ -25,16 +25,10 @@ * Parses a query and returns a ParsedQuery object with a set of * nodes per type, i.e. words, phrases, hashtags, etc. */ -class QueryParser +final class QueryParser { - /** @var Tokenizer */ - protected $tokenizer; - - /** @var TokenStream */ - protected $stream; - - /** @var ParsedQuery */ - protected $query; + private Tokenizer $tokenizer; + private TokenStream $stream; /** * Constructs a new QueryParser. @@ -44,15 +38,10 @@ public function __construct() $this->tokenizer = new Tokenizer(); } - /** - * @param string $input - * - * @return ParsedQuery - */ public function parse(string $input): ParsedQuery { $this->stream = $this->tokenizer->scan($input); - $this->query = new ParsedQuery(); + $query = new ParsedQuery(); while ($this->stream->next()) { $boolOperator = $this->getBoolOperator(); @@ -61,10 +50,10 @@ public function parse(string $input): ParsedQuery break; } - $this->query->addNodes($this->createNodes($token, $boolOperator)); + $query->addNodes($this->createNodes($token, $boolOperator)); } - return $this->query; + return $query; } /** @@ -74,7 +63,7 @@ public function parse(string $input): ParsedQuery * * @return Node[] */ - protected function createNodes( + private function createNodes( Token $token, BoolOperator $boolOperator, ?ComparisonOperator $comparisonOperator = null @@ -138,7 +127,7 @@ protected function createNodes( * * @return Field|Node[]|Node */ - protected function handleField(string $fieldName, BoolOperator $boolOperator) + private function handleField(string $fieldName, BoolOperator $boolOperator) { $lookahead = $this->stream->getLookahead(); if (!$lookahead instanceof Token) { @@ -193,7 +182,7 @@ protected function handleField(string $fieldName, BoolOperator $boolOperator) * * @return Field|Node[]|Node */ - protected function handleFieldWithRange(string $fieldName, BoolOperator $boolOperator) + private function handleFieldWithRange(string $fieldName, BoolOperator $boolOperator) { $exclusive = $this->stream->typeIs(Token::T_RANGE_EXCL_START); $matchTypes = true; @@ -291,7 +280,7 @@ protected function handleFieldWithRange(string $fieldName, BoolOperator $boolOpe * * @return Field|Node */ - protected function handleFieldWithSubquery(string $fieldName, BoolOperator $boolOperator): Node + private function handleFieldWithSubquery(string $fieldName, BoolOperator $boolOperator): Node { $this->stream->nextIf(Token::T_SUBQUERY_START); $subquery = $this->handleSubquery($boolOperator); @@ -315,7 +304,7 @@ protected function handleFieldWithSubquery(string $fieldName, BoolOperator $bool * * @return Subquery|Node[]|Node */ - protected function handleSubquery(BoolOperator $queryBoolOperator) + private function handleSubquery(BoolOperator $queryBoolOperator) { $this->stream->nextIf(Token::T_SUBQUERY_START); /** @var Node[] $nodes */ @@ -378,14 +367,7 @@ protected function handleSubquery(BoolOperator $queryBoolOperator) return new Subquery($nodes, $queryBoolOperator, $m['use_boost'], $m['boost']); } - /** - * @param string $value - * @param BoolOperator $boolOperator - * @param ComparisonOperator $comparisonOperator - * - * @return Date - */ - protected function createDate( + private function createDate( string $value, BoolOperator $boolOperator, ?ComparisonOperator $comparisonOperator = null @@ -402,102 +384,54 @@ protected function createDate( ); } - /** - * @param string $value - * @param BoolOperator $boolOperator - * - * @return Emoji - */ - protected function createEmoji(string $value, BoolOperator $boolOperator): Emoji + private function createEmoji(string $value, BoolOperator $boolOperator): Emoji { $boolOperator = $boolOperator->equals(BoolOperator::OPTIONAL()) ? BoolOperator::REQUIRED() : $boolOperator; $m = $this->getModifiers(); return new Emoji($value, $boolOperator, $m['use_boost'], $m['boost']); } - /** - * @param string $value - * @param BoolOperator $boolOperator - * - * @return Emoticon - */ - protected function createEmoticon(string $value, BoolOperator $boolOperator): Emoticon + private function createEmoticon(string $value, BoolOperator $boolOperator): Emoticon { $boolOperator = $boolOperator->equals(BoolOperator::OPTIONAL()) ? BoolOperator::REQUIRED() : $boolOperator; $m = $this->getModifiers(); return new Emoticon($value, $boolOperator, $m['use_boost'], $m['boost']); } - /** - * @param string $value - * @param BoolOperator $boolOperator - * - * @return Hashtag - */ - protected function createHashtag(string $value, BoolOperator $boolOperator): Hashtag + private function createHashtag(string $value, BoolOperator $boolOperator): Hashtag { $boolOperator = $boolOperator->equals(BoolOperator::OPTIONAL()) ? BoolOperator::REQUIRED() : $boolOperator; $m = $this->getModifiers(); return new Hashtag($value, $boolOperator, $m['use_boost'], $m['boost']); } - /** - * @param string $value - * @param BoolOperator $boolOperator - * - * @return Mention - */ - protected function createMention(string $value, BoolOperator $boolOperator): Mention + private function createMention(string $value, BoolOperator $boolOperator): Mention { $boolOperator = $boolOperator->equals(BoolOperator::OPTIONAL()) ? BoolOperator::REQUIRED() : $boolOperator; $m = $this->getModifiers(); return new Mention($value, $boolOperator, $m['use_boost'], $m['boost']); } - /** - * @param float $value - * @param ComparisonOperator $comparisonOperator - * - * @return Numbr - */ - protected function createNumber(float $value, ?ComparisonOperator $comparisonOperator = null): Numbr + private function createNumber(float $value, ?ComparisonOperator $comparisonOperator = null): Numbr { // move the stream and ignore them if they exist $this->getModifiers(); return new Numbr($value, $comparisonOperator); } - /** - * @param string $value - * @param BoolOperator $boolOperator - * - * @return Phrase - */ - protected function createPhrase(string $value, BoolOperator $boolOperator): Phrase + private function createPhrase(string $value, BoolOperator $boolOperator): Phrase { $m = $this->getModifiers(); return new Phrase($value, $boolOperator, $m['use_boost'], $m['boost'], $m['use_fuzzy'], $m['fuzzy']); } - /** - * @param string $value - * @param BoolOperator $boolOperator - * - * @return Url - */ - protected function createUrl(string $value, BoolOperator $boolOperator): Url + private function createUrl(string $value, BoolOperator $boolOperator): Url { $m = $this->getModifiers(); return new Url($value, $boolOperator, $m['use_boost'], $m['boost']); } - /** - * @param string $value - * @param BoolOperator $boolOperator - * - * @return Word - */ - protected function createWord(string $value, BoolOperator $boolOperator): Word + private function createWord(string $value, BoolOperator $boolOperator): Word { $m = $this->getModifiers(); return new Word( @@ -511,12 +445,7 @@ protected function createWord(string $value, BoolOperator $boolOperator): Word ); } - /** - * @param int $default - * - * @return BoolOperator - */ - protected function getBoolOperator(int $default = BoolOperator::OPTIONAL): BoolOperator + private function getBoolOperator(int $default = BoolOperator::OPTIONAL): BoolOperator { if ($this->stream->nextIf(Token::T_REQUIRED) || $this->stream->lookaheadTypeIs(Token::T_AND) @@ -532,10 +461,7 @@ protected function getBoolOperator(int $default = BoolOperator::OPTIONAL): BoolO return BoolOperator::create($default); } - /** - * @return ComparisonOperator - */ - protected function getComparisonOperator(): ?ComparisonOperator + private function getComparisonOperator(): ?ComparisonOperator { if ($this->stream->nextIf(Token::T_GREATER_THAN)) { $op = ComparisonOperator::GT; @@ -552,10 +478,7 @@ protected function getComparisonOperator(): ?ComparisonOperator return ComparisonOperator::create($op); } - /** - * @return array - */ - protected function getModifiers(): array + private function getModifiers(): array { $array = [ 'trailing_wildcard' => $this->stream->nextIfLookahead(Token::T_WILDCARD), diff --git a/src/Token.php b/src/Token.php index 2348570..e14c9b0 100755 --- a/src/Token.php +++ b/src/Token.php @@ -3,7 +3,7 @@ namespace Gdbots\QueryParser; -class Token implements \JsonSerializable +final class Token implements \JsonSerializable { const T_EOI = 0; // end of input const T_WHITE_SPACE = 1; @@ -42,10 +42,9 @@ class Token implements \JsonSerializable * * @var array */ - private static $typeNames; + private static array $typeNames; - /** @var int */ - private $type = self::T_EOI; + private int $type; /** @var string|float|null */ private $value; @@ -73,28 +72,19 @@ public static function name(int $type): string static::$typeNames = array_flip((new \ReflectionClass(__CLASS__))->getConstants()); } - return isset(self::$typeNames[$type]) ? self::$typeNames[$type] : (string)$type; + return self::$typeNames[$type] ?? (string)$type; } - /** - * @return array - */ public function jsonSerialize() { return ['type' => $this->type, 'value' => $this->value]; } - /** - * @return string - */ public function getTypeName(): string { return self::name($this->type); } - /** - * @return int - */ public function getType(): int { return $this->type; @@ -108,11 +98,6 @@ public function getValue() return $this->value; } - /** - * @param int $type - * - * @return bool - */ public function typeEquals(int $type): bool { return $type === $this->type; @@ -128,25 +113,16 @@ public function typeEqualsAnyOf(array $types): bool return in_array($this->type, $types, true); } - /** - * @return bool - */ public function isWhiteSpace(): bool { return self::T_WHITE_SPACE === $this->type; } - /** - * @return bool - */ public function isIgnored(): bool { return self::T_IGNORED === $this->type; } - /** - * @return bool - */ public function isEndOfInput(): bool { return self::T_EOI === $this->type; diff --git a/src/TokenStream.php b/src/TokenStream.php index a7b2ac3..8f03fc8 100755 --- a/src/TokenStream.php +++ b/src/TokenStream.php @@ -5,17 +5,13 @@ final class TokenStream implements \JsonSerializable { - /** @var Token */ - private static $eoi; + private static ?Token $eoi = null; /** @var Token[] */ - private $tokens = []; + private array $tokens = []; - /** @var Token */ - private $current; - - /** @var int */ - private $position = 0; + private Token $current; + private int $position = 0; /** * @param Token[] $tokens @@ -38,7 +34,7 @@ public function __construct(array $tokens) public function reset(): self { $this->position = 0; - $this->current = isset($this->tokens[$this->position]) ? $this->tokens[$this->position] : self::$eoi; + $this->current = $this->tokens[$this->position] ?? self::$eoi; return $this; } @@ -151,7 +147,7 @@ public function typeIs(int $type): bool /** * Returns true if the current type equals any of the given types. * - * @param array $types + * @param int[] $types * * @return bool */ @@ -175,7 +171,7 @@ public function lookaheadTypeIs(int $type): bool /** * Returns true if the lookahead type equals any of the given types. * - * @param array $types + * @param int[] $types * * @return bool */ @@ -199,7 +195,7 @@ public function prevTypeIs(int $type): bool /** * Returns true if the previous token type equals any of the given types. * - * @param array $types + * @param int[] $types * * @return bool */ @@ -208,20 +204,14 @@ public function prevTypeIsAnyOf(array $types): bool return isset($this->tokens[$this->position - 2]) && $this->tokens[$this->position - 2]->typeEqualsAnyOf($types); } - /** - * @return Token - */ public function getCurrent(): Token { return $this->current; } - /** - * @return Token|null - */ public function getLookahead(): ?Token { - return isset($this->tokens[$this->position]) ? $this->tokens[$this->position] : null; + return $this->tokens[$this->position] ?: null; } /** @@ -234,9 +224,6 @@ public function getTokens(): array return $this->tokens; } - /** - * @return array - */ public function jsonSerialize() { return $this->tokens; diff --git a/src/Tokenizer.php b/src/Tokenizer.php index 1e0af19f66e0a54febda53334eeeace78c419d43..4cc0fa59f1c62641f0d76ce90c94729dc4a18804 100755 GIT binary patch delta 225 zcmX>;oAL21#tHUpX_%*Yel6t52w@qEWHK^m=9NsIEqa8lxTGjE zFMV>HnAqg2VzR7>MMa5~lRt{(T8HFkr{*cB+DA?NCDyTpdAzAGxEj~Fz zTxoKfxXk2v;;NH37_m&&li-vzdH2^W+*up~(m2I9SROb4n){D9CS~r*u>c0Pk>KqyPW_ diff --git a/tests/Builder/XmlQueryBuilderTest.php b/tests/Builder/XmlQueryBuilderTest.php index b92d232..2a257f0 100755 --- a/tests/Builder/XmlQueryBuilderTest.php +++ b/tests/Builder/XmlQueryBuilderTest.php @@ -4,19 +4,16 @@ namespace Gdbots\Tests\QueryParser\Builder; use Gdbots\QueryParser\Builder\XmlQueryBuilder; -use Gdbots\QueryParser\QueryParser; use Gdbots\QueryParser\Node\Node; +use Gdbots\QueryParser\QueryParser; use PHPUnit\Framework\TestCase; class XmlQueryBuilderTest extends TestCase { - /** @var QueryParser */ - protected $parser; - - /** @var XmlQueryBuilder */ - protected $builder; + protected ?QueryParser $parser = null; + protected ?XmlQueryBuilder $builder = null; - public function setUp() + public function setUp(): void { $this->parser = new QueryParser(); $this->builder = new XmlQueryBuilder(); @@ -60,9 +57,6 @@ public function testToSimpleXmlElement(string $name, string $input, $ignored, ar } } - /** - * @return array - */ public function getTestQueries(): array { return require __DIR__ . '/../Fixtures/test-queries.php'; diff --git a/tests/QueryParserTest.php b/tests/QueryParserTest.php index af59767..4824a98 100755 --- a/tests/QueryParserTest.php +++ b/tests/QueryParserTest.php @@ -8,10 +8,9 @@ class QueryParserTest extends TestCase { - /** @var QueryParser */ - protected $parser; + protected ?QueryParser $parser = null; - public function setUp() + public function setUp(): void { $this->parser = new QueryParser(); } @@ -30,9 +29,6 @@ public function testParse(string $name, string $input, $ignored, array $expected $this->assertEquals($expectedNodes, $result->getNodes(), "Test query [{$name}] with input [{$input}] failed."); } - /** - * @return array - */ public function getTestQueries(): array { return require __DIR__ . '/Fixtures/test-queries.php'; diff --git a/tests/TokenizerTest.php b/tests/TokenizerTest.php index 30a049d..a80f090 100755 --- a/tests/TokenizerTest.php +++ b/tests/TokenizerTest.php @@ -9,10 +9,9 @@ class TokenizerTest extends TestCase { - /** @var Tokenizer */ - protected $tokenizer; + protected ?Tokenizer $tokenizer = null; - public function setUp() + public function setUp(): void { $this->tokenizer = new Tokenizer(); } @@ -45,9 +44,6 @@ public function testScan(string $name, string $input, array $expectedTokens): vo $this->assertEquals($expectedTokens, $tokenStream->getTokens(), "Test query [{$name}] with input [{$input}] failed."); } - /** - * @return array - */ public function getTestQueries(): array { return require __DIR__ . '/Fixtures/test-queries.php';