Index   A
last analyzed

Complexity

Total Complexity 26

Size/Duplication

Total Lines 205
Duplicated Lines 0 %

Test Coverage

Coverage 63.97%

Importance

Changes 0
Metric Value
eloc 95
dl 0
loc 205
ccs 87
cts 136
cp 0.6397
rs 10
c 0
b 0
f 0
wmc 26

10 Methods

Rating   Name   Duplication   Size   Complexity  
A saveStatistics() 0 23 3
A execute() 0 8 1
A validateForm() 0 11 3
A getQuery() 0 13 2
A display() 0 17 2
A getCachedData() 0 14 4
B getRealData() 0 39 6
A buildForm() 0 14 1
A getCanonicalUrl() 0 8 2
A parse() 0 14 2
1
<?php
2
3
namespace Frontend\Modules\Search\Actions;
4
5
use DateInterval;
6
use Psr\Cache\CacheItemPoolInterface;
7
use Frontend\Core\Engine\Base\Block as FrontendBaseBlock;
8
use Frontend\Core\Engine\Form as FrontendForm;
9
use Frontend\Core\Language\Language as FL;
10
use Frontend\Core\Engine\Model as FrontendModel;
11
use Frontend\Core\Engine\Navigation as FrontendNavigation;
12
use Frontend\Modules\Search\Engine\Model as FrontendSearchModel;
13
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
14
15
class Index extends FrontendBaseBlock
16
{
17
    /** @var FrontendForm */
18
    private $form;
19
20
    /** @var array */
21
    private $searchResults;
22
23
    /** @var int */
24
    private $limit;
25
26
    /** @var int */
27
    private $offset;
28
29
    /** @var int */
30
    private $requestedPage;
31
32
    /** @var string */
33
    private $searchTerm = '';
34
35
    /** @var CacheItemPoolInterface */
36
    private $cache;
37
38
    /** @var string */
39
    private $cacheKey;
40
41 4
    private function display(): void
42
    {
43 4
        $this->requestedPage = $this->url->getParameter('page', 'int', 1);
44 4
        $this->limit = $this->get('fork.settings')->get('Search', 'overview_num_items', 20);
45 4
        $this->offset = ($this->requestedPage * $this->limit) - $this->limit;
46 4
        $this->cache = $this->get('cache.search');
47 4
        $this->cacheKey = implode(
48 4
            '_',
49 4
            [$this->getModule(), LANGUAGE, md5($this->searchTerm), $this->offset, $this->limit]
50
        );
51
52 4
        if (!$this->getCachedData()) {
53
            // no valid cache so we get fresh data
54 4
            $this->getRealData();
55
        }
56
57 4
        $this->parse();
58 4
    }
59
60 4
    public function execute(): void
61
    {
62 4
        parent::execute();
63 4
        $this->loadTemplate();
64 4
        $this->buildForm();
65 4
        $this->validateForm();
66 4
        $this->display();
67 4
        $this->saveStatistics();
68 4
    }
69
70 4
    private function getCachedData(): bool
71
    {
72 4
        if (!$this->searchTerm || $this->getContainer()->getParameter('kernel.debug')) {
73 4
            return false;
74
        }
75
76
        $cacheItem = $this->cache->getItem($this->cacheKey);
77
        if (!$cacheItem->isHit()) {
78
            return false;
79
        }
80
81
        ['pagination' => $this->pagination, 'items' => $this->searchResults] = $cacheItem->get();
82
83
        return true;
84
    }
85
86 4
    private function getRealData(): void
87
    {
88 4
        if (!$this->searchTerm) {
89 4
            return;
90
        }
91
92 1
        $this->searchResults = FrontendSearchModel::search($this->searchTerm, $this->limit, $this->offset);
93
94
        // populate count fields in pagination
95
        // this is done after actual search because some items might be
96
        // activated/deactivated (getTotal only does rough checking)
97 1
        $numberOfItems = FrontendSearchModel::getTotal($this->searchTerm);
98 1
        $this->pagination = [
99 1
            'url' => FrontendNavigation::getUrlForBlock('Search') . '?form=search&q=' . $this->searchTerm,
100 1
            'limit' => $this->limit,
101 1
            'offset' => $this->offset,
102 1
            'requested_page' => $this->requestedPage,
103 1
            'num_items' => FrontendSearchModel::getTotal($this->searchTerm),
104 1
            'num_pages' => (int) ceil($numberOfItems / $this->limit)
105
        ];
106
107
        // num pages is always equal to at least 1
108 1
        if ($this->pagination['num_pages'] === 0) {
109
            $this->pagination['num_pages'] = 1;
110
        }
111
112 1
        if ($this->requestedPage < 1 || $this->requestedPage > $this->pagination['num_pages']) {
113
            throw new NotFoundHttpException();
114
        }
115
116
        // Don't save the result in the cache when debug is enabled
117 1
        if ($this->getContainer()->getParameter('kernel.debug')) {
118 1
            return;
119
        }
120
121
        $cacheItem = $this->cache->getItem($this->cacheKey);
122
        $cacheItem->expiresAfter(new DateInterval('PT1H'));
123
        $cacheItem->set(['pagination' => $this->pagination, 'items' => $this->searchResults]);
124
        $this->cache->save($cacheItem);
125
    }
126
127 4
    private function buildForm(): void
128
    {
129 4
        $this->form = new FrontendForm('search', null, 'get', null, false);
130
131 4
        $query = $this->getQuery();
132 4
        $this->form->addText('q', $query)->setAttributes(
133
            [
134 4
                'data-role' => 'fork-search-field',
135
                'data-autocomplete' => 'enabled',
136
                'data-live-suggest' => 'enabled',
137
            ]
138
        );
139
140 4
        $this->header->setCanonicalUrl($this->getCanonicalUrl($query));
141 4
    }
142
143 4
    private function getQuery(): string
144
    {
145 4
        if ($this->getRequest()->query->has('q')) {
146 2
            return $this->getRequest()->query->get('q', '');
147
        }
148
149
        // search query was submitted by our search widget
150 4
        $query = $this->getRequest()->query->get('q_widget', '');
151
        // set $_GET variable to keep SpoonForm happy
152
        // should be refactored out when Symfony form are implemented here
153 4
        $_GET['q'] = $query;
154
155 4
        return $query;
156
    }
157
158 4
    private function getCanonicalUrl(string $query): string
159
    {
160 4
        $canonicalUrl = SITE_URL . FrontendNavigation::getUrlForBlock('Search');
161 4
        if ($query === '') {
162 4
            return $canonicalUrl;
163
        }
164
165
        return $canonicalUrl . '?q=' . \SpoonFilter::htmlspecialchars($query);
166
    }
167
168 4
    private function parse(): void
169
    {
170 4
        $this->addJS('/js/vendors/typeahead.bundle.min.js', true, false);
171 4
        $this->addCSS('Search.css');
172
173 4
        $this->form->parse($this->template);
174
175 4
        if (!$this->searchTerm) {
176 4
            return;
177
        }
178
179 1
        $this->template->assign('searchResults', $this->searchResults);
180 1
        $this->template->assign('searchTerm', $this->searchTerm);
181 1
        $this->parsePagination();
182 1
    }
183
184 4
    private function saveStatistics(): void
185
    {
186 4
        if (!$this->searchTerm) {
187 4
            return;
188
        }
189
190 1
        $previousTerm = FrontendModel::getSession()->get('searchTerm', '');
191 1
        FrontendModel::getSession()->set('searchTerm', '');
192
193
        // don't save the search term in the database if it is the same as the last time
194 1
        if ($previousTerm !== $this->searchTerm) {
195 1
            FrontendSearchModel::save(
196
                [
197 1
                    'term' => $this->searchTerm,
198 1
                    'language' => LANGUAGE,
199 1
                    'time' => FrontendModel::getUTCDate(),
200 1
                    'data' => serialize(['server' => $_SERVER]),
201 1
                    'num_results' => $this->pagination['num_items'],
202
                ]
203
            );
204
        }
205
206 1
        FrontendModel::getSession()->set('searchTerm', $this->searchTerm);
207 1
    }
208
209 4
    private function validateForm(): void
210
    {
211 4
        if (!$this->form->isSubmitted()) {
212 4
            return;
213
        }
214
215 2
        $this->form->cleanupFields();
216 2
        $this->form->getField('q')->isFilled(FL::err('TermIsRequired'));
217
218 2
        if ($this->form->isCorrect()) {
219 1
            $this->searchTerm = $this->form->getField('q')->getValue();
220
        }
221 2
    }
222
}
223