Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
100.00% |
36 / 36 |
|
100.00% |
5 / 5 |
CRAP | |
100.00% |
1 / 1 |
ClassBasedTemplateRendererTrait | |
100.00% |
36 / 36 |
|
100.00% |
5 / 5 |
11 | |
100.00% |
1 / 1 |
resolveClassTemplate | |
100.00% |
12 / 12 |
|
100.00% |
1 / 1 |
3 | |||
renderClassTemplate | |
100.00% |
13 / 13 |
|
100.00% |
1 / 1 |
4 | |||
getCachedClassTemplate | |
100.00% |
8 / 8 |
|
100.00% |
1 / 1 |
2 | |||
getBriefClass | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
getTemplateWithClass | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 |
1 | <?php |
2 | |
3 | /** |
4 | * Trait for view helpers that render a template based on a class name. |
5 | * |
6 | * Note: This trait is for view helpers only. It expects $this->getView() method to |
7 | * be available. |
8 | * |
9 | * PHP version 8 |
10 | * |
11 | * Copyright (C) Villanova University 2018. |
12 | * Copyright (C) The National Library of Finland 2020. |
13 | * |
14 | * This program is free software; you can redistribute it and/or modify |
15 | * it under the terms of the GNU General Public License version 2, |
16 | * as published by the Free Software Foundation. |
17 | * |
18 | * This program is distributed in the hope that it will be useful, |
19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
21 | * GNU General Public License for more details. |
22 | * |
23 | * You should have received a copy of the GNU General Public License |
24 | * along with this program; if not, write to the Free Software |
25 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
26 | * |
27 | * @category VuFind |
28 | * @package View_Helpers |
29 | * @author Demian Katz <demian.katz@villanova.edu> |
30 | * @author Ere Maijala <ere.maijala@helsinki.fi> |
31 | * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License |
32 | * @link https://vufind.org/wiki/development Wiki |
33 | */ |
34 | |
35 | namespace VuFind\View\Helper\Root; |
36 | |
37 | use Laminas\View\Exception\RuntimeException; |
38 | use Laminas\View\Resolver\ResolverInterface; |
39 | |
40 | /** |
41 | * Trait for view helpers that render a template based on a class name. |
42 | * |
43 | * @category VuFind |
44 | * @package View_Helpers |
45 | * @author Demian Katz <demian.katz@villanova.edu> |
46 | * @author Ere Maijala <ere.maijala@helsinki.fi> |
47 | * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License |
48 | * @link https://vufind.org/wiki/development Wiki |
49 | */ |
50 | trait ClassBasedTemplateRendererTrait |
51 | { |
52 | /** |
53 | * Cache for found templates |
54 | * |
55 | * @var array |
56 | */ |
57 | protected $templateCache = []; |
58 | |
59 | /** |
60 | * Recursively locate a template that matches the provided class name |
61 | * (or one of its parent classes); throw an exception if no match is found. |
62 | * |
63 | * @param string $template Template path (with %s as class name |
64 | * placeholder) |
65 | * @param string $className Name of class to apply to template. |
66 | * @param ResolverInterface $resolver Resolver to use |
67 | * @param string $topClassName Top-level parent class of $className |
68 | * (or null if $className is already the top level; used for recursion only). |
69 | * |
70 | * @return string |
71 | */ |
72 | protected function resolveClassTemplate( |
73 | $template, |
74 | $className, |
75 | ResolverInterface $resolver, |
76 | $topClassName = null |
77 | ) { |
78 | // If the template resolves, return it: |
79 | $templateWithClass = $this->getTemplateWithClass($template, $className); |
80 | if ($resolver->resolve($templateWithClass)) { |
81 | return $templateWithClass; |
82 | } |
83 | |
84 | // If the template doesn't resolve, let's see if we can inherit a |
85 | // template from a parent class: |
86 | $parentClass = get_parent_class($className); |
87 | if (empty($parentClass)) { |
88 | return ''; |
89 | } |
90 | |
91 | // Recurse until we find a template or run out of parents... |
92 | return $this->resolveClassTemplate( |
93 | $template, |
94 | $parentClass, |
95 | $resolver, |
96 | $topClassName ?? $className |
97 | ); |
98 | } |
99 | |
100 | /** |
101 | * Render a template associated with the provided class name, applying to |
102 | * specified context variables. |
103 | * |
104 | * @param string $template Template path (with %s as class name placeholder) |
105 | * @param string $className Name of class to apply to template. |
106 | * @param array $context Context for rendering template |
107 | * @param bool $throw If true (default), an exception is thrown if the |
108 | * template is not found. Otherwise an empty string is returned. |
109 | * |
110 | * @return string |
111 | * @throws RuntimeException |
112 | */ |
113 | protected function renderClassTemplate( |
114 | $template, |
115 | $className, |
116 | $context = [], |
117 | $throw = true |
118 | ) { |
119 | // Set up the needed context in the view: |
120 | $view = $this->getView(); |
121 | $contextHelper = $view->plugin('context'); |
122 | $oldContext = $contextHelper($view)->apply($context); |
123 | |
124 | // Find and render the template: |
125 | $classTemplate = $this->getCachedClassTemplate($template, $className); |
126 | if (!$classTemplate && $throw) { |
127 | throw new RuntimeException( |
128 | 'Cannot find ' |
129 | . $this->getTemplateWithClass($template, '[brief class name]') |
130 | . " for class $className or any of its parent classes" |
131 | ); |
132 | } |
133 | |
134 | $html = $classTemplate ? $view->render($classTemplate) : ''; |
135 | |
136 | // Restore the original context before returning the result: |
137 | $contextHelper($view)->restore($oldContext); |
138 | return $html; |
139 | } |
140 | |
141 | /** |
142 | * Resolve the class template file unless already cached and return the file |
143 | * name. |
144 | * |
145 | * @param string $template Template path (with %s as class name placeholder) |
146 | * @param string $className Name of class to apply to template. |
147 | * |
148 | * @return string |
149 | */ |
150 | protected function getCachedClassTemplate($template, $className) |
151 | { |
152 | if (!isset($this->templateCache[$className][$template])) { |
153 | $this->templateCache[$className][$template] |
154 | = $this->resolveClassTemplate( |
155 | $template, |
156 | $className, |
157 | $this->getView()->resolver() |
158 | ); |
159 | } |
160 | return $this->templateCache[$className][$template]; |
161 | } |
162 | |
163 | /** |
164 | * Helper to grab the end of the class name |
165 | * |
166 | * @param string $className Class name to abbreviate |
167 | * |
168 | * @return string |
169 | */ |
170 | protected function getBriefClass($className) |
171 | { |
172 | $classParts = explode('\\', $className); |
173 | return array_pop($classParts); |
174 | } |
175 | |
176 | /** |
177 | * Helper to put the template path and class name together |
178 | * |
179 | * @param string $template Template path (with %s as class name placeholder) |
180 | * @param string $className Class name to abbreviate |
181 | * |
182 | * @return string |
183 | */ |
184 | protected function getTemplateWithClass( |
185 | string $template, |
186 | string $className |
187 | ): string { |
188 | return sprintf($template, $this->getBriefClass($className)); |
189 | } |
190 | } |