Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
116 / 116
100.00% covered (success)
100.00%
9 / 9
CRAP
100.00% covered (success)
100.00%
1 / 1
SearchTabs
100.00% covered (success)
100.00%
116 / 116
100.00% covered (success)
100.00%
9 / 9
28
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 getTabConfig
100.00% covered (success)
100.00%
44 / 44
100.00% covered (success)
100.00%
1 / 1
9
 getTabConfigForParams
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
1
 getHiddenFilters
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
1
 getCurrentHiddenFilterParams
100.00% covered (success)
100.00%
25 / 25
100.00% covered (success)
100.00%
1 / 1
8
 remapBasicSearch
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
1 / 1
2
 getHomeTabUrl
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 getAdvancedTabUrl
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
2
 buildUrlHiddenFilters
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
1 / 1
3
1<?php
2
3/**
4 * "Search tabs" view helper
5 *
6 * PHP version 8
7 *
8 * Copyright (C) Villanova University 2010.
9 * Copyright (C) The National Library of Finland 2015-2016.
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2,
13 * as published by the Free Software Foundation.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
23 *
24 * @category VuFind
25 * @package  View_Helpers
26 * @author   Demian Katz <demian.katz@villanova.edu>
27 * @author   Ere Maijala <ere.maijala@helsinki.fi>
28 * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
29 * @link     https://vufind.org/wiki/development Wiki
30 */
31
32namespace VuFind\View\Helper\Root;
33
34use Laminas\Http\Request;
35use Laminas\View\Helper\Url;
36use VuFind\Search\Base\Results;
37use VuFind\Search\Results\PluginManager;
38use VuFind\Search\SearchTabsHelper;
39use VuFind\Search\UrlQueryHelper;
40
41/**
42 * "Search tabs" view helper
43 *
44 * @category VuFind
45 * @package  View_Helpers
46 * @author   Demian Katz <demian.katz@villanova.edu>
47 * @author   Ere Maijala <ere.maijala@helsinki.fi>
48 * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
49 * @link     https://vufind.org/wiki/development Wiki
50 */
51class SearchTabs extends \Laminas\View\Helper\AbstractHelper
52{
53    /**
54     * Search manager
55     *
56     * @var PluginManager
57     */
58    protected $results;
59
60    /**
61     * Request
62     *
63     * @var Request
64     */
65    protected $request;
66
67    /**
68     * Url
69     *
70     * @var Url
71     */
72    protected $url;
73
74    /**
75     * Search tab helper
76     *
77     * @var SearchTabsHelper
78     */
79    protected $helper;
80
81    /**
82     * Cached hidden filter url params
83     *
84     * @var array
85     */
86    protected $cachedHiddenFilterParams = [];
87
88    /**
89     * Constructor
90     *
91     * @param PluginManager    $results Search results plugin manager
92     * @param Url              $url     URL helper
93     * @param SearchTabsHelper $helper  Search tabs helper
94     */
95    public function __construct(
96        PluginManager $results,
97        Url $url,
98        SearchTabsHelper $helper
99    ) {
100        $this->results = $results;
101        $this->url = $url;
102        $this->helper = $helper;
103    }
104
105    /**
106     * Determine information about search tabs
107     *
108     * @param string $activeSearchClass The search class ID of the active search
109     * @param string $query             The current search query
110     * @param string $handler           The current search handler
111     * @param string $type              The current search type (basic/advanced)
112     * @param array  $hiddenFilters     The current hidden filters
113     *
114     * @return array
115     */
116    public function getTabConfig(
117        $activeSearchClass,
118        $query,
119        $handler,
120        $type = 'basic',
121        $hiddenFilters = []
122    ) {
123        $retVal = ['tabs' => []];
124        $allFilters = $this->helper->getTabFilterConfig();
125        $allPermissions = $this->helper->getTabPermissionConfig();
126        $allSettings = $this->helper->getSettings();
127        $retVal['showCounts'] = $allSettings['show_result_counts'] ?? false;
128        foreach ($this->helper->getTabConfig() as $key => $label) {
129            $permissionName = null;
130            if (isset($allPermissions[$key])) {
131                $permissionName = $allPermissions[$key];
132            }
133            $class = $this->helper->extractClassName($key);
134            $filters = isset($allFilters[$key]) ? (array)$allFilters[$key] : [];
135            $selected = $class == $activeSearchClass && $this->helper->filtersMatch($class, $hiddenFilters, $filters);
136            if ($type == 'basic') {
137                if (!isset($activeOptions)) {
138                    $activeOptions
139                        = $this->results->get($activeSearchClass)->getOptions();
140                }
141                $url = $this->remapBasicSearch(
142                    $activeOptions,
143                    $class,
144                    $query,
145                    $handler,
146                    $filters,
147                );
148            } elseif ($type == 'advanced') {
149                $url = $this->getAdvancedTabUrl(
150                    $class,
151                    $filters,
152                );
153            } else {
154                $url = $this->getHomeTabUrl(
155                    $class,
156                    $filters,
157                );
158            }
159            $tab = [
160                'id' => $key,
161                'class' => $class,
162                'label' => $label,
163                'permission' => $permissionName,
164                'selected' => $selected,
165                'url' => $url,
166            ];
167            $retVal['tabs'][] = $tab;
168            if ($selected) {
169                $retVal['selected'] = $tab;
170            }
171        }
172
173        return $retVal;
174    }
175
176    /**
177     * Get the tab configuration
178     *
179     * @param \VuFind\Search\Base\Params $params Search parameters
180     *
181     * @return array
182     */
183    public function getTabConfigForParams($params)
184    {
185        $tabConfig = $this->getTabConfig(
186            $params->getSearchClassId(),
187            $params->getDisplayQuery(),
188            $params->getSearchHandler(),
189            $params->getSearchType(),
190            $params->getHiddenFilters()
191        );
192        return $tabConfig['tabs'];
193    }
194
195    /**
196     * Get an array of hidden filters
197     *
198     * @param string $searchClassId         Active search class
199     * @param bool   $returnDefaultsIfEmpty Whether to return default tab filters if
200     * no filters are currently active
201     * @param bool   $ignoreCurrentRequest  Whether to ignore hidden filters in
202     * the current request
203     *
204     * @return array
205     */
206    public function getHiddenFilters(
207        $searchClassId,
208        $returnDefaultsIfEmpty = true,
209        $ignoreCurrentRequest = false
210    ) {
211        return $this->helper->getHiddenFilters(
212            $searchClassId,
213            $returnDefaultsIfEmpty,
214            $ignoreCurrentRequest
215        );
216    }
217
218    /**
219     * Get current hidden filters as a string suitable for search URLs
220     *
221     * @param string $searchClassId            Active search class
222     * @param bool   $ignoreHiddenFilterMemory Whether to ignore hidden filters in
223     * search memory
224     * @param string $prepend                  String to prepend to the hidden
225     * filters if they're not empty
226     *
227     * @return string
228     */
229    public function getCurrentHiddenFilterParams(
230        $searchClassId,
231        $ignoreHiddenFilterMemory = false,
232        $prepend = '&amp;'
233    ) {
234        if (!isset($this->cachedHiddenFilterParams[$searchClassId])) {
235            $view = $this->getView();
236            $hiddenFilters = $this->getHiddenFilters(
237                $searchClassId,
238                $ignoreHiddenFilterMemory
239            );
240            if (empty($hiddenFilters) && !$ignoreHiddenFilterMemory) {
241                $hiddenFilters = $view->plugin('searchMemory')
242                    ->getLastHiddenFilters($searchClassId);
243                if (empty($hiddenFilters)) {
244                    $hiddenFilters = $this->getHiddenFilters($searchClassId);
245                }
246            }
247
248            $results = $this->results->get($searchClassId);
249            $params = $results->getParams();
250            foreach ($hiddenFilters as $field => $filter) {
251                foreach ($filter as $value) {
252                    $params->addHiddenFilterForField($field, $value);
253                }
254            }
255            if ($hiddenFilters = $params->getHiddenFiltersAsQueryParams()) {
256                $this->cachedHiddenFilterParams[$searchClassId]
257                    = UrlQueryHelper::buildQueryString(
258                        [
259                            'hiddenFilters' => $hiddenFilters,
260                        ]
261                    );
262            } else {
263                $this->cachedHiddenFilterParams[$searchClassId] = '';
264            }
265        }
266        return $prepend . $this->cachedHiddenFilterParams[$searchClassId];
267    }
268
269    /**
270     * Map a search query from one class to another.
271     *
272     * @param \VuFind\Search\Base\Options $activeOptions Search options for source
273     * @param string                      $targetClass   Search class ID for target
274     * @param string                      $query         Search query to map
275     * @param string                      $handler       Search handler to map
276     * @param array                       $filters       Tab filters
277     *
278     * @return string
279     */
280    protected function remapBasicSearch(
281        $activeOptions,
282        $targetClass,
283        $query,
284        $handler,
285        $filters
286    ) {
287        // Set up results object for URL building:
288        $results = $this->results->get($targetClass);
289        $params = $results->getParams();
290        foreach ($filters as $filter) {
291            $params->addHiddenFilter($filter);
292        }
293
294        // Find matching handler for new query (and use default if no match):
295        $options = $results->getOptions();
296        $targetHandler = $options->getHandlerForLabel(
297            $activeOptions->getLabelForBasicHandler($handler)
298        );
299
300        // Build new URL:
301        $results->getParams()->setBasicSearch($query, $targetHandler);
302        return ($this->url)($options->getSearchAction())
303            . $results->getUrlQuery()->getParams(false);
304    }
305
306    /**
307     * Get an url to "search home".
308     *
309     * @param string $class   Search class ID
310     * @param array  $filters Tab filters
311     *
312     * @return string
313     */
314    protected function getHomeTabUrl($class, $filters)
315    {
316        // If an advanced search is available, link there; otherwise, just go
317        // to the search home:
318        $results = $this->results->get($class);
319        $url = ($this->url)($results->getOptions()->getSearchHomeAction())
320            . $this->buildUrlHiddenFilters($results, $filters);
321        return $url;
322    }
323
324    /**
325     * Get url for an advanced search tab.
326     *
327     * @param string $class   Search class ID
328     * @param array  $filters Tab filters
329     *
330     * @return string
331     */
332    protected function getAdvancedTabUrl($class, $filters)
333    {
334        // If an advanced search is available, link there; otherwise, just go
335        // to the search home:
336        $results = $this->results->get($class);
337        $options = $results->getOptions();
338        $advSearch = $options->getAdvancedSearchAction();
339        return ($this->url)($advSearch ?: $options->getSearchHomeAction())
340            . $this->buildUrlHiddenFilters($results, $filters);
341    }
342
343    /**
344     * Build a hidden filter query fragment from the given filters
345     *
346     * @param Results $results Search results
347     * @param array   $filters Filters
348     * @param string  $prepend String to prepend to the hidden filters if they're not
349     * empty
350     *
351     * @return string Query parameters
352     */
353    protected function buildUrlHiddenFilters(
354        Results $results,
355        array $filters,
356        string $prepend = '?'
357    ): string {
358        // Set up results object for URL building:
359        $params = $results->getParams();
360        foreach ($filters as $filter) {
361            $params->addHiddenFilter($filter);
362        }
363        if ($hiddenFilters = $params->getHiddenFiltersAsQueryParams()) {
364            return $prepend . UrlQueryHelper::buildQueryString(
365                [
366                    'hiddenFilters' => $hiddenFilters,
367                ],
368                false
369            );
370        }
371        return '';
372    }
373}