Completed
Branch master (b22b71)
by Timo
13:13 queued 21s
created

ResultsCommand   A

Complexity

Total Complexity 35

Size/Duplication

Total Lines 360
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 12

Test Coverage

Coverage 75.69%

Importance

Changes 0
Metric Value
wmc 35
lcom 1
cbo 12
dl 0
loc 360
ccs 165
cts 218
cp 0.7569
rs 9
c 0
b 0
f 0

12 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 1
B execute() 0 42 1
A getParentPlugin() 0 4 1
A isFiltered() 0 7 2
C getResultDocuments() 0 50 8
A renderVariants() 0 15 3
B processDocumentFieldsToArray() 0 38 6
A renderDocumentFields() 0 19 3
B getPageBrowser() 0 39 4
A getPageBrowserLabels() 0 16 2
A getPageBrowserRange() 0 17 1
A isFilteredByUser() 0 11 3
1
<?php
2
namespace ApacheSolrForTypo3\Solr\Plugin\Results;
3
4
/***************************************************************
5
 *  Copyright notice
6
 *
7
 *  (c) 2009-2015 Ingo Renner <[email protected]>
8
 *  All rights reserved
9
 *
10
 *  This script is part of the TYPO3 project. The TYPO3 project is
11
 *  free software; you can redistribute it and/or modify
12
 *  it under the terms of the GNU General Public License as published by
13
 *  the Free Software Foundation; either version 2 of the License, or
14
 *  (at your option) any later version.
15
 *
16
 *  The GNU General Public License can be found at
17
 *  http://www.gnu.org/copyleft/gpl.html.
18
 *
19
 *  This script is distributed in the hope that it will be useful,
20
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
21
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22
 *  GNU General Public License for more details.
23
 *
24
 *  This copyright notice MUST APPEAR in all copies of the script!
25
 ***************************************************************/
26
27
use ApacheSolrForTypo3\Solr\Domain\Search\ResultSet\SearchResult;
28
use ApacheSolrForTypo3\Solr\Plugin\CommandPluginBase;
29
use ApacheSolrForTypo3\Solr\Plugin\PluginCommand;
30
use ApacheSolrForTypo3\Solr\ResultDocumentModifier\ResultDocumentModifier;
31
use ApacheSolrForTypo3\Solr\ResultsetModifier\ResultSetModifier;
32
use ApacheSolrForTypo3\Solr\Search;
33
use ApacheSolrForTypo3\Solr\Template;
34
use ApacheSolrForTypo3\Solr\Util;
35
use TYPO3\CMS\Core\Utility\GeneralUtility;
36
37
/**
38
 * Results view command
39
 *
40
 * @author Ingo Renner <[email protected]>
41
 */
