Passed
Push — master ( 16f071...f55a40 )
by Timo
27:02
created

sortFacetOptionsInNaturalOrder()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 3
cts 3
cp 1
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 1
crap 1
1
<?php
2
namespace ApacheSolrForTypo3\Solr\Domain\Search\ResultSet\Facets\OptionBased\Hierarchy;
3
4
/*
5
 * This file is part of the TYPO3 CMS project.
6
 *
7
 * It is free software; you can redistribute it and/or modify it under
8
 * the terms of the GNU General Public License, either version 2
9
 * of the License, or any later version.
10
 *
11
 * For the full copyright and license information, please read the
12
 * LICENSE.txt file that was distributed with this source code.
13
 *
14
 * The TYPO3 project - inspiring people to share!
15
 */
16
17
use ApacheSolrForTypo3\Solr\Domain\Search\Query\ParameterBuilder\Faceting;
18
use ApacheSolrForTypo3\Solr\Domain\Search\Query\Query;
19
use ApacheSolrForTypo3\Solr\Domain\Search\ResultSet\Facets\AbstractFacetParser;
20
use ApacheSolrForTypo3\Solr\Domain\Search\ResultSet\SearchResultSet;
21
22
/**
23
 * Class OptionsFacetParser
24
 */
25
class HierarchyFacetParser extends AbstractFacetParser
26
{
27
    /**
28
     * @param SearchResultSet $resultSet
29
     * @param string $facetName
30
     * @param array $facetConfiguration
31
     * @return HierarchyFacet|null
32
     */
33 37
    public function parse(SearchResultSet $resultSet, $facetName, array $facetConfiguration)
34
    {
35 37
        $response = $resultSet->getResponse();
36 37
        $fieldName = $facetConfiguration['field'];
37 37
        $label = $this->getPlainLabelOrApplyCObject($facetConfiguration);
38 37
        $optionsFromSolrResponse = isset($response->facet_counts->facet_fields->{$fieldName}) ? get_object_vars($response->facet_counts->facet_fields->{$fieldName}) : [];
39 37
        $optionsFromRequest = $this->getActiveFacetValuesFromRequest($resultSet, $facetName);
40 37
        $hasOptionsInResponse = !empty($optionsFromSolrResponse);
41 37
        $hasSelectedOptionsInRequest = count($optionsFromRequest) > 0;
42 37
        $hasNoOptionsToShow = !$hasOptionsInResponse && !$hasSelectedOptionsInRequest;
43 37
        $hideEmpty = !$resultSet->getUsedSearchRequest()->getContextTypoScriptConfiguration()->getSearchFacetingShowEmptyFacetsByName($facetName);
44
45 37
        if ($hasNoOptionsToShow && $hideEmpty) {
46 4
            return null;
47
        }
48
49
        /** @var $facet HierarchyFacet */
50 34
        $facet = $this->objectManager->get(HierarchyFacet::class, $resultSet, $facetName, $fieldName, $label, $facetConfiguration);
0 ignored issues
show
Unused Code introduced by
The call to TYPO3\CMS\Extbase\Object...ManagerInterface::get() has too many arguments starting with $resultSet. ( Ignorable by Annotation )

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

50
        /** @scrutinizer ignore-call */ 
51
        $facet = $this->objectManager->get(HierarchyFacet::class, $resultSet, $facetName, $fieldName, $label, $facetConfiguration);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
51
52 34
        $hasActiveOptions = count($optionsFromRequest) > 0;
53 34
        $facet->setIsUsed($hasActiveOptions);
54
55 34
        $facet->setIsAvailable($hasOptionsInResponse);
56
57 34
        $nodesToCreate = $this->getMergedFacetValueFromSearchRequestAndSolrResponse($optionsFromSolrResponse, $optionsFromRequest);
58
59 34
        if ($this->facetOptionsMustBeResorted($facetConfiguration, $resultSet) === true) {
60 1
            $nodesToCreate = $this->sortFacetOptionsInNaturalOrder($nodesToCreate);
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $nodesToCreate is correct as $this->sortFacetOptionsI...alOrder($nodesToCreate) targeting ApacheSolrForTypo3\Solr\...OptionsInNaturalOrder() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
61
        }
62
63 34
        foreach ($nodesToCreate as $value => $count) {
64 34
            if ($this->getIsExcludedFacetValue($value, $facetConfiguration)) {
65
                continue;
66
            }
67 34
            $isActive = in_array($value, $optionsFromRequest);
68 34
            $delimiterPosition = strpos($value, '-');
69 34
            $path = substr($value, $delimiterPosition + 1);
70 34
            $pathArray = $this->getPathAsArray($path);
71 34
            $key = array_pop($pathArray);
72 34
            $parentKey = array_pop($pathArray);
73 34
            $value = '/' . $path;
74 34
            $label = $this->getLabelFromRenderingInstructions($key, $count, $facetName, $facetConfiguration);
75
76 34
            $facet->createNode($parentKey, $key, $label, $value, $count, $isActive);
77
        }
78
79 34
        return $facet;
80
    }
81
82
    /**
83
     * Sorts facet options in natural order.
84
     * Options must be sorted in natural order,
85
     * because lower nesting levels must be instantiated first, to serve as parents for higher nested levels.
86
     * See implementation of HierarchyFacet::createNode().
87
     *
88
     * @param array $flatOptionsListForFacet
89
     * @return void sorted list of facet options
90
     */
91 1
    protected function sortFacetOptionsInNaturalOrder(array $flatOptionsListForHierarchyFacet)
92
    {
93 1
        uksort($flatOptionsListForHierarchyFacet, "strnatcmp");
94 1
        return $flatOptionsListForHierarchyFacet;
95
    }
96
97
    /**
98
     * Checks if options must be resorted.
99
     *
100
     * Apache Solr facet.sort can be set globally or per facet.
101
     * Relevant TypoScript paths:
102
     * plugin.tx_solr.search.faceting.sortBy causes facet.sort Apache Solr parameter
103
     * plugin.tx_solr.search.faceting.facets.[facetName].sortBy causes f.<fieldname>.facet.sort parameter
104
     *
105
     * see: https://lucene.apache.org/solr/guide/6_6/faceting.html#Faceting-Thefacet.sortParameter
106
     * see: https://wiki.apache.org/solr/SimpleFacetParameters#facet.sort : "This parameter can be specified on a per field basis."
107
     *
108
     * If plugin.tx_solr.search.faceting.facets.[facetName].sortBy is not set, then trying to get global parameter from ResultSet.
109
     *
110
     * @param array $facetConfiguration
111
     * @param SearchResultSet $resultSet
112
     * @return bool
113
     */
114 34
    protected function facetOptionsMustBeResorted(array $facetConfiguration, SearchResultSet $resultSet)
115
    {
116 34
        if (isset($facetConfiguration['sortBy']) && $facetConfiguration['sortBy'] === 'index') {
117 1
            return true;
118
        }
119
120 33
        if (!isset($facetConfiguration['sortBy'])
121 33
            && $resultSet->getUsedQuery()->getFaceting()->getSorting() === 'index') {
122
            return true;
123
        }
124
125 33
        return false;
126
    }
127
128
    /**
129
     * This method is used to get the path array from a hierarchical facet. It substitutes escaped slashes to keep them
130
     * when they are used inside a facetValue.
131
     *
132
     * @param string $path
133
     * @return array
134
     */
135 34
    protected function getPathAsArray($path)
136
    {
137 34
        $path = str_replace('\/', '@@@', $path);
138 34
        $path = rtrim($path, "/");
139 34
        $segments = explode('/', $path);
140 34
        return array_map(function($item) {
141 34
            return str_replace('@@@', '/', $item);
142 34
        }, $segments);
143
    }
144
145
    /**
146
     * Retrieves the active facetValue for a facet from the search request.
147
     * @param SearchResultSet $resultSet
148
     * @param string $facetName
149
     * @return array
150
     */
151 37
    protected function getActiveFacetValuesFromRequest(SearchResultSet $resultSet, $facetName)
152
    {
153 37
        $activeFacetValues = [];
154 37
        $values = $resultSet->getUsedSearchRequest()->getActiveFacetValuesByName($facetName);
155
156 37
        foreach (is_array($values) ? $values : [] as $valueFromRequest) {
157
            // Attach the 'depth' param again to the value
158 3
            if (strpos($valueFromRequest, '-') === false) {
159 3
                $valueFromRequest = trim($valueFromRequest, '/');
160 3
                $valueFromRequest = (count(explode('/', $valueFromRequest)) - 1) . '-' . $valueFromRequest . '/';
161
            }
162 3
            $activeFacetValues[] = $valueFromRequest;
163
        }
164 37
        return $activeFacetValues;
165
    }
166
}
167