Completed
Push — master ( 366a5b...a17b2a )
by
unknown
17:34 queued 14:29
created

Search::addFacetsMenu()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 24

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
nc 4
nop 0
dl 0
loc 24
rs 9.536
c 0
b 0
f 0
1
<?php
2
namespace Kitodo\Dlf\Plugin;
3
4
/**
5
 * (c) Kitodo. Key to digital objects e.V. <[email protected]>
6
 *
7
 * This file is part of the Kitodo and TYPO3 projects.
8
 *
9
 * @license GNU General Public License version 3 or later.
10
 * For the full copyright and license information, please read the
11
 * LICENSE.txt file that was distributed with this source code.
12
 */
13
14
use Kitodo\Dlf\Common\Document;
15
use Kitodo\Dlf\Common\DocumentList;
16
use Kitodo\Dlf\Common\Helper;
17
use Kitodo\Dlf\Common\Indexer;
18
use Kitodo\Dlf\Common\Solr;
19
20
/**
21
 * Plugin 'Search' for the 'dlf' extension
22
 *
23
 * @author Sebastian Meyer <[email protected]>
24
 * @author Henrik Lochmann <[email protected]>
25
 * @author Frank Ulrich Weber <[email protected]>
26
 * @package TYPO3
27
 * @subpackage dlf
28
 * @access public
29
 */
30
class Search extends \Kitodo\Dlf\Common\AbstractPlugin {
31
    public $scriptRelPath = 'Classes/Plugin/Search.php';
32
33
    /**
34
     * Adds the JS files necessary for search suggestions
35
     *
36
     * @access protected
37
     *
38
     * @return void
39
     */
40
    protected function addAutocompleteJS() {
41
        // Check if there are any metadata to suggest.
42
        $result = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
43
            'tx_dlf_metadata.*',
44
            'tx_dlf_metadata',
45
            'tx_dlf_metadata.index_autocomplete=1'
46
                .' AND tx_dlf_metadata.pid='.intval($this->conf['pages'])
47
                .Helper::whereClause('tx_dlf_metadata'),
48
            '',
49
            '',
50
            '1'
51
        );
52
        if ($GLOBALS['TYPO3_DB']->sql_num_rows($result)) {
53
            $GLOBALS['TSFE']->additionalHeaderData[$this->prefixId.'_search_suggest'] = '<script type="text/javascript" src="'.\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::siteRelPath($this->extKey).'Resources/Public/Javascript/Search/Suggester.js"></script>';
54
        } else {
55
            Helper::devLog('No metadata fields configured for search suggestions', DEVLOG_SEVERITY_WARNING);
56
        }
57
    }
58
59
    /**
60
     * Adds the current collection's UID to the search form
61
     *
62
     * @access protected
63
     *
64
     * @return string HTML input fields with current document's UID and parent ID
65
     */