42
class ResultsCommand implements PluginCommand
43
{
44
45
    /**
46
     * @var Search
47
     */
48
    protected $search;
49
50
    /**
51
     * Parent plugin
52
     *
53
     * @var Results
54
     */
55
    protected $parentPlugin;
56
57
    /**
58
     * Configuration
59
     *
60
     * @var array
61
     */
62
    protected $configuration;
63
64
    /**
65
     * Constructor.
66
     *
67
     * @param CommandPluginBase $parentPlugin Parent plugin object.
68
     */
69 18
    public function __construct(CommandPluginBase $parentPlugin)
70
    {
71 18
        $this->parentPlugin = $parentPlugin;
0 ignored issues
show
Documentation Bug introduced by
$parentPlugin is of type object<ApacheSolrForTypo...ugin\CommandPluginBase>, but the property $parentPlugin was declared to be of type object<ApacheSolrForTypo...Plugin\Results\Results>. Are you sure that you always receive this specific sub-class here, or does it make sense to add an instanceof check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a given class or a super-class is assigned to a property that is type hinted more strictly.

Either this assignment is in error or an instanceof check should be added for that assignment.

class Alien {}

class Dalek extends Alien {}

class Plot
{
    /** @var  Dalek */
    public $villain;
}

$alien = new Alien();
$plot = new Plot();
if ($alien instanceof Dalek) {
    $plot->villain = $alien;
}
Loading history...
72 18
        $this->configuration = $parentPlugin->typoScriptConfiguration;
0 ignored issues
show
Documentation Bug introduced by
It seems like $parentPlugin->typoScriptConfiguration of type object<ApacheSolrForTypo...ypoScriptConfiguration> is incompatible with the declared type array of property $configuration.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
73 18
        $this->search = $parentPlugin->getSearchResultSetService()->getSearch();
74 18
    }
75
76
    /**
77
     * @return array
78
     */
79 18
    public function execute()
80
    {
81 18
        $numberOfResults = $this->search->getNumberOfResults();
82
83 18
        $query = $this->search->getQuery();
84 18
        $rawQueryTerms = $query->getKeywordsRaw();
85 18
        $queryTerms = $query->getKeywordsCleaned();
86
87 18
        $searchedFor = strtr(
88 18
            $this->parentPlugin->pi_getLL('results_searched_for'),
89 18
            array('@searchWord' => '<span class="tx-solr-search-word">' . $queryTerms . '</span>')
90 18
        );
91
92 18
        $foundResultsInfo = strtr(
93 18
            $this->parentPlugin->pi_getLL('results_found'),
94
            array(
95 18
                '@resultsTotal' => $this->search->getNumberOfResults(),
96 18
                '@resultsTime' => $this->search->getQueryTime()
97 18
            )
98 18
        );
99
100
        return array(
101 18
            'searched_for' => $searchedFor,
102 18
            'query' => $queryTerms,
103 18
            'query_urlencoded' => rawurlencode($rawQueryTerms),
104 18
            'query_raw' => $rawQueryTerms,
105 18
            'found' => $foundResultsInfo,
106 18
            'range' => $this->getPageBrowserRange(),
107 18
            'count' => $this->search->getNumberOfResults(),
108 18
            'offset' => ($this->search->getResultOffset() + 1),
109 18
            'query_time' => $this->search->getQueryTime(),
110 18
            'pagebrowser' => $this->getPageBrowser($numberOfResults),
111 18
            'filtered' => $this->isFiltered(),
112 18
            'filtered_by_user' => $this->isFilteredByUser(),
113
            /* construction of the array key:
114
             * loop_ : tells the plugin that the content of that field should be processed in a loop
115
             * result_documents : is the loop name as in the template
116
             * result_document : is the marker name for the single items in the loop
117
             */
118 18
            'loop_result_documents|result_document' => $this->getResultDocuments()
119 18
        );
120
    }
121
122
    /**
123
     * @return \Apache_Solr_Document[]
124
     */
125 18
    protected function getResultDocuments()
126
    {
127 18
        $responseDocuments = $this->search->getResultDocumentsEscaped();
128 18
        $resultDocuments = array();
129
130 18
        if (is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['solr']['modifyResultSet'])) {
131 18
            foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['solr']['modifyResultSet'] as $classReference) {
132 18
                $resultSetModifier = GeneralUtility::getUserObj($classReference);
133
134 18
                if ($resultSetModifier instanceof ResultSetModifier) {
135 18
                    $responseDocuments = $resultSetModifier->modifyResultSet($this,
136 18
                        $responseDocuments);
137 18
                } else {
138
                    throw new \UnexpectedValueException(
139
                        get_class($resultSetModifier) . ' must implement interface ApacheSolrForTypo3\Solr\ResultsetModifier\ResultSetModifier',
140
                        1310386927
141
                    );
142
                }
143 18
            }
144 18
        }
145
146 18
        foreach ($responseDocuments as $resultDocument) {
147
            /** @var  $resultDocument SearchResult */
148 18
            $temporaryResultDocument = $this->processDocumentFieldsToArray($resultDocument);
149
150 18
            if (is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['solr']['modifyResultDocument'])) {
151 18
                foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['solr']['modifyResultDocument'] as $classReference) {
152 18
                    $resultDocumentModifier = GeneralUtility::getUserObj($classReference);
153
154 18
                    if ($resultDocumentModifier instanceof ResultDocumentModifier) {
155 18
                        $temporaryResultDocument = $resultDocumentModifier->modifyResultDocument($this,
156 18
                            $temporaryResultDocument);
157 18
                    } else {
158
                        throw new \UnexpectedValueException(
159
                            get_class($resultDocumentModifier) . ' must implement interface ApacheSolrForTypo3\Solr\ResultDocumentModifier\ResultDocumentModifier',
160
                            1310386725
161
                        );
162
                    }
163 18
                }
164 18
            }
165
166 18
            $renderedResultDocument = $this->renderDocumentFields($temporaryResultDocument);
167 18
            $renderedResultDocument = $this->renderVariants($resultDocument, $renderedResultDocument);
168
169 18
            $resultDocuments[] = $renderedResultDocument;
170 18
            unset($temporaryResultDocument);
171 18
        }
172
173 18
        return $resultDocuments;
174
    }
