1 | <?php |
||||
2 | |||||
3 | namespace Apps\Model\Front\Content; |
||||
4 | |||||
5 | use Apps\ActiveRecord\Content as ContentEntity; |
||||
6 | use Ffcms\Core\App; |
||||
7 | use Ffcms\Core\Arch\Model; |
||||
8 | use Ffcms\Core\Exception\NotFoundException; |
||||
9 | use Ffcms\Core\Helper\Text; |
||||
10 | use Ffcms\Core\Helper\Type\Any; |
||||
11 | use Ffcms\Core\Helper\Type\Str; |
||||
12 | |||||
13 | /** |
||||
14 | * Class EntityContentSearch. Search similar content items. |
||||
15 | * @package Apps\Model\Front\Content |
||||
16 | */ |
||||
17 | class EntityContentSearch extends Model |
||||
18 | { |
||||
19 | const MAX_ITEMS = 5; |
||||
20 | const MIN_QUERY_LENGTH = 2; |
||||
21 | const SEARCH_BY_WORDS_COUNT = 3; |
||||
22 | const CACHE_TIME = 120; // seconds |
||||
23 | |||||
24 | public $items; |
||||
25 | |||||
26 | private $_terms; |
||||
27 | private $_skip = [0]; |
||||
28 | private $_categoryId; |
||||
29 | private $_records; |
||||
30 | |||||
31 | /** |
||||
32 | * EntityContentSearch constructor. Pass search terms (query string) to model and used items to skip it by id. |
||||
33 | * @param $terms |
||||
34 | * @param int|array $skipIds |
||||
35 | * @param int|null $categoryId |
||||
36 | */ |
||||
37 | public function __construct($terms, $skipIds = 0, $categoryId = null) |
||||
38 | { |
||||
39 | $this->_terms = App::$Security->strip_tags(trim($terms, ' ')); |
||||
40 | $this->_categoryId = $categoryId; |
||||
41 | if (Any::isInt($skipIds)) { |
||||
42 | $this->_skip = [$skipIds]; |
||||
43 | } elseif (Any::isArray($skipIds)) { |
||||
44 | $this->_skip = $skipIds; |
||||
45 | } |
||||
46 | parent::__construct(); |
||||
47 | } |
||||
48 | |||||
49 | /** |
||||
50 | * Prepare conditions to build content list |
||||
51 | * @throws NotFoundException |
||||
52 | * @throws \Psr\Cache\InvalidArgumentException |
||||
53 | * @return void |
||||
54 | */ |
||||
55 | public function before(): void |
||||
56 | { |
||||
57 | // check length of passed terms |
||||
58 | if (!Any::isStr($this->_terms) || Str::length($this->_terms) < self::MIN_QUERY_LENGTH) { |
||||
59 | throw new NotFoundException(__('Search terms is too short')); |
||||
60 | } |
||||
61 | |||||
62 | $index = implode('-', $this->_skip); |
||||
63 | // try to get this slow query from cache |
||||
64 | $cache = App::$Cache->getItem('entity.content.search.index.' . $index); |
||||
65 | if (!$cache->isHit()) { |
||||
66 | $cache->set($this->makeSearch()); |
||||
67 | $cache->expiresAfter(static::CACHE_TIME); |
||||
68 | App::$Cache->save($cache); |
||||
69 | } |
||||
70 | $this->_records = $cache->get(); |
||||
71 | |||||
72 | // lets make active record building |
||||
73 | $this->buildContent(); |
||||
74 | parent::before(); |
||||
75 | } |
||||
76 | |||||
77 | /** |
||||
78 | * Build content items as array |
||||
79 | * @return void |
||||
80 | */ |
||||
81 | private function buildContent(): void |
||||
82 | { |
||||
83 | if (!$this->_records || $this->_records->count() < 1) { |
||||
84 | return; |
||||
85 | } |
||||
86 | |||||
87 | foreach ($this->_records as $item) { |
||||
88 | /** @var \Apps\ActiveRecord\Content $item */ |
||||
89 | // full text |
||||
90 | $text = $item->getLocaled('text'); |
||||
91 | // remove html |
||||
92 | $text = App::$Security->strip_tags($text); |
||||
93 | // build items |
||||
94 | $this->items[] = [ |
||||
95 | 'id' => $item->id, |
||||
96 | 'title' => $item->getLocaled('title'), |
||||
97 | 'snippet' => Text::snippet($text), |
||||
0 ignored issues
–
show
Bug
introduced
by
Loading history...
|
|||||
98 | 'uri' => '/content/read/' . $item->getPath(), |
||||
99 | 'thumb' => $item->getPosterThumbUri() |
||||
100 | ]; |
||||
101 | } |
||||
102 | } |
||||
103 | |||||
104 | /** |
||||
105 | * Search records in database and get object result |
||||
106 | * @return ContentEntity[] |
||||
107 | */ |
||||
108 | private function makeSearch() |
||||
109 | { |
||||
110 | $records = new ContentEntity(); |
||||
111 | $records = $records->search($this->_terms, null, static::SEARCH_BY_WORDS_COUNT) |
||||
0 ignored issues
–
show
The call to
Ffcms\Core\Arch\ActiveModel::search() has too many arguments starting with static::SEARCH_BY_WORDS_COUNT .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue. If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.
Loading history...
|
|||||
112 | ->whereNotIn('id', $this->_skip) |
||||
113 | ->where('display', true); |
||||
114 | |||||
115 | if ($this->_categoryId && Any::isInt($this->_categoryId) && $this->_categoryId > 0) { |
||||
0 ignored issues
–
show
The expression
$this->_categoryId of type integer|null is loosely compared to true ; this is ambiguous if the integer can be 0. You might want to explicitly use !== null instead.
In PHP, under loose comparison (like For 0 == false // true
0 == null // true
123 == false // false
123 == null // false
// It is often better to use strict comparison
0 === false // false
0 === null // false
Loading history...
|
|||||
116 | $records = $records->where('category_id', $this->_categoryId); |
||||
117 | } |
||||
118 | |||||
119 | return $records->take(self::MAX_ITEMS) |
||||
0 ignored issues
–
show
|
|||||
120 | ->get(); |
||||
121 | } |
||||
122 | } |
||||
123 |