diff options
| author | 2022-06-02 08:41:08 +0200 | |
|---|---|---|
| committer | 2022-06-02 08:41:08 +0200 | |
| commit | f85c510ed49be031145f6b35e815ce890cd4f9aa (patch) | |
| tree | c7ac947ba5ddacf85dc5d97330f38f7d91b0964c /app/Models/Entry.php | |
| parent | f988b996ab69104bc45b222fa88d34b5c78f98b3 (diff) | |
New search engine (#4378)
* New possibility to invoke user queries from a search expression
From the search field: `S:"My query"`.
Can be combined with other filters such as `S:"My query" date:P3d` as long as the user queries do not contain `OR`.
A use-case is to have an RSS filter with a stable address or an external API call with the ability to update the user query.
* Draft of parenthesis logic
* More draft
* Working parenthesis (a OR b) (c OR d)
* Working (A) OR (B)
* Support nested parentheses + unit tests + documentation
* search:MySearch and S:3
Diffstat (limited to 'app/Models/Entry.php')
| -rw-r--r-- | app/Models/Entry.php | 178 |
1 files changed, 93 insertions, 85 deletions
diff --git a/app/Models/Entry.php b/app/Models/Entry.php index c3cb337fe..57b0e0b60 100644 --- a/app/Models/Entry.php +++ b/app/Models/Entry.php @@ -325,108 +325,116 @@ class FreshRSS_Entry extends Minz_Model { } public function matches(FreshRSS_BooleanSearch $booleanSearch): bool { - if (count($booleanSearch->searches()) <= 0) { - return true; - } + $ok = true; foreach ($booleanSearch->searches() as $filter) { - $ok = true; - if ($filter->getMinDate()) { - $ok &= strnatcmp($this->id, $filter->getMinDate() . '000000') >= 0; - } - if ($ok && $filter->getNotMinDate()) { - $ok &= strnatcmp($this->id, $filter->getNotMinDate() . '000000') < 0; - } - if ($ok && $filter->getMaxDate()) { - $ok &= strnatcmp($this->id, $filter->getMaxDate() . '000000') <= 0; - } - if ($ok && $filter->getNotMaxDate()) { - $ok &= strnatcmp($this->id, $filter->getNotMaxDate() . '000000') > 0; - } - if ($ok && $filter->getMinPubdate()) { - $ok &= $this->date >= $filter->getMinPubdate(); - } - if ($ok && $filter->getNotMinPubdate()) { - $ok &= $this->date < $filter->getNotMinPubdate(); - } - if ($ok && $filter->getMaxPubdate()) { - $ok &= $this->date <= $filter->getMaxPubdate(); - } - if ($ok && $filter->getNotMaxPubdate()) { - $ok &= $this->date > $filter->getNotMaxPubdate(); - } - if ($ok && $filter->getFeedIds()) { - $ok &= in_array($this->feedId, $filter->getFeedIds()); - } - if ($ok && $filter->getNotFeedIds()) { - $ok &= !in_array($this->feedId, $filter->getFeedIds()); - } - if ($ok && $filter->getAuthor()) { - foreach ($filter->getAuthor() as $author) { - $ok &= stripos(implode(';', $this->authors), $author) !== false; + if ($filter instanceof FreshRSS_BooleanSearch) { + // BooleanSearches are combined by AND (default) or OR (special case) operator and are recursive + if ($filter->operator() === 'OR') { + $ok |= $this->matches($filter); + } else { + $ok &= $this->matches($filter); } - } - if ($ok && $filter->getNotAuthor()) { - foreach ($filter->getNotAuthor() as $author) { - $ok &= stripos(implode(';', $this->authors), $author) === false; + } elseif ($filter instanceof FreshRSS_Search) { + // Searches are combined by OR and are not recursive + $ok = true; + if ($filter->getMinDate()) { + $ok &= strnatcmp($this->id, $filter->getMinDate() . '000000') >= 0; } - } - if ($ok && $filter->getIntitle()) { - foreach ($filter->getIntitle() as $title) { - $ok &= stripos($this->title, $title) !== false; + if ($ok && $filter->getNotMinDate()) { + $ok &= strnatcmp($this->id, $filter->getNotMinDate() . '000000') < 0; } - } - if ($ok && $filter->getNotIntitle()) { - foreach ($filter->getNotIntitle() as $title) { - $ok &= stripos($this->title, $title) === false; + if ($ok && $filter->getMaxDate()) { + $ok &= strnatcmp($this->id, $filter->getMaxDate() . '000000') <= 0; } - } - if ($ok && $filter->getTags()) { - foreach ($filter->getTags() as $tag2) { - $found = false; - foreach ($this->tags as $tag1) { - if (strcasecmp($tag1, $tag2) === 0) { - $found = true; + if ($ok && $filter->getNotMaxDate()) { + $ok &= strnatcmp($this->id, $filter->getNotMaxDate() . '000000') > 0; + } + if ($ok && $filter->getMinPubdate()) { + $ok &= $this->date >= $filter->getMinPubdate(); + } + if ($ok && $filter->getNotMinPubdate()) { + $ok &= $this->date < $filter->getNotMinPubdate(); + } + if ($ok && $filter->getMaxPubdate()) { + $ok &= $this->date <= $filter->getMaxPubdate(); + } + if ($ok && $filter->getNotMaxPubdate()) { + $ok &= $this->date > $filter->getNotMaxPubdate(); + } + if ($ok && $filter->getFeedIds()) { + $ok &= in_array($this->feedId, $filter->getFeedIds()); + } + if ($ok && $filter->getNotFeedIds()) { + $ok &= !in_array($this->feedId, $filter->getFeedIds()); + } + if ($ok && $filter->getAuthor()) { + foreach ($filter->getAuthor() as $author) { + $ok &= stripos(implode(';', $this->authors), $author) !== false; + } + } + if ($ok && $filter->getNotAuthor()) { + foreach ($filter->getNotAuthor() as $author) { + $ok &= stripos(implode(';', $this->authors), $author) === false; + } + } + if ($ok && $filter->getIntitle()) { + foreach ($filter->getIntitle() as $title) { + $ok &= stripos($this->title, $title) !== false; + } + } + if ($ok && $filter->getNotIntitle()) { + foreach ($filter->getNotIntitle() as $title) { + $ok &= stripos($this->title, $title) === false; + } + } + if ($ok && $filter->getTags()) { + foreach ($filter->getTags() as $tag2) { + $found = false; + foreach ($this->tags as $tag1) { + if (strcasecmp($tag1, $tag2) === 0) { + $found = true; + } } + $ok &= $found; } - $ok &= $found; } - } - if ($ok && $filter->getNotTags()) { - foreach ($filter->getNotTags() as $tag2) { - $found = false; - foreach ($this->tags as $tag1) { - if (strcasecmp($tag1, $tag2) === 0) { - $found = true; + if ($ok && $filter->getNotTags()) { + foreach ($filter->getNotTags() as $tag2) { + $found = false; + foreach ($this->tags as $tag1) { + if (strcasecmp($tag1, $tag2) === 0) { + $found = true; + } } + $ok &= !$found; } - $ok &= !$found; } - } - if ($ok && $filter->getInurl()) { - foreach ($filter->getInurl() as $url) { - $ok &= stripos($this->link, $url) !== false; + if ($ok && $filter->getInurl()) { + foreach ($filter->getInurl() as $url) { + $ok &= stripos($this->link, $url) !== false; + } } - } - if ($ok && $filter->getNotInurl()) { - foreach ($filter->getNotInurl() as $url) { - $ok &= stripos($this->link, $url) === false; + if ($ok && $filter->getNotInurl()) { + foreach ($filter->getNotInurl() as $url) { + $ok &= stripos($this->link, $url) === false; + } } - } - if ($ok && $filter->getSearch()) { - foreach ($filter->getSearch() as $needle) { - $ok &= (stripos($this->title, $needle) !== false || stripos($this->content, $needle) !== false); + if ($ok && $filter->getSearch()) { + foreach ($filter->getSearch() as $needle) { + $ok &= (stripos($this->title, $needle) !== false || stripos($this->content, $needle) !== false); + } } - } - if ($ok && $filter->getNotSearch()) { - foreach ($filter->getNotSearch() as $needle) { - $ok &= (stripos($this->title, $needle) === false && stripos($this->content, $needle) === false); + if ($ok && $filter->getNotSearch()) { + foreach ($filter->getNotSearch() as $needle) { + $ok &= (stripos($this->title, $needle) === false && stripos($this->content, $needle) === false); + } + } + if ($ok) { + return true; } - } - if ($ok) { - return true; } } - return false; + return $ok; } public function applyFilterActions(array $titlesAsRead = []) { |
