Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 72 |
|
0.00% |
0 / 7 |
CRAP | |
0.00% |
0 / 1 |
HTMLTree | |
0.00% |
0 / 72 |
|
0.00% |
0 / 7 |
650 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
2 | |||
getTreeList | |
0.00% |
0 / 20 |
|
0.00% |
0 / 1 |
56 | |||
render | |
0.00% |
0 / 11 |
|
0.00% |
0 / 1 |
12 | |||
augmentNodeData | |
0.00% |
0 / 9 |
|
0.00% |
0 / 1 |
30 | |||
getContextualUrl | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
20 | |||
getUrlFromRouteCache | |
0.00% |
0 / 17 |
|
0.00% |
0 / 1 |
6 | |||
getRouteNameFromDataSource | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
12 |
1 | <?php |
2 | |
3 | /** |
4 | * Hierarchy Tree HTML Renderer |
5 | * |
6 | * PHP version 8 |
7 | * |
8 | * Copyright (C) Villanova University 2010. |
9 | * Copyright (C) The National Library of Finland 2023. |
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 HierarchyTree_Renderer |
26 | * @author Luke O'Sullivan <l.osullivan@swansea.ac.uk> |
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:plugins:hierarchy_components Wiki |
30 | */ |
31 | |
32 | namespace VuFind\Hierarchy\TreeRenderer; |
33 | |
34 | use Laminas\Mvc\Controller\Plugin\Url as UrlPlugin; |
35 | use Laminas\View\Renderer\RendererInterface; |
36 | |
37 | use function in_array; |
38 | |
39 | /** |
40 | * Hierarchy Tree HTML Renderer |
41 | * |
42 | * This is a helper class for producing hierarchy trees. |
43 | * |
44 | * @category VuFind |
45 | * @package HierarchyTree_Renderer |
46 | * @author Luke O'Sullivan <l.osullivan@swansea.ac.uk> |
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:plugins:hierarchy_components Wiki |
50 | */ |
51 | class HTMLTree extends AbstractBase implements \VuFind\I18n\Translator\TranslatorAwareInterface |
52 | { |
53 | use \VuFind\I18n\Translator\TranslatorAwareTrait; |
54 | |
55 | /** |
56 | * Router plugin |
57 | * |
58 | * @var UrlPlugin |
59 | */ |
60 | protected $router = null; |
61 | |
62 | /** |
63 | * Whether the collections functionality is enabled |
64 | * |
65 | * @var bool |
66 | */ |
67 | protected $collectionsEnabled; |
68 | |
69 | /** |
70 | * View renderer |
71 | * |
72 | * @var RendererInterface |
73 | */ |
74 | protected $viewRenderer; |
75 | |
76 | /** |
77 | * Constructor |
78 | * |
79 | * @param UrlPlugin $router Router plugin for urls |
80 | * @param bool $collectionsEnabled Whether the collections functionality is enabled |
81 | * @param RendererInterface $renderer View renderer |
82 | */ |
83 | public function __construct(UrlPlugin $router, bool $collectionsEnabled, RendererInterface $renderer) |
84 | { |
85 | $this->router = $router; |
86 | $this->collectionsEnabled = $collectionsEnabled; |
87 | $this->viewRenderer = $renderer; |
88 | } |
89 | |
90 | /** |
91 | * Get a list of trees containing the item represented by the stored record |
92 | * driver. |
93 | * |
94 | * @param string $hierarchyID Optional filter: specific hierarchy ID to retrieve |
95 | * |
96 | * @return mixed An array of hierarchy IDS if a hierarchy tree exists, |
97 | * false if it does not |
98 | */ |
99 | public function getTreeList($hierarchyID = false) |
100 | { |
101 | $record = $this->getRecordDriver(); |
102 | $inHierarchies = $record->getHierarchyTopID(); |
103 | $inHierarchiesTitle = $record->getHierarchyTopTitle(); |
104 | |
105 | if ($hierarchyID) { |
106 | // Specific Hierarchy Supplied |
107 | if ( |
108 | in_array($hierarchyID, $inHierarchies) |
109 | && $this->getDataSource()->supports($hierarchyID) |
110 | ) { |
111 | return [ |
112 | $hierarchyID => $this->getHierarchyName( |
113 | $hierarchyID, |
114 | $inHierarchies, |
115 | $inHierarchiesTitle |
116 | ), |
117 | ]; |
118 | } |
119 | } else { |
120 | // Return All Hierarchies |
121 | $hierarchies = []; |
122 | foreach ($inHierarchies as $i => $hierarchyTopID) { |
123 | if ($this->getDataSource()->supports($hierarchyTopID)) { |
124 | $hierarchies[$hierarchyTopID] = $inHierarchiesTitle[$i] ?? ''; |
125 | } |
126 | } |
127 | if (!empty($hierarchies)) { |
128 | return $hierarchies; |
129 | } |
130 | } |
131 | |
132 | // If we got this far, we couldn't find valid match(es). |
133 | return false; |
134 | } |
135 | |
136 | /** |
137 | * Render the Hierarchy Tree |
138 | * |
139 | * @param string $context The context from which the call has been made |
140 | * @param string $mode The mode in which the tree should be generated |
141 | * @param string $hierarchyID The hierarchy ID of the tree to fetch (optional) |
142 | * @param ?string $selectedID The current record ID (optional) |
143 | * @param array $options Additional options |
144 | * |
145 | * @return mixed The desired hierarchy tree output (or false on error) |
146 | */ |
147 | public function render( |
148 | string $context, |
149 | string $mode, |
150 | string $hierarchyID, |
151 | ?string $selectedID = null, |
152 | array $options = [] |
153 | ) { |
154 | if (empty($context)) { |
155 | return false; |
156 | } |
157 | if ($json = $this->getDataSource()->getJSON($hierarchyID)) { |
158 | $driver = $this->recordDriver; |
159 | $nodes = [json_decode($json)]; |
160 | $this->augmentNodeData($nodes, $context, $selectedID); |
161 | return $this->viewRenderer->render( |
162 | 'hierarchy/tree.phtml', |
163 | compact('nodes', 'context', 'hierarchyID', 'driver', 'selectedID', 'options') |
164 | ); |
165 | } |
166 | return false; |
167 | } |
168 | |
169 | /** |
170 | * Augment all nodes with 'hasSelectedChild' and 'href' for rendering. |
171 | * |
172 | * @param array $nodes Node list |
173 | * @param string $context Context |
174 | * @param ?string $selectedID Selected record ID |
175 | * |
176 | * @return bool Whether any items are applied (for recursive calls) |
177 | */ |
178 | protected function augmentNodeData(array $nodes, string $context, ?string $selectedID): bool |
179 | { |
180 | $result = false; |
181 | foreach ($nodes as &$node) { |
182 | $node->hasSelectedChild = !empty($node->children) |
183 | && $this->augmentNodeData($node->children, $context, $selectedID); |
184 | if ($node->id === $selectedID || $node->hasSelectedChild) { |
185 | $result = true; |
186 | } |
187 | $node->href = $this->getContextualUrl($node, $context); |
188 | } |
189 | unset($node); |
190 | return $result; |
191 | } |
192 | |
193 | /** |
194 | * Use the router to build the appropriate URL based on context |
195 | * |
196 | * @param object $node JSON object of a node/top node |
197 | * @param string $context Record or Collection |
198 | * |
199 | * @return string |
200 | */ |
201 | protected function getContextualUrl($node, $context) |
202 | { |
203 | $type = $node->type; |
204 | if ('collection' === $type && !$this->collectionsEnabled) { |
205 | $type = 'record'; |
206 | } |
207 | $url = $this->getUrlFromRouteCache($type, $node->id); |
208 | return $type === 'collection' |
209 | ? $url . '#tabnav' |
210 | : $url; |
211 | } |
212 | |
213 | /** |
214 | * Get the URL for a record and cache it to avoid the relatively slow routing |
215 | * calls. |
216 | * |
217 | * @param string $route Route |
218 | * @param string $id Record ID |
219 | * |
220 | * @return string URL |
221 | */ |
222 | protected function getUrlFromRouteCache($route, $id) |
223 | { |
224 | static $cache = []; |
225 | if (!isset($cache[$route])) { |
226 | $params = [ |
227 | 'id' => '__record_id__', |
228 | 'tab' => 'HierarchyTree', |
229 | ]; |
230 | $options = [ |
231 | 'query' => [ |
232 | 'recordID' => '__record_id__', |
233 | ], |
234 | ]; |
235 | $cache[$route] = $this->router->fromRoute( |
236 | $this->getRouteNameFromDataSource($route), |
237 | $params, |
238 | $options |
239 | ); |
240 | } |
241 | return str_replace('__record_id__', urlencode($id), $cache[$route]); |
242 | } |
243 | |
244 | /** |
245 | * Get route name from data source. |
246 | * |
247 | * @param string $route Route |
248 | * |
249 | * @return string |
250 | */ |
251 | protected function getRouteNameFromDataSource($route) |
252 | { |
253 | if ($route === 'collection') { |
254 | return $this->getDataSource()->getCollectionRoute(); |
255 | } elseif ($route === 'record') { |
256 | return $this->getDataSource()->getRecordRoute(); |
257 | } |
258 | return $route; |
259 | } |
260 | } |