Passed
Pull Request — main (#3338)
by Rafael
03:25
created

SearchController   A

Complexity

Total Complexity 21

Size/Duplication

Total Lines 193
Duplicated Lines 0 %

Test Coverage

Coverage 62.82%

Importance

Changes 2
Bugs 0 Features 0
Metric Value
wmc 21
eloc 74
c 2
b 0
f 0
dl 0
loc 193
ccs 49
cts 78
cp 0.6282
rs 10

11 Methods

Rating   Name   Duplication   Size   Complexity  
A initializeAction() 0 4 1
A getCustomTemplateFromConfiguration() 0 4 1
A mapGlobalQueryStringWhenEnabled() 0 8 3
A initializeView() 0 12 4
A solrNotAvailableAction() 0 4 1
A frequentlySearchedAction() 0 20 1
A detailAction() 0 9 2
A resultsAction() 0 42 5
A handleSolrUnavailable() 0 4 1
A getAdditionalFilters() 0 3 1
A formAction() 0 11 1
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\Pagination\ResultsPagination;
20
use ApacheSolrForTypo3\Solr\Pagination\ResultsPaginator;
21
use ApacheSolrForTypo3\Solr\System\Solr\SolrUnavailableException;
22
use ApacheSolrForTypo3\Solr\Util;
23
use Psr\Http\Message\ResponseInterface;
24
use TYPO3\CMS\Core\Context\Exception\AspectNotFoundException;
25
use TYPO3\CMS\Core\Utility\GeneralUtility;
26
use TYPO3\CMS\Extbase\Http\ForwardResponse;
27
use TYPO3\CMS\Extbase\Mvc\Exception\NoSuchArgumentException;
28
use TYPO3\CMS\Extbase\SignalSlot\Exception\InvalidSlotException;
29
use TYPO3\CMS\Extbase\SignalSlot\Exception\InvalidSlotReturnException;
30
use TYPO3\CMS\Fluid\View\TemplateView;
31
use TYPO3Fluid\Fluid\View\ViewInterface;
32
33
/**
34
 * Class SearchController
35
 *
36
 * @author Frans Saris <[email protected]>
37
 * @author Timo Hund <[email protected]>
38
 */
39
class SearchController extends AbstractBaseController
40
{
41
    /**
42
     * @var TemplateView
43
     */
44
    protected $view;
45
46
    /**
47
     * Provide search query in extbase arguments.
48
     */
49 35
    protected function initializeAction()
50
    {
51 35
        parent::initializeAction();
52 35
        $this->mapGlobalQueryStringWhenEnabled();
53
    }
54
55 35
    protected function mapGlobalQueryStringWhenEnabled()
56
    {
57 35
        $query = GeneralUtility::_GET('q');
58
59 35
        $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

59
        $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...
60
61 35
        if ($useGlobalQueryString) {
62 1
            $this->request->setArgument('q', $query);
63
        }
64
    }
65
66
    /**
67
     * @param ViewInterface $view
68
     */
69 35
    public function initializeView($view)
70
    {
71 35
        if ($view instanceof TemplateView) {
72 35
            $customTemplate = $this->getCustomTemplateFromConfiguration();
73 35
            if ($customTemplate === '') {
74 34
                return;
75
            }
76
77 1
            if (strpos($customTemplate, 'EXT:') !== false) {
78 1
                $view->setTemplatePathAndFilename($customTemplate);
79
            } else {
80
                $view->setTemplate($customTemplate);
81
            }
82
        }
83
    }
84
85
    /**
86
     * @return string
87
     */
88 35
    protected function getCustomTemplateFromConfiguration(): string
89
    {
90 35
        $templateKey = str_replace('Action', '', $this->actionMethodName);
91 35
        return $this->typoScriptConfiguration->getViewTemplateByFileKey($templateKey);
92
    }
93
94
    /**
95
     * Results
96
     * @return ResponseInterface
97
     * @throws AspectNotFoundException
98
     * @throws NoSuchArgumentException
99
     * @throws InvalidSlotException
100
     * @throws InvalidSlotReturnException
101
     */
102 33
    public function resultsAction(): ResponseInterface
103
    {
104
        try {
105 33
            $arguments = $this->request->getArguments();
106 33
            $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

106
            /** @scrutinizer ignore-call */ 
107
            $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...
107 33
            $languageId = Util::getLanguageUid();
108 33
            $searchRequest = $this->getSearchRequestBuilder()->buildForSearch($arguments, $pageId, $languageId);
109
110 33
            $searchResultSet = $this->searchService->search($searchRequest);
0 ignored issues
show
Bug introduced by
The method search() 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

110
            /** @scrutinizer ignore-call */ 
111
            $searchResultSet = $this->searchService->search($searchRequest);

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