66
    protected function addCurrentCollection() {
67
        // Load current collection.
68
        $list = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(DocumentList::class);
69
        if (!empty($list->metadata['options']['source'])
70
            && $list->metadata['options']['source'] == 'collection') {
71
            // Get collection's UID.
72
            return '<input type="hidden" name="'.$this->prefixId.'[collection]" value="'.$list->metadata['options']['select'].'" />';
73 View Code Duplication
        } elseif (!empty($list->metadata['options']['params']['filterquery'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
74
            // Get collection's UID from search metadata.
75
            foreach ($list->metadata['options']['params']['filterquery'] as $facet) {
76
                $facetKeyVal = explode(':', $facet['query'], 2);
77
                if ($facetKeyVal[0] == 'collection_faceting'
78
                    && !strpos($facetKeyVal[1], '" OR "')) {
79
                    $collectionId = Helper::getUidFromIndexName(trim($facetKeyVal[1], '(")'), 'tx_dlf_collections');
80
                }
81
            }
82
            return '<input type="hidden" name="'.$this->prefixId.'[collection]" value="'.$collectionId.'" />';
0 ignored issues
show
Bug introduced by
The variable $collectionId does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
83
        }
84
        return '';
85
    }
86
87
    /**
88
     * Adds the current document's UID or parent ID to the search form
89
     *
90
     * @access protected
91
     *
92
     * @return string HTML input fields with current document's UID and parent ID
93
     */
94
    protected function addCurrentDocument() {
95
        // Load current list object.
96
        $list = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(DocumentList::class);
97
        // Load current document.
98
        if (!empty($this->piVars['id'])
99
            && \TYPO3\CMS\Core\Utility\MathUtility::canBeInterpretedAsInteger($this->piVars['id'])) {
100
            $this->loadDocument();
101
            // Get document's UID or parent ID.
102
            if ($this->doc->ready) {
0 ignored issues
show
Documentation introduced by
The property $ready is declared protected in Kitodo\Dlf\Common\Document. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
103
                return '<input type="hidden" name="'.$this->prefixId.'[id]" value="'.($this->doc->parentId > 0 ? $this->doc->parentId : $this->doc->uid).'" />';
0 ignored issues
show
Documentation introduced by
The property $parentId is declared protected in Kitodo\Dlf\Common\Document. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
Documentation introduced by
The property $uid is declared protected in Kitodo\Dlf\Common\Document. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
104
            }
105 View Code Duplication
        } elseif (!empty($list->metadata['options']['params']['filterquery'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
106
            // Get document's UID from search metadata.
107
            foreach ($list->metadata['options']['params']['filterquery'] as $facet) {
108
                $facetKeyVal = explode(':', $facet['query']);
109
                if ($facetKeyVal[0] == 'uid') {
110
                    $documentId = (int) substr($facetKeyVal[1], 1, strpos($facetKeyVal[1], ')'));
111
                }
112
            }
113
            return '<input type="hidden" name="'.$this->prefixId.'[id]" value="'.$documentId.'" />';
0 ignored issues
show
Bug introduced by
The variable $documentId does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
114
        }
115
        return '';
116
    }
117
118
    /**
119
     * Adds the encrypted Solr core name to the search form
120
     *
121
     * @access protected
122
     *
123
     * @return string HTML input fields with encrypted core name and hash
124
     */
125
    protected function addEncryptedCoreName() {
126
        // Get core name.
127
        $name = Helper::getIndexNameFromUid($this->conf['solrcore'], 'tx_dlf_solrcores');
128
        // Encrypt core name.
129
        if (!empty($name)) {
130
            $name = Helper::encrypt($name);
131
        }
132
        // Add encrypted fields to search form.
133
        if (is_array($name)) {
134
            return '<input type="hidden" name="'.$this->prefixId.'[encrypted]" value="'.$name['encrypted'].'" /><input type="hidden" name="'.$this->prefixId.'[hashed]" value="'.$name['hash'].'" />';
135
        } else {
136
            return '';
137
        }
138
    }
139
140
    /**
141
     * Returns the extended search form and adds the JS files necessary for extended search.
142
     *
143
     * @access protected
144
     *
145
     * @return string The extended search form or an empty string
146
     */
147
    protected function addExtendedSearch() {
148
        $extendedSearch = '';
149
        // Quit without doing anything if no fields for extended search are selected.
150
        if (empty($this->conf['extendedSlotCount'])
151
            || empty($this->conf['extendedFields'])) {
152
            return $extendedSearch;
153
        }
154
        // Get operator options.
155
        $operatorOptions = '';
156
        foreach (['AND', 'OR', 'NOT'] as $operator) {
157
            $operatorOptions .= '<option class="tx-dlf-search-operator-option tx-dlf-search-operator-'.$operator.'" value="'.$operator.'">'.$this->pi_getLL($operator, '', TRUE).'</option>';
158
        }
159
        // Get field selector options.
160
        $fieldSelectorOptions = '';
161
        $searchFields = \TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode(',', $this->conf['extendedFields'], TRUE);
162
        foreach ($searchFields as $searchField) {
163
            $fieldSelectorOptions .= '<option class="tx-dlf-search-field-option tx-dlf-search-field-'.$searchField.'" value="'.$searchField.'">'.Helper::translate($searchField, 'tx_dlf_metadata', $this->conf['pages']).'</option>';
164
        }
165
        for ($i = 0; $i < $this->conf['extendedSlotCount']; $i++) {
166
            $markerArray = [
167
                '###EXT_SEARCH_OPERATOR###' => '<select class="tx-dlf-search-operator tx-dlf-search-operator-'.$i.'" name="'.$this->prefixId.'[extOperator]['.$i.']">'.$operatorOptions.'</select>',
168
                '###EXT_SEARCH_FIELDSELECTOR###' => '<select class="tx-dlf-search-field tx-dlf-search-field-'.$i.'" name="'.$this->prefixId.'[extField]['.$i.']">'.$fieldSelectorOptions.'</select>',
169
                '###EXT_SEARCH_FIELDQUERY###' => '<input class="tx-dlf-search-query tx-dlf-search-query-'.$i.'" type="text" name="'.$this->prefixId.'[extQuery]['.$i.']" />'
170
            ];
171
            $extendedSearch .= $this->cObj->substituteMarkerArray($this->cObj->getSubpart($this->template, '###EXT_SEARCH_ENTRY###'), $markerArray);
0 ignored issues
show
Deprecated Code introduced by
The method TYPO3\CMS\Frontend\Conte...tRenderer::getSubpart() has been deprecated with message: since TYPO3 v8, will be removed in TYPO3 v9, please use the MarkerBasedTemplateService instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
Deprecated Code introduced by
The method TYPO3\CMS\Frontend\Conte...substituteMarkerArray() has been deprecated with message: since TYPO3 v8, will be removed in TYPO3 v9, please use the MarkerBasedTemplateService instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
172
        }
173
        return $extendedSearch;
174
    }
175
176
    /**
177
     * Adds the facets menu to the search form
178
     *
179
     * @access protected
180
     *
181
     * @return string HTML output of facets menu
182
     */
183
    protected function addFacetsMenu() {
184
        // Check for typoscript configuration to prevent fatal error.
185
        if (empty($this->conf['facetsConf.'])) {
186
            Helper::devLog('Incomplete plugin configuration', DEVLOG_SEVERITY_WARNING);
187
            return '';
188
        }
189
        // Quit without doing anything if no facets are selected.
190
        if (empty($this->conf['facets'])) {
191
            return '';
192
        }
193
        // Get facets from plugin configuration.
194
        $facets = [];
195
        foreach (\TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode(',', $this->conf['facets'], TRUE) as $facet) {
196
            $facets[$facet.'_faceting'] = Helper::translate($facet, 'tx_dlf_metadata', $this->conf['pages']);
197
        }
198
        // Render facets menu.
199
        $TSconfig = [];
200
        $TSconfig['special'] = 'userfunction';
201
        $TSconfig['special.']['userFunc'] = \Kitodo\Dlf\Plugin\Search::class.'->makeFacetsMenuArray';
202
        $TSconfig['special.']['facets'] = $facets;
203
        $TSconfig['special.']['limit'] = max(intval($this->conf['limitFacets']), 1);
204
        $TSconfig = Helper::mergeRecursiveWithOverrule($this->conf['facetsConf.'], $TSconfig);
205
        return $this->cObj->cObjGetSingle('HMENU', $TSconfig);
206
    }
207
208
    /**
209
     * Adds the fulltext switch to the search form
210
     *
211
     * @access protected
212
     *
213
     * @param integer $isFulltextSearch: Is fulltext search activated?
0 ignored issues
show
Documentation introduced by
There is no parameter named $isFulltextSearch:. Did you maybe mean $isFulltextSearch?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.

Consider the following example. The parameter $ireland is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $ireland
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was changed, but the annotation was not.

Loading history...
214
     *
215
     * @return string HTML output of fulltext switch
216
     */
217
    protected function addFulltextSwitch($isFulltextSearch = 0) {
218
        $output = '';
219
        // Check for plugin configuration.
220
        if (!empty($this->conf['fulltext'])) {
221
            $output .= ' <input class="tx-dlf-search-fulltext" id="tx-dlf-search-fulltext-no" type="radio" name="'.$this->prefixId.'[fulltext]" value="0" '.($isFulltextSearch == 0 ? 'checked="checked"' : '').' />';
222
            $output .= ' <label for="tx-dlf-search-fulltext-no">'.$this->pi_getLL('label.inMetadata', '').'</label>';
223
            $output .= ' <input class="tx-dlf-search-fulltext" id="tx-dlf-search-fulltext-yes" type="radio" name="'.$this->prefixId.'[fulltext]" value="1" '.($isFulltextSearch == 1 ? 'checked="checked"' : '').'/>';
224
            $output .= ' <label for="tx-dlf-search-fulltext-yes">'.$this->pi_getLL('label.inFulltext', '').'</label>';
225
        }
226
        return $output;
227
    }
228
229
    /**
230
     * Adds the logical page field to the search form
231
     *
232
     * @access protected
233
     *
234
     * @return string HTML output of logical page field
235
     */
236
    protected function addLogicalPage() {
237
        $output = '';
238
        // Check for plugin configuration.
239
        if (!empty($this->conf['showLogicalPageField'])) {
240
            $output .= ' <label for="tx-dlf-search-logical-page">'.$this->pi_getLL('label.logicalPage', '').': </label>';
241
            $output .= ' <input class="tx-dlf-search-logical-page" id="tx-dlf-search-logical-page" type="text" name="'.$this->prefixId.'[logicalPage]" />';
242
        }
243
        return $output;
244
    }
245
246
    /**
247
     * Creates an array for a HMENU entry of a facet value.
248
     *
249
     * @access protected
250
     *
251
     * @param string $field: The facet's index_name
0 ignored issues
show
Documentation introduced by
There is no parameter named $field:. Did you maybe mean $field?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.

Consider the following example. The parameter $ireland is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $ireland
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was changed, but the annotation was not.

Loading history...
252
     * @param string $value: The facet's value
0 ignored issues
show
Documentation introduced by
There is no parameter named $value:. Did you maybe mean $value?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.

Consider the following example. The parameter $ireland is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $ireland
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was changed, but the annotation was not.

Loading history...
253
     * @param integer $count: Number of hits for this facet
0 ignored issues
show
Documentation introduced by
There is no parameter named $count:. Did you maybe mean $count?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.

Consider the following example. The parameter $ireland is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $ireland
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was changed, but the annotation was not.

Loading history...
254
     * @param array $search: The parameters of the current search query
0 ignored issues
show
Documentation introduced by
There is no parameter named $search:. Did you maybe mean $search?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.

Consider the following example. The parameter $ireland is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $ireland
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was changed, but the annotation was not.

Loading history...
255
     * @param string &$state: The state of the parent item
256
     *
257
     * @return array The array for the facet's menu entry
258
     */
259
    protected function getFacetsMenuEntry($field, $value, $count, $search, &$state) {
260
        $entryArray = [];
261
        // Translate value.
262
        if ($field == 'owner_faceting') {
263
            // Translate name of holding library.
264
            $entryArray['title'] = htmlspecialchars(Helper::translate($value, 'tx_dlf_libraries', $this->conf['pages']));
265
        } elseif ($field == 'type_faceting') {
266
            // Translate document type.
267
            $entryArray['title'] = htmlspecialchars(Helper::translate($value, 'tx_dlf_structures', $this->conf['pages']));
268
        } elseif ($field == 'collection_faceting') {
269
            // Translate name of collection.
270
            $entryArray['title'] = htmlspecialchars(Helper::translate($value, 'tx_dlf_collections', $this->conf['pages']));
271
        } elseif ($field == 'language_faceting') {
272
            // Translate ISO 639 language code.
273
            $entryArray['title'] = htmlspecialchars(Helper::getLanguageName($value));
274
        } else {
275
            $entryArray['title'] = htmlspecialchars($value);
276
        }
277
        $entryArray['count'] = $count;
278
        $entryArray['doNotLinkIt'] = 0;
279
        // Check if facet is already selected.
280
        $queryColumn = array_column($search['params']['filterquery'], 'query');
281
        $index = array_search($field.':("'.Solr::escapeQuery($value).'")', $queryColumn);
282
        if ($index !== FALSE) {
283
            // Facet is selected, thus remove it from filter.
284
            unset($queryColumn[$index]);
285
            $queryColumn = array_values($queryColumn);
286
            $entryArray['ITEM_STATE'] = 'CUR';
287
            $state = 'ACTIFSUB';
288
            //Reset facets
289
            if ($this->conf['resetFacets']) {
290
                //remove ($count) for selected facet in template
291
                $entryArray['count'] = FALSE;
292
                //build link to delete selected facet
293
                $entryArray['_OVERRIDE_HREF'] = $this->pi_linkTP_keepPIvars_url(['query' => $search['query'], 'fq' => $queryColumn]);
294
                $entryArray['title'] = sprintf($this->pi_getLL('resetFacet', ''), $entryArray['title']);
295
            }
296
        } else {
297
            // Facet is not selected, thus add it to filter.
298
            $queryColumn[] = $field.':("'.Solr::escapeQuery($value).'")';
299
            $entryArray['ITEM_STATE'] = 'NO';
300
        }
301
        $entryArray['_OVERRIDE_HREF'] = $this->pi_linkTP_keepPIvars_url(['query' => $search['query'], 'fq' => $queryColumn]);
302
        return $entryArray;
303
    }
304
305
    /**
306
     * The main method of the PlugIn
307
     *
308
     * @access public
309
     *
310
     * @param string $content: The PlugIn content
0 ignored issues
show
Documentation introduced by
There is no parameter named $content:. Did you maybe mean $content?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.

Consider the following example. The parameter $ireland is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $ireland
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was changed, but the annotation was not.

Loading history...
311
     * @param array $conf: The PlugIn configuration
0 ignored issues
show
Bug introduced by
There is no parameter named $conf:. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
312
     *
313
     * @return string The content that is displayed on the website
314
     */
315
    public function main($content, $conf) {
316
        $this->init($conf);
317
        // Disable caching for this plugin.
318
        $this->setCache(FALSE);
319
        // Quit without doing anything if required variables are not set.
320
        if (empty($this->conf['solrcore'])) {
321
            Helper::devLog('Incomplete plugin configuration', DEVLOG_SEVERITY_WARNING);
322
            return $content;
323
        }
324
        if (!isset($this->piVars['query'])
325
            && empty($this->piVars['extQuery'])) {
326
            // Extract query and filter from last search.
327
            $list = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(DocumentList::class);
328 View Code Duplication
            if (!empty($list->metadata['searchString'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
329
                if ($list->metadata['options']['source'] == 'search') {
330
                    $search['query'] = $list->metadata['searchString'];
0 ignored issues
show
Coding Style Comprehensibility introduced by
$search was never initialized. Although not strictly required by PHP, it is generally a good practice to add $search = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
331
                }
332
                $search['params'] = $list->metadata['options']['params'];
0 ignored issues
show
Bug introduced by
The variable $search does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
333
            }
334
            // Add javascript for search suggestions if enabled and jQuery autocompletion is available.
335
            if (!empty($this->conf['suggest'])) {
336
                $this->addAutocompleteJS();
337
            }
338
            // Load template file.
339
            $this->getTemplate();
340
            // Configure @action URL for form.
341
            $linkConf = [
342
                'parameter' => $GLOBALS['TSFE']->id
343
            ];
344
            // Fill markers.
345
            $markerArray = [
346
                '###ACTION_URL###' => $this->cObj->typoLink_URL($linkConf),
347
                '###LABEL_QUERY###' => (!empty($search['query']) ? htmlspecialchars($search['query']) : $this->pi_getLL('label.query')),
348
                '###LABEL_SUBMIT###' => $this->pi_getLL('label.submit'),
349
                '###FIELD_QUERY###' => $this->prefixId.'[query]',
350
                '###QUERY###' => (!empty($search['query']) ? $search['query'] : ''),
351
                '###FULLTEXTSWITCH###' => $this->addFulltextSwitch($list->metadata['fulltextSearch']),
352
                '###FIELD_DOC###' => ($this->conf['searchIn'] == 'document' || $this->conf['searchIn'] == 'all' ? $this->addCurrentDocument() : ''),
353
                '###FIELD_COLL###' => ($this->conf['searchIn'] == 'collection' || $this->conf['searchIn'] == 'all' ? $this->addCurrentCollection() : ''),
354
                '###ADDITIONAL_INPUTS###' => $this->addEncryptedCoreName(),
355
                '###FACETS_MENU###' => $this->addFacetsMenu(),
356
                '###LOGICAL_PAGE###' => $this->addLogicalPage()
357
            ];
358
            // Get additional fields for extended search.
359
            $extendedSearch = $this->addExtendedSearch();
360
            // Display search form.
361
            $content .= $this->cObj->substituteSubpart($this->cObj->substituteMarkerArray($this->template, $markerArray), '###EXT_SEARCH_ENTRY###', $extendedSearch);
0 ignored issues
show
Deprecated Code introduced by
The method TYPO3\CMS\Frontend\Conte...substituteMarkerArray() has been deprecated with message: since TYPO3 v8, will be removed in TYPO3 v9, please use the MarkerBasedTemplateService instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
Deprecated Code introduced by
The method TYPO3\CMS\Frontend\Conte...er::substituteSubpart() has been deprecated with message: since TYPO3 v8, will be removed in TYPO3 v9, please use the MarkerBasedTemplateService instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
362
            return $this->pi_wrapInBaseClass($content);
363
        } else {
364
            // Instantiate search object.
365
            $solr = Solr::getInstance($this->conf['solrcore']);
366
            if (!$solr->ready) {
0 ignored issues
show
Documentation introduced by
The property $ready is declared protected in Kitodo\Dlf\Common\Solr. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
367
                Helper::devLog('Apache Solr not available', DEVLOG_SEVERITY_ERROR);
368
                return $content;
369
            }
370
            // Build label for result list.
371
            $label = $this->pi_getLL('search', '', TRUE);
372
            if (!empty($this->piVars['query'])) {
373
                $label .= htmlspecialchars(sprintf($this->pi_getLL('for', ''), $this->piVars['query']));
374
            }
375
            // Prepare query parameters.
376
            $params = [];
377
            $matches = [];
378
            // Set search query.
379
            if ((!empty($this->conf['fulltext']) && !empty($this->piVars['fulltext']))
380
                || preg_match('/fulltext:\((.*)\)/', $this->piVars['query'], $matches)) {
381
                // If the query already is a fulltext query e.g using the facets
382
                $this->piVars['query'] = empty($matches[1]) ? $this->piVars['query'] : $matches[1];
383
                // Search in fulltext field if applicable. query must not be empty!
384
                if (!empty($this->piVars['query'])) {
385
                    $query = 'fulltext:('.Solr::escapeQuery($this->piVars['query']).')';
386
                }
387
            } else {
388
                // Retain given search field if valid.
389
                $query = Solr::escapeQueryKeepField($this->piVars['query'], $this->conf['pages']);
390
            }
391
            // Add extended search query.
392
            if (!empty($this->piVars['extQuery'])
393
                && is_array($this->piVars['extQuery'])) {
394
                $allowedOperators = ['AND', 'OR', 'NOT'];
395
                $allowedFields = \TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode(',', $this->conf['extendedFields'], TRUE);
396
                for ($i = 0; $i < count($this->piVars['extQuery']); $i++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
397
                    if (!empty($this->piVars['extQuery'][$i])) {
398
                        if (in_array($this->piVars['extOperator'][$i], $allowedOperators)
399
                            && in_array($this->piVars['extField'][$i], $allowedFields)) {
400
                            if (!empty($query)) {
401
                                $query .= ' '.$this->piVars['extOperator'][$i].' ';
402
                            }
403
                            $query .= Indexer::getIndexFieldName($this->piVars['extField'][$i], $this->conf['pages']).':('.Solr::escapeQuery($this->piVars['extQuery'][$i]).')';
0 ignored issues
show
Bug introduced by
The variable $query does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
404
                        }
405
                    }
406
                }
407
            }
408
            // Add filter query for faceting.
409
            if (!empty($this->piVars['fq'])) {
410
                foreach ($this->piVars['fq'] as $filterQuery) {
411
                    $params['filterquery'][]['query'] = $filterQuery;
412
                }
413
            }
414
            // Add filter query for in-document searching.
415
            if ($this->conf['searchIn'] == 'document'
416
                || $this->conf['searchIn'] == 'all') {
417
                if (!empty($this->piVars['id'])
418
                    && \TYPO3\CMS\Core\Utility\MathUtility::canBeInterpretedAsInteger($this->piVars['id'])) {
419
                    $params['filterquery'][]['query'] = 'uid:('.$this->piVars['id'].') OR partof:('.$this->piVars['id'].')';
420
                    $label .= htmlspecialchars(sprintf($this->pi_getLL('in', ''), Document::getTitle($this->piVars['id'])));
421
                }
422
            }
423
            // Add filter query for in-collection searching.
424
            if ($this->conf['searchIn'] == 'collection'
425
                || $this->conf['searchIn'] == 'all') {
426
                if (!empty($this->piVars['collection'])
427
                    && \TYPO3\CMS\Core\Utility\MathUtility::canBeInterpretedAsInteger($this->piVars['collection'])) {
428
                    $index_name = Helper::getIndexNameFromUid($this->piVars['collection'], 'tx_dlf_collections', $this->conf['pages']);
429
                    $params['filterquery'][]['query'] = 'collection_faceting:("'.Solr::escapeQuery($index_name).'")';
430
                    $label .= sprintf($this->pi_getLL('in', '', TRUE), Helper::translate($index_name, 'tx_dlf_collections', $this->conf['pages']));
431
                }
432
            }
433
            // Add filter query for collection restrictions.
434
            if ($this->conf['collections']) {
435
                $collIds = explode(',', $this->conf['collections']);
436
                $collIndexNames = [];
437
                foreach ($collIds as $collId) {
438
                    $collIndexNames[] = Solr::escapeQuery(Helper::getIndexNameFromUid(intval($collId), 'tx_dlf_collections', $this->conf['pages']));
439
                }
440
                // Last value is fake and used for distinction in $this->addCurrentCollection()
441
                $params['filterquery'][]['query'] = 'collection_faceting:("'.implode('" OR "', $collIndexNames).'" OR "FakeValueForDistinction")';
442
            }
443
            // Set some query parameters.
444
            $params['query'] = $query;
445
            $params['start'] = 0;
446
            $params['rows'] = 0;
447
            $params['sort'] = ['score' => 'desc'];
448
            // Instantiate search object.
449
            $solr = Solr::getInstance($this->conf['solrcore']);
450
            if (!$solr->ready) {
0 ignored issues
show
Documentation introduced by
The property $ready is declared protected in Kitodo\Dlf\Common\Solr. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
451
                Helper::devLog('Apache Solr not available', DEVLOG_SEVERITY_ERROR);
452
                return $content;
453
            }
454
            // Set search parameters.
455
            $solr->cPid = $this->conf['pages'];
0 ignored issues
show
Documentation introduced by
The property $cPid is declared protected in Kitodo\Dlf\Common\Solr. Since you implemented __set(), maybe consider adding a @property or @property-write annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
456
            $solr->params = $params;
0 ignored issues
show
Documentation introduced by
The property $params is declared protected in Kitodo\Dlf\Common\Solr. Since you implemented __set(), maybe consider adding a @property or @property-write annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
457
            // Perform search.
458
            $list = $solr->search();
459
            $list->metadata = [
0 ignored issues
show
Documentation introduced by
The property $metadata is declared protected in Kitodo\Dlf\Common\DocumentList. Since you implemented __set(), maybe consider adding a @property or @property-write annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
460
                'label' => $label,
461
                'thumbnail' => '',
462
                'searchString' => $this->piVars['query'],
463
                'fulltextSearch' => (!empty($this->piVars['fulltext']) ? '1' : '0'),
464
                'options' => $list->metadata['options']
0 ignored issues
show
Documentation introduced by
The property $metadata is declared protected in Kitodo\Dlf\Common\DocumentList. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
465
            ];
466
            $list->save();
467
            // Clean output buffer.
468
            ob_end_clean();
469
            $additionalParams = [];
470
            if (!empty($this->piVars['logicalPage'])) {
471
                $additionalParams['logicalPage'] = $this->piVars['logicalPage'];
472
            }
473
            // Jump directly to the page view, if there is only one result and it is configured
474
            if ($list->metadata['options']['numberOfHits'] == 1 && !empty($this->conf['showSingleResult'])) {
0 ignored issues
show
Documentation introduced by
The property $metadata is declared protected in Kitodo\Dlf\Common\DocumentList. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
475
                $linkConf['parameter'] = $this->conf['targetPidPageView'];
0 ignored issues
show
Coding Style Comprehensibility introduced by
$linkConf was never initialized. Although not strictly required by PHP, it is generally a good practice to add $linkConf = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
476
                $additionalParams['id'] = $list->current()['uid'];
477
                $additionalParams['highlight_word'] = preg_replace('/\s\s+/', ';', $list->metadata['searchString']);
0 ignored issues
show
Documentation introduced by
The property $metadata is declared protected in Kitodo\Dlf\Common\DocumentList. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
478
                $additionalParams['page'] = count($list[0]['subparts']) == 1 ? $list[0]['subparts'][0]['page'] : 1;
479
            } else {
480
                // Keep some plugin variables.
481
                $linkConf['parameter'] = $this->conf['targetPid'];
0 ignored issues
show
Coding Style Comprehensibility introduced by
$linkConf was never initialized. Although not strictly required by PHP, it is generally a good practice to add $linkConf = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
482
                if (!empty($this->piVars['order'])) {
483
                    $additionalParams['order'] = $this->piVars['order'];
484
                    $additionalParams['asc'] = !empty($this->piVars['asc']) ? '1' : '0';
485
                }
486
            }
487
            $linkConf['additionalParams'] = \TYPO3\CMS\Core\Utility\GeneralUtility::implodeArrayForUrl($this->prefixId, $additionalParams, '', TRUE, FALSE);
488
            // Send headers.
489
            header('Location: '.\TYPO3\CMS\Core\Utility\GeneralUtility::locationHeaderUrl($this->cObj->typoLink_URL($linkConf)));
490
            exit;
491
        }
492
    }
493
494
    /**
495
     * This builds a menu array for HMENU
496
     *
497
     * @access public
498
     *
499
     * @param string $content: The PlugIn content
0 ignored issues
show
Documentation introduced by
There is no parameter named $content:. Did you maybe mean $content?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.

Consider the following example. The parameter $ireland is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $ireland
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was changed, but the annotation was not.

Loading history...
500
     * @param array $conf: The PlugIn configuration
0 ignored issues
show
Bug introduced by
There is no parameter named $conf:. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
501
     *
502
     * @return array HMENU array
503
     */
504
    public function makeFacetsMenuArray($content, $conf) {
0 ignored issues
show
Unused Code introduced by
The parameter $content is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
505
        $this->init($conf);
506
        $menuArray = [];
507
        // Set default value for facet search.
508
        $search = [
509
            'query' => '*',
510
            'params' => [
511
                'component' => [
512
                    'facetset' => [
513
                        'facet' => []
514
                    ]
515
                ]
516
            ]
517
        ];
518
        // Extract query and filter from last search.
519
        $list = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(DocumentList::class);
520 View Code Duplication
        if (!empty($list->metadata['options']['source'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
521
            if ($list->metadata['options']['source'] == 'search') {
522
                $search['query'] = $list->metadata['options']['select'];
523
            }
524
            $search['params'] = $list->metadata['options']['params'];
525
        }
526
        // Get applicable facets.
527
        $solr = Solr::getInstance($this->conf['solrcore']);
528
        if (!$solr->ready) {
0 ignored issues
show
Documentation introduced by
The property $ready is declared protected in Kitodo\Dlf\Common\Solr. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
529
            Helper::devLog('Apache Solr not available', DEVLOG_SEVERITY_ERROR);
530
            return [];
531
        }
532
        // Set needed parameters for facet search.
533
        if (empty($search['params']['filterquery'])) {
534
            $search['params']['filterquery'] = [];
535
        }
536
        foreach (array_keys($this->conf['facets']) as $field) {
537
            $search['params']['component']['facetset']['facet'][] = [
538
                'type' => 'field',
539
                'key' => $field,
540
                'field' => $field,
541
                'limit' => $this->conf['limitFacets'],
542
                'sort' => isset($this->conf['sortingFacets']) ? $this->conf['sortingFacets'] : 'count'
543
            ];
544
        }
545
        // Set additional query parameters.
546
        $search['params']['start'] = 0;
547
        $search['params']['rows'] = 0;
548
        // Set query.
549
        $search['params']['query'] = $search['query'];
550
        // Perform search.
551
        $selectQuery = $solr->service->createSelect($search['params']);
0 ignored issues
show
Documentation introduced by
The property $service is declared protected in Kitodo\Dlf\Common\Solr. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
552
        $results = $solr->service->select($selectQuery);
0 ignored issues
show
Documentation introduced by
The property $service is declared protected in Kitodo\Dlf\Common\Solr. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
553
        $facet = $results->getFacetSet();
554
        // Process results.
555
        foreach ($facet as $field => $values) {
0 ignored issues
show
Bug introduced by
The expression $facet of type object<Solarium\Component\Result\FacetSet>|null is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
556
            $entryArray = [];
557
            $entryArray['title'] = htmlspecialchars($this->conf['facets'][$field]);
558
            $entryArray['count'] = 0;
559
            $entryArray['_OVERRIDE_HREF'] = '';
560
            $entryArray['doNotLinkIt'] = 1;
561
            $entryArray['ITEM_STATE'] = 'NO';
562
            // Count number of facet values.
563
            $i = 0;
564
            foreach ($values as $value => $count) {
565
                if ($count > 0) {
566
                    $entryArray['count']++;
567
                    if ($entryArray['ITEM_STATE'] == 'NO') {
568
                        $entryArray['ITEM_STATE'] = 'IFSUB';
569
                    }
570
                    $entryArray['_SUB_MENU'][] = $this->getFacetsMenuEntry($field, $value, $count, $search, $entryArray['ITEM_STATE']);
571
                    if (++$i == $this->conf['limit']) {
572
                        break;
573
                    }
574
                } else {
575
                    break;
576
                }
577
            }
578
            $menuArray[] = $entryArray;
579
        }
580
        return $menuArray;
581
    }
582
}
583