Test Failed
Push — master ( e3c39f...fe570d )
by Mihail
07:20
created

Apps/Model/Front/Content/EntityContentSearch.php (2 issues)

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),
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)
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
Bug Best Practice introduced by
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 ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

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
Bug Best Practice introduced by
The expression return $records->take(self::MAX_ITEMS)->get() returns the type Illuminate\Database\Eloquent\Collection which is incompatible with the documented return type Apps\ActiveRecord\Content[].
Loading history...
120
            ->get();
121
    }
122
}
123