175
176
    /**
177
     * Renders the collapsedDocuments/variants of a document and adds them into the virtual field "variants".
178
     *
179
     * @param SearchResult $resultDocument
180
     * @param array $renderedResultDocument
181
     * @return mixed
182
     */
183 18
    protected function renderVariants(SearchResult $resultDocument, $renderedResultDocument)
184
    {
185 18
        $availableVariants = $resultDocument->getVariants();
186
187 18
        if (!is_array($availableVariants)) {
188
            return $renderedResultDocument;
189
        }
190
191 18
        foreach ($availableVariants as $expandedResult) {
192
            $expandedDocumentArray = $this->processDocumentFieldsToArray($expandedResult);
193
            $renderedResultDocument['variants'][] = $expandedDocumentArray;
194 18
        }
195
196 18
        return $renderedResultDocument;
197
    }
198
199
    /**
200
     * takes a search result document and processes its fields according to the
201
     * instructions configured in TS. Currently available instructions are
202
     *    * timestamp - converts a date field into a unix timestamp
203
     *    * serialize - uses serialize() to encode multivalue fields which then can be put out using the MULTIVALUE view helper
204
     *    * skip - skips the whole field so that it is not available in the result, useful for the spell field f.e.
205
     * The default is to do nothing and just add the document's field to the
206
     * resulting array.
207
     *
208
     * @param \Apache_Solr_Document $document the Apache_Solr_Document result document
209
     * @return array An array with field values processed like defined in TS
210
     */
211 18
    protected function processDocumentFieldsToArray(
212
        \Apache_Solr_Document $document
213
    ) {
214 18
        $processingInstructions = $this->configuration->getSearchResultsFieldProcessingInstructionsConfiguration();
0 ignored issues
show
Bug introduced by
The method getSearchResultsFieldPro...structionsConfiguration cannot be called on $this->configuration (of type array).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
215 18
        $availableFields = $document->getFieldNames();
216 18
        $result = array();
217
218 18
        foreach ($availableFields as $fieldName) {
219 18
            $processingInstruction = $processingInstructions[$fieldName];
220
221
            // TODO switch to field processors
222
            // TODO allow to have multiple (comma-separated) instructions for each field
223
            switch ($processingInstruction) {
224 18
                case 'timestamp':
225 18
                    $processedFieldValue = Util::isoToTimestamp($document->{$fieldName});
226 18
                    break;
227 18
                case 'serialize':
228
                    if (!empty($document->{$fieldName})) {
229
                        $processedFieldValue = serialize($document->{$fieldName});
230
                    } else {
231
                        $processedFieldValue = '';
232
                    }
233
                    break;
234 18
                case 'skip':
235
                    continue 2;
236 18
                default:
237 18
                    $processedFieldValue = $document->{$fieldName};
238 18
            }
239
240
            // escape markers in document fields
241
            // TODO remove after switching to fluid templates
242 18
            $processedFieldValue = Template::escapeMarkers($processedFieldValue);
243
244 18
            $result[$fieldName] = $processedFieldValue;
245 18
        }
246
247 18
        return $result;
248
    }
249
250
    /**
251
     * @param array $document
252
     * @return array
253
     */
254 18
    protected function renderDocumentFields(array $document)
255
    {
256 18
        $renderingInstructions = $this->configuration->getSearchResultsFieldRenderingInstructionsConfiguration();
0 ignored issues
show
Bug introduced by
The method getSearchResultsFieldRen...structionsConfiguration cannot be called on $this->configuration (of type array).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
257 18
        $cObj = GeneralUtility::makeInstance('TYPO3\\CMS\\Frontend\\ContentObject\\ContentObjectRenderer');
258 18
        $cObj->start($document);
259
260 18
        foreach ($renderingInstructions as $renderingInstructionName => $renderingInstruction) {
261 18
            if (!is_array($renderingInstruction)) {
262 18
                $renderedField = $cObj->cObjGetSingle(
263 18
                    $renderingInstructions[$renderingInstructionName],
264 18
                    $renderingInstructions[$renderingInstructionName . '.']
265 18
                );
266
267 18
                $document[$renderingInstructionName] = $renderedField;
268 18
            }
269 18
        }
270
271 18
        return $document;
272
    }
273
274
    /**
275
     * @param $numberOfResults
276
     * @return string
277
     */
278 18
    protected function getPageBrowser($numberOfResults)
