Passed
Push — task/3376-TYPO3_12_compatibili... ( 00c9eb...0c91ac )
by Rafael
51:40 queued 09:07
created

SearchController   A

Complexity

Total Complexity 24

Size/Duplication

Total Lines 228
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 24
eloc 94
c 1
b 0
f 0
dl 0
loc 228
rs 10

11 Methods

Rating   Name   Duplication   Size   Complexity  
A getCustomTemplateFromConfiguration() 0 4 1
A mapGlobalQueryStringWhenEnabled() 0 8 3
A initializeView() 0 12 4
A initializeAction() 0 4 1
A solrNotAvailableAction() 0 4 1
A frequentlySearchedAction() 0 25 1
A detailAction() 0 13 3
B resultsAction() 0 56 6
A handleSolrUnavailable() 0 4 1
A getAdditionalFilters() 0 3 1
A formAction() 0 22 2
1
<?php
2
3
/*
4
 * This file is part of the TYPO3 CMS project.
5
 *
6
 * It is free software; you can redistribute it and/or modify it under
7
 * the terms of the GNU General Public License, either version 2
8
 * of the License, or any later version.
9
 *
10
 * For the full copyright and license information, please read the
11
 * LICENSE.txt file that was distributed with this source code.
12
 *
13
 * The TYPO3 project - inspiring people to share!
14
 */
15
16
namespace ApacheSolrForTypo3\Solr\Controller;
17
18
use ApacheSolrForTypo3\Solr\Domain\Search\ResultSet\SearchResultSet;
19
use ApacheSolrForTypo3\Solr\Event\Search\AfterFrequentlySearchedEvent;
20
use ApacheSolrForTypo3\Solr\Event\Search\AfterSearchEvent;
21
use ApacheSolrForTypo3\Solr\Event\Search\FormEvent;
22
use ApacheSolrForTypo3\Solr\Pagination\ResultsPagination;
23
use ApacheSolrForTypo3\Solr\Pagination\ResultsPaginator;
24
use ApacheSolrForTypo3\Solr\System\Solr\SolrUnavailableException;
25
use ApacheSolrForTypo3\Solr\Util;
26
use Psr\Http\Message\ResponseInterface;
27
use TYPO3\CMS\Core\Context\Exception\AspectNotFoundException;
28
use TYPO3\CMS\Core\Utility\GeneralUtility;
29
use TYPO3\CMS\Extbase\Http\ForwardResponse;
30
use TYPO3\CMS\Extbase\Mvc\Exception\NoSuchArgumentException;
31
use TYPO3\CMS\Fluid\View\TemplateView;
32
use TYPO3Fluid\Fluid\View\ViewInterface;
33
34
/**
35
 * Class SearchController
36
 *
37
 * @author Frans Saris <[email protected]>
38
 * @author Timo Hund <[email protected]>
39
 */