279
    {
280 18
        $pageBrowserMarkup = '';
281 18
        $solrPageBrowserConfiguration = $this->configuration->getSearchResultsPageBrowserConfiguration();
0 ignored issues
show
Bug introduced by
The method getSearchResultsPageBrowserConfiguration cannot be called on $this->configuration (of type array).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
282
283 18
        if ($solrPageBrowserConfiguration['enabled']) {
284 18
            $resultsPerPage = $this->parentPlugin->getSearchResultSetService()->getLastResultSet()->getResultsPerPage();
285 18
            $numberOfPages = intval($numberOfResults / $resultsPerPage)
286 18
                + (($numberOfResults % $resultsPerPage) == 0 ? 0 : 1);
287
288 18
            $solrGetParameters = GeneralUtility::_GET('tx_solr');
289 18
            if (!is_array($solrGetParameters)) {
290 17
                $solrGetParameters = array();
291 17
            }
292 18
            $currentPage = $solrGetParameters['page'];
293 18
            unset($solrGetParameters['page']);
294
295 18
            $pageBrowserConfiguration = array_merge(
296 18
                $solrPageBrowserConfiguration,
297
                array(
298 18
                    'numberOfPages' => $numberOfPages,
299 18
                    'currentPage' => $currentPage,
300 18
                    'extraQueryString' => GeneralUtility::implodeArrayForUrl('tx_solr',
301 18
                        $solrGetParameters),
302 18
                    'templateFile' => $this->configuration->getTemplateByFileKey('pagebrowser')
0 ignored issues
show
Bug introduced by
The method getTemplateByFileKey cannot be called on $this->configuration (of type array).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
303 18
                )
304 18
            );
305
306 18
            $pageBrowser = GeneralUtility::makeInstance(
307 18
                'ApacheSolrForTypo3\\Solr\\Plugin\\Results\\PageBrowser',
308 18
                $pageBrowserConfiguration,
309 18
                $this->getPageBrowserLabels()
310 18
            );
311
312 18
            $pageBrowserMarkup = $pageBrowser->render();
313 18
        }
314
315 18
        return $pageBrowserMarkup;
316
    }
317
318
    /**
319
     * Gets the labels for us in the page browser
320
     *
321
     * @return array page browser labels
322
     */
323 18
    protected function getPageBrowserLabels()
324
    {
325
        $labelKeys = array(
326 18
            'pagebrowser_first',
327 18
            'pagebrowser_next',
328 18
            'pagebrowser_prev',
329
            'pagebrowser_last'
330 18
        );
331
332 18
        $labels = array();
333 18
        foreach ($labelKeys as $labelKey) {
334 18
            $labels[$labelKey] = $this->parentPlugin->pi_getLL($labelKey);
335 18
        }
336
337 18
        return $labels;
338
    }
339
340
    /**
341
     * @return string
342
     */
343 18
    protected function getPageBrowserRange()
344
    {
345 18
        $resultsFrom = $this->search->getResponseBody()->start + 1;
346 18
        $resultsTo = $resultsFrom + count($this->search->getResultDocumentsEscaped()) - 1;
347 18
        $resultsTotal = $this->search->getNumberOfResults();
348
349 18
        $label = strtr(
350 18
            $this->parentPlugin->pi_getLL('results_range'),
351
            array(
352 18
                '@resultsFrom' => $resultsFrom,
353 18
                '@resultsTo' => $resultsTo,
354
                '@resultsTotal' => $resultsTotal
355 18
            )
356 18
        );
357
358 18
        return $label;
359
    }
360
361
    /**
362
     * Gets the parent plugin.
363
     *
364
     * @return Results
365
     */
366 18
    public function getParentPlugin()
367
    {
368 18
        return $this->parentPlugin;
369
    }
370
371
    /**
372
     * Determines whether filters have been applied to the query or not.
373
     *
374
     * @return string 1 if filters are applied, 0 if not (for use in templates)
375
     */
376 18
    protected function isFiltered()
377
    {
378 18
        $filters = $this->search->getQuery()->getFilters();
379 18
        $filtered = !empty($filters);
380
381 18
        return ($filtered ? '1' : '0');
382
    }
383
384
    /**
385
     * Determines whether filters have been applied by the user (facets for
386
     * example) to the query or not.
387
     *
388
     * @return string 1 if filters are applied, 0 if not (for use in templates)
389
     */
390 18
    protected function isFilteredByUser()
391
    {
392 18
        $userFiltered = false;
393 18
        $resultParameters = GeneralUtility::_GET('tx_solr');
394
395 18
        if (isset($resultParameters['filter'])) {
396 1
            $userFiltered = true;
397 1
        }
398
399 18
        return ($userFiltered ? '1' : '0');
400
    }
401
}
402