40
class SearchController extends AbstractBaseController
41
{
42
    /**
43
     * @var TemplateView
44
     */
45
    protected $view;
46
47
    /**
48
     * Provide search query in extbase arguments.
49
     */
50
    protected function initializeAction()
51
    {
52
        parent::initializeAction();
53
        $this->mapGlobalQueryStringWhenEnabled();
54
    }
55
56
    protected function mapGlobalQueryStringWhenEnabled()
57
    {
58
        $query = GeneralUtility::_GET('q');
59
60
        $useGlobalQueryString = $query !== null && !$this->typoScriptConfiguration->getSearchIgnoreGlobalQParameter();
0 ignored issues
show
Bug introduced by
The method getSearchIgnoreGlobalQParameter() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

60
        $useGlobalQueryString = $query !== null && !$this->typoScriptConfiguration->/** @scrutinizer ignore-call */ getSearchIgnoreGlobalQParameter();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
61
62
        if ($useGlobalQueryString) {
63
            $this->request->setArgument('q', $query);
0 ignored issues
show
Bug introduced by
The method setArgument() does not exist on TYPO3\CMS\Extbase\Mvc\RequestInterface. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

63
            $this->request->/** @scrutinizer ignore-call */ 
64
                            setArgument('q', $query);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
64
        }
65
    }
66
67
    /**
68
     * @param ViewInterface $view
69
     */
70
    public function initializeView($view)
71
    {
72
        if ($view instanceof TemplateView) {
73
            $customTemplate = $this->getCustomTemplateFromConfiguration();
74
            if ($customTemplate === '') {
75
                return;
76
            }
77
78
            if (str_contains($customTemplate, 'EXT:')) {
79
                $view->setTemplatePathAndFilename($customTemplate);
80
            } else {
81
                $view->setTemplate($customTemplate);
82
            }
83
        }
84
    }
85
86
    /**
87
     * @return string
88
     */
89
    protected function getCustomTemplateFromConfiguration(): string
90
    {
91
        $templateKey = str_replace('Action', '', $this->actionMethodName);
92
        return $this->typoScriptConfiguration->getViewTemplateByFileKey($templateKey);
93
    }
94
95
    /**
96
     * Results
97
     * @return ResponseInterface
98
     * @throws AspectNotFoundException
99
     * @throws NoSuchArgumentException
100
     */
101
    public function resultsAction(): ResponseInterface
102
    {
103
        if ($this->searchService === null) {
104
            return $this->handleSolrUnavailable();
105
        }
106
107
        try {
108
            $arguments = $this->request->getArguments();
109
            $pageId = $this->typoScriptFrontendController->getRequestedId();
0 ignored issues
show
Bug introduced by
The method getRequestedId() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

109
            /** @scrutinizer ignore-call */ 
110
            $pageId = $this->typoScriptFrontendController->getRequestedId();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
110
            $languageId = Util::getLanguageUid();
111
            $searchRequest = $this->getSearchRequestBuilder()->buildForSearch($arguments, $pageId, $languageId);
112
113
            $searchResultSet = $this->searchService->search($searchRequest);
114
115
            // we pass the search result set to the controller context, to have the possibility
116
            // to access it without passing it from partial to partial
117
            $this->controllerContext->setSearchResultSet($searchResultSet);
118
119
            $currentPage = $this->request->hasArgument('page') ? (int)$this->request->getArgument('page') : 1;
120
121
            // prevent currentPage < 1 (i.e for GET request like &tx_solr[page]=0)
122
            if ($currentPage < 1) {
123
                $currentPage = 1;
124
            }
125
126
            $itemsPerPage = ($searchResultSet->getUsedResultsPerPage() ?: $this->typoScriptConfiguration->getSearchResultsPerPage(10));
127
            $paginator = GeneralUtility::makeInstance(ResultsPaginator::class, $searchResultSet, $currentPage, $itemsPerPage);
128
            $pagination = GeneralUtility::makeInstance(ResultsPagination::class, $paginator);
129
            $pagination->setMaxPageNumbers((int)$this->typoScriptConfiguration->getMaxPaginatorLinks(0));
130
131
            /* @var AfterSearchEvent $afterSearchEvent */
132
            $afterSearchEvent = $this->eventDispatcher->dispatch(
133
                new AfterSearchEvent(
134
                    $searchResultSet,
135
                    $this->getAdditionalFilters(),
136
                    $this->typoScriptConfiguration->getSearchPluginNamespace(),
137
                    $arguments,
138
                    $pagination,
139
                    $currentPage
140
                )
141
            );
142
143
            $values = [
144
                'additionalFilters' => $afterSearchEvent->getAdditionalFilters(),
145
                'resultSet' => $afterSearchEvent->getResultSet(),
146
                'pluginNamespace' => $afterSearchEvent->getPluginNamespace(),
147
                'arguments' => $afterSearchEvent->getArguments(),
148
                'pagination' => $afterSearchEvent->getPagination(),
149
                'currentPage' => $afterSearchEvent->getCurrentPage(),
150
            ];
151
152
            $this->view->assignMultiple($values);
153
        } catch (SolrUnavailableException $e) {
154
            return $this->handleSolrUnavailable();
155
        }
156
        return $this->htmlResponse();
157
    }
158
159
    /**
160
     * Form
161
     */
162
    public function formAction(): ResponseInterface
163
    {
164
        if ($this->searchService === null) {
165
            return $this->handleSolrUnavailable();
166
        }
167
168
        /* @var FormEvent $formEvent */
169
        $formEvent = $this->eventDispatcher->dispatch(
170
            new FormEvent(
171
                $this->searchService->getSearch(),
172
                $this->getAdditionalFilters(),
173
                $this->typoScriptConfiguration->getSearchPluginNamespace()
174
            )
175
        );
176
        $values = [
177
            'search' => $formEvent->getSearch(),
178
            'additionalFilters' => $formEvent->getAdditionalFilters(),
179
            'pluginNamespace' => $formEvent->getPluginNamespace(),
180
        ];
181
182
        $this->view->assignMultiple($values);
183
        return $this->htmlResponse();
184
    }
185
186
    /**
187
     * Frequently Searched
188
     *
189
     * @return ResponseInterface
190
     */
191
    public function frequentlySearchedAction(): ResponseInterface
192
    {
193
        /** @var  $searchResultSet SearchResultSet */
194
        $searchResultSet = GeneralUtility::makeInstance(SearchResultSet::class);
195
196
        $pageId = $this->typoScriptFrontendController->getRequestedId();
197
        $languageId = Util::getLanguageUid();
198
        $searchRequest = $this->getSearchRequestBuilder()->buildForFrequentSearches($pageId, $languageId);
199
        $searchResultSet->setUsedSearchRequest($searchRequest);
200
201
        $this->controllerContext->setSearchResultSet($searchResultSet);
202
203
        /* @var AfterFrequentlySearchedEvent $afterFrequentlySearchedEvent*/
204
        $afterFrequentlySearchedEvent = $this->eventDispatcher->dispatch(
205
            new AfterFrequentlySearchedEvent(
206
                $searchResultSet,
207
                $this->getAdditionalFilters()
208
            )
209
        );
210
        $values = [
211
            'additionalFilters' => $afterFrequentlySearchedEvent->getAdditionalFilters(),
212
            'resultSet' => $afterFrequentlySearchedEvent->getResultSet(),
213
        ];
214
        $this->view->assignMultiple($values);
215
        return $this->htmlResponse();
216
    }
217
218
    /**
219
     * This action allows to render a detailView with data from solr.
220
     *
221
     * @param string $documentId
222
     * @return ResponseInterface
223
     */
224
    public function detailAction(string $documentId = ''): ResponseInterface
225
    {
226
        if ($this->searchService === null) {
227
            return $this->handleSolrUnavailable();
228
        }
229
230
        try {
231
            $document = $this->searchService->getDocumentById($documentId);
232
            $this->view->assign('document', $document);
233
        } catch (SolrUnavailableException $e) {
234
            return $this->handleSolrUnavailable();
235
        }
236
        return $this->htmlResponse();
237
    }
238
239
    /**
240
     * Rendered when no search is available.
241
     *
242
     * @return ResponseInterface
243
     */
244
    public function solrNotAvailableAction(): ResponseInterface
245
    {
246
        return $this->htmlResponse()
247
            ->withStatus(503, self::STATUS_503_MESSAGE);
248
    }
249
250
    /**
251
     * Called when the solr server is unavailable.
252
     */
253
    protected function handleSolrUnavailable(): ResponseInterface
254
    {
255
        parent::logSolrUnavailable();
256
        return new ForwardResponse('solrNotAvailable');
257
    }
258
259
    /**
260
     * This method can be overwritten to add additionalFilters for the autosuggest.
261
     * By default, suggest controller will apply the configured filters from the typoscript configuration.
262
     *
263
     * @return array
264
     */
265
    protected function getAdditionalFilters(): array
266
    {
267
        return [];
268
    }
269
}
270