1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* BB's Zend Framework 2 Components |
4
|
|
|
* |
5
|
|
|
* UI Components |
6
|
|
|
* |
7
|
|
|
* @package [MyApplication] |
8
|
|
|
* @subpackage BB's Zend Framework 2 Components |
9
|
|
|
* @subpackage UI Components |
10
|
|
|
* @author Björn Bartels <[email protected]> |
11
|
|
|
* @link https://gitlab.bjoernbartels.earth/groups/zf2 |
12
|
|
|
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0 |
13
|
|
|
* @copyright copyright (c) 2016 Björn Bartels <[email protected]> |
14
|
|
|
*/ |
15
|
|
|
|
16
|
|
|
namespace UIComponents\View\Helper; |
17
|
|
|
|
18
|
|
|
use RecursiveIteratorIterator; |
19
|
|
|
use Zend\EventManager\EventManager; |
20
|
|
|
use Zend\EventManager\EventManagerAwareInterface; |
21
|
|
|
use Zend\EventManager\EventManagerInterface; |
22
|
|
|
use Zend\I18n\Translator\TranslatorAwareInterface; |
23
|
|
|
use Zend\Navigation\Page\AbstractPage; |
24
|
|
|
use Zend\Navigation\AbstractContainer; |
25
|
|
|
use Zend\Permissions\Acl; |
26
|
|
|
use Zend\ServiceManager\ServiceLocatorAwareInterface; |
27
|
|
|
use Zend\ServiceManager\ServiceLocatorInterface; |
28
|
|
|
use Zend\View; |
29
|
|
|
use Zend\View\Exception; |
30
|
|
|
use \UIComponents\Translator\TranslatorAwareInterfaceTrait; |
31
|
|
|
use \UIComponents\View\Helper\Traits\ComponentClassnamesTrait; |
32
|
|
|
use \UIComponents\View\Helper\Traits\ComponentAttributesTrait; |
33
|
|
|
use \UIComponents\View\Helper\Traits\ComponentServiceManagersTrait; |
34
|
|
|
use \UIComponents\View\Helper\Traits\ComponentAclTrait; |
35
|
|
|
use \UIComponents\View\Helper\Traits\ComponentNavigationTrait; |
36
|
|
|
|
37
|
|
|
/** |
38
|
|
|
* Base class for navigational helpers |
39
|
|
|
*/ |
40
|
|
|
abstract class AbstractHelper extends \Zend\View\Helper\AbstractHtmlElement implements |
41
|
|
|
EventManagerAwareInterface, |
42
|
|
|
HelperInterface, |
43
|
|
|
ServiceLocatorAwareInterface, |
44
|
|
|
TranslatorAwareInterface |
45
|
|
|
{ |
46
|
|
|
|
47
|
|
|
use TranslatorAwareInterfaceTrait; |
48
|
|
|
use ComponentClassnamesTrait; |
49
|
|
|
use ComponentAttributesTrait; |
50
|
|
|
use ComponentServiceManagersTrait; |
51
|
|
|
use ComponentAclTrait; |
52
|
|
|
use ComponentNavigationTrait; |
53
|
|
|
|
54
|
|
|
// |
55
|
|
|
// component related vars/properties/providers/services... |
56
|
|
|
// |
57
|
|
|
|
58
|
|
|
/** |
59
|
|
|
* component's tag-name |
60
|
|
|
* |
61
|
|
|
* @var string |
62
|
|
|
*/ |
63
|
|
|
protected $tagname = 'div'; |
64
|
|
|
|
65
|
|
|
|
66
|
|
|
/** |
67
|
|
|
* component's header |
68
|
|
|
* |
69
|
|
|
* @var mixed |
70
|
|
|
*/ |
71
|
|
|
protected $header = null; |
72
|
|
|
|
73
|
|
|
/** |
74
|
|
|
* component's footer |
75
|
|
|
* |
76
|
|
|
* @var mixed |
77
|
|
|
*/ |
78
|
|
|
protected $footer = null; |
79
|
|
|
|
80
|
|
|
/** |
81
|
|
|
* component's main content |
82
|
|
|
* |
83
|
|
|
* @var string|array |
84
|
|
|
*/ |
85
|
|
|
protected $content = ''; |
86
|
|
|
|
87
|
|
|
/** |
88
|
|
|
* component's size attributes |
89
|
|
|
* |
90
|
|
|
* @var string|array |
91
|
|
|
*/ |
92
|
|
|
protected $size = ''; |
93
|
|
|
|
94
|
|
|
|
95
|
|
|
|
96
|
|
|
/** |
97
|
|
|
* DOM object container needed for element creation with php's default DOM method |
98
|
|
|
* |
99
|
|
|
* @var \DOMDocument |
100
|
|
|
*/ |
101
|
|
|
protected $_DOMDoc = null; |
102
|
|
|
|
103
|
|
|
|
104
|
|
|
|
105
|
|
|
/** |
106
|
|
|
* Magic overload: Proxy calls to the navigation container |
107
|
|
|
* |
108
|
|
|
* @param string $method method name in container |
109
|
|
|
* @param array $arguments rguments to pass |
110
|
|
|
* @return mixed |
111
|
|
|
* @throws Navigation\Exception\ExceptionInterface |
112
|
|
|
*/ |
113
|
|
|
public function __call($method, array $arguments = []) |
114
|
|
|
{ |
115
|
|
|
return call_user_func_array( |
116
|
|
|
[$this->getContainer(), $method], |
117
|
|
|
$arguments |
118
|
|
|
); |
119
|
|
|
} |
120
|
|
|
|
121
|
|
|
/** |
122
|
|
|
* Magic overload: Proxy to {@link render()}. |
123
|
|
|
* |
124
|
|
|
* This method will trigger an E_USER_ERROR if rendering the helper causes |
125
|
|
|
* an exception to be thrown. |
126
|
|
|
* |
127
|
|
|
* Implements {@link HelperInterface::__toString()}. |
128
|
|
|
* |
129
|
|
|
* @return string |
130
|
|
|
*/ |
131
|
|
|
public function __toString() |
132
|
|
|
{ |
133
|
|
|
return $this->render(); |
134
|
|
|
} |
135
|
|
|
|
136
|
|
|
/** |
137
|
|
|
* render component |
138
|
|
|
* |
139
|
|
|
* @param boolean $output |
140
|
|
|
* |
141
|
|
|
* @return string |
142
|
|
|
*/ |
143
|
|
View Code Duplication |
public function render($output = false) |
|
|
|
|
144
|
|
|
{ |
145
|
|
|
try { |
146
|
|
|
|
147
|
|
|
if ($output) { |
148
|
|
|
echo $this->buildComponent(); |
149
|
|
|
} |
150
|
|
|
return $this->buildComponent(); |
151
|
|
|
|
152
|
|
|
} catch (\Exception $e) { |
153
|
|
|
|
154
|
|
|
$msg = get_class($e) . ': ' . $e->getMessage() . "\n" . $e->getTraceAsString(); |
155
|
|
|
trigger_error($msg, E_USER_ERROR); |
156
|
|
|
return ''; |
157
|
|
|
|
158
|
|
|
} |
159
|
|
|
} |
160
|
|
|
|
161
|
|
|
/** |
162
|
|
|
* Determines whether a page should be allowed given certain parameters |
163
|
|
|
* |
164
|
|
|
* @param array $params |
165
|
|
|
* @return bool |
166
|
|
|
*/ |
167
|
|
|
protected function isAllowed($params) |
168
|
|
|
{ |
169
|
|
|
$results = $this->getEventManager()->trigger(__FUNCTION__, $this, $params); |
170
|
|
|
return $results->last(); |
171
|
|
|
} |
172
|
|
|
|
173
|
|
|
// Util methods: |
174
|
|
|
|
175
|
|
|
/** |
176
|
|
|
* Returns an HTML string containing an 'a' element for the given page |
177
|
|
|
* |
178
|
|
|
* @param AbstractPage $page page to generate HTML for |
179
|
|
|
* @return string HTML string (<a href="…">Label</a>) |
180
|
|
|
*/ |
181
|
|
|
public function htmlify(AbstractPage $page) |
182
|
|
|
{ |
183
|
|
|
$label = $this->translate($page->getLabel(), $page->getTextDomain()); |
184
|
|
|
$title = $this->translate($page->getTitle(), $page->getTextDomain()); |
185
|
|
|
|
186
|
|
|
// get attribs for anchor element |
187
|
|
|
$attribs = [ |
188
|
|
|
'id' => $page->getId(), |
189
|
|
|
'title' => $title, |
190
|
|
|
'class' => $page->getClass(), |
191
|
|
|
'href' => $page->getHref(), |
192
|
|
|
'target' => $page->getTarget() |
193
|
|
|
]; |
194
|
|
|
|
195
|
|
|
/** @var \Zend\View\Helper\EscapeHtml $escaper */ |
196
|
|
|
$escaper = $this->view->plugin('escapeHtml'); |
|
|
|
|
197
|
|
|
$label = $escaper($label); |
198
|
|
|
|
199
|
|
|
return '<a' . $this->htmlAttribs($attribs) . '>' . $label . '</a>'; |
200
|
|
|
} |
201
|
|
|
|
202
|
|
|
/** |
203
|
|
|
* Normalize an ID |
204
|
|
|
* |
205
|
|
|
* Overrides {@link View\Helper\AbstractHtmlElement::normalizeId()}. |
206
|
|
|
* |
207
|
|
|
* @param string $value |
208
|
|
|
* @return string |
209
|
|
|
*/ |
210
|
|
|
protected function normalizeId($value) |
211
|
|
|
{ |
212
|
|
|
$prefix = get_class($this); |
213
|
|
|
$prefix = strtolower(trim(substr($prefix, strrpos($prefix, '\\')), '\\')); |
214
|
|
|
|
215
|
|
|
return $prefix . '-' . $value; |
216
|
|
|
} |
217
|
|
|
|
218
|
|
|
// |
219
|
|
|
// component related methods |
220
|
|
|
// |
221
|
|
|
|
222
|
|
|
/** |
223
|
|
|
* @return string the assemled component rendered to HTML |
224
|
|
|
*/ |
225
|
|
|
public function buildComponent() { |
226
|
|
|
$html = ' '.__CLASS__.' '; |
|
|
|
|
227
|
|
|
if ( empty($this->getTagname()) ) { |
228
|
|
|
return ''; |
229
|
|
|
} |
230
|
|
|
|
231
|
|
|
$header = $this->getHeader(); |
232
|
|
|
|
233
|
|
|
$footer = $this->getFooter(); |
234
|
|
|
|
235
|
|
|
$body = $this->getContent(); |
236
|
|
|
|
237
|
|
|
$content = (array($header, $body, $footer)); |
238
|
|
View Code Duplication |
if ( is_array($body) && !isset($body["tagname"])) { |
|
|
|
|
239
|
|
|
$content = array_merge(array($header), ($body), array($footer)); |
240
|
|
|
} |
241
|
|
|
|
242
|
|
|
$component = $this->_createElement($this->getTagname(), $this->getClassnames(), (array)$this->getAttributes(), $content); |
243
|
|
|
|
244
|
|
|
return $component; |
245
|
|
|
|
246
|
|
|
} |
247
|
|
|
|
248
|
|
|
/** |
249
|
|
|
* create the component markup |
250
|
|
|
* |
251
|
|
|
* @param string $tagname |
252
|
|
|
* @param string $classnames |
253
|
|
|
* @param array $attributes |
254
|
|
|
* @param string|mixed $content |
255
|
|
|
* |
256
|
|
|
* @return string the component markup |
257
|
|
|
*/ |
258
|
|
|
public function _createElement($tagname = 'div', $classnames = '', $attributes = array(), $content = '') { |
259
|
|
|
$html = ''; |
260
|
|
|
$html .= '<'.$tagname.''.((isset($classnames) && !empty($classnames)) ? ' class="'.$classnames.'"' : '').' '.$this->htmlAttribs($attributes).'>'; |
261
|
|
|
if (!empty($content)) { |
262
|
|
|
if ( $content instanceof AbstractHelper ) { |
263
|
|
|
$html .= $content->render(); |
264
|
|
|
} else if ( is_array($content) && isset($content['tagname']) ) { |
265
|
|
|
$html .= $this->_createElement( |
266
|
|
|
$content['tagname'], |
267
|
|
|
(isset($content['classnames']) && !empty($content['classnames']) ? $content['classnames'] : (isset($content['class']) && !empty($content['class']) ? $content['class'] : '')), |
268
|
|
|
(isset($content['attributes']) && !empty($content['attributes']) ? $content['attributes'] : (isset($content['attr']) && !empty($content['attr']) ? $content['attr'] : '')), |
269
|
|
|
(isset($content['content']) && !empty($content['content']) ? $content['content'] : '') |
270
|
|
|
); |
271
|
|
|
} else if ( is_array($content) ) { |
272
|
|
|
foreach ($content as $key => $item) { |
273
|
|
|
if ( $item instanceof AbstractHelper ) { |
274
|
|
|
$html .= $item->render(); |
275
|
|
|
} else if ( is_array($item) && isset($item['tagname']) ) { |
276
|
|
|
$html .= $this->_createElement( |
277
|
|
|
$item['tagname'], |
278
|
|
|
(isset($item['classnames']) && !empty($item['classnames']) ? $item['classnames'] : (isset($item['class']) && !empty($item['class']) ? $item['class'] : '')), |
279
|
|
|
(array)(isset($item['attributes']) && !empty($item['attributes']) ? $item['attributes'] : (isset($item['attr']) && !empty($item['attr']) ? $item['attr'] : '')), |
280
|
|
|
(isset($item['content']) && !empty($item['content']) ? $item['content'] : '') |
281
|
|
|
); |
282
|
|
|
} else if ( is_array($item) ) { |
283
|
|
|
foreach ($content as $key => $value) { |
284
|
|
|
$html .= (string)$value; |
285
|
|
|
} |
286
|
|
|
} else { |
287
|
|
|
$html .= $item; |
288
|
|
|
} |
289
|
|
|
} |
290
|
|
|
} else { |
291
|
|
|
$html .= $content; |
292
|
|
|
} |
293
|
|
|
} |
294
|
|
|
$html .= '</'.$tagname.'>'; |
295
|
|
|
|
296
|
|
|
return $html; |
297
|
|
|
} |
298
|
|
|
|
299
|
|
|
|
300
|
|
|
// |
301
|
|
|
// component related getters/setters |
302
|
|
|
// |
303
|
|
|
|
304
|
|
|
/** |
305
|
|
|
* get main tag-name |
306
|
|
|
* |
307
|
|
|
* @return string the $tagname |
308
|
|
|
*/ |
309
|
|
|
public function getTagname() { |
310
|
|
|
return $this->tagname; |
311
|
|
|
} |
312
|
|
|
|
313
|
|
|
/** |
314
|
|
|
* set main tag-name |
315
|
|
|
* |
316
|
|
|
* @param string $tagname |
317
|
|
|
*/ |
318
|
|
|
public function setTagname($tagname) { |
319
|
|
|
if ( null !== $tagname ) { |
320
|
|
|
$this->tagname = $tagname; |
321
|
|
|
} |
322
|
|
|
return $this; |
323
|
|
|
} |
324
|
|
|
|
325
|
|
|
/** |
326
|
|
|
* get the element header |
327
|
|
|
* |
328
|
|
|
* @return mixed the $header |
329
|
|
|
*/ |
330
|
|
|
public function getHeader() { |
331
|
|
|
return $this->header; |
332
|
|
|
} |
333
|
|
|
|
334
|
|
|
/** |
335
|
|
|
* set the element header |
336
|
|
|
* |
337
|
|
|
* @param mixed $header |
338
|
|
|
*/ |
339
|
|
|
public function setHeader($header) { |
340
|
|
|
if ( null !== $header ) { |
341
|
|
|
$this->header = $header; |
342
|
|
|
} |
343
|
|
|
return $this; |
344
|
|
|
} |
345
|
|
|
|
346
|
|
|
/** |
347
|
|
|
* get the element footer |
348
|
|
|
* |
349
|
|
|
* @return mixed the $footer |
350
|
|
|
*/ |
351
|
|
|
public function getFooter() { |
352
|
|
|
return $this->footer; |
353
|
|
|
} |
354
|
|
|
|
355
|
|
|
/** |
356
|
|
|
* set the element footer |
357
|
|
|
* |
358
|
|
|
* @param mixed $footer |
359
|
|
|
*/ |
360
|
|
|
public function setFooter($footer = null) { |
361
|
|
|
if ( null !== $footer ) { |
362
|
|
|
$this->footer = $footer; |
363
|
|
|
} |
364
|
|
|
return $this; |
365
|
|
|
} |
366
|
|
|
|
367
|
|
|
/** |
368
|
|
|
* get the element content |
369
|
|
|
* @return the $content |
370
|
|
|
*/ |
371
|
|
|
public function getContent() { |
372
|
|
|
return $this->content; |
373
|
|
|
} |
374
|
|
|
|
375
|
|
|
/** |
376
|
|
|
* set the element content |
377
|
|
|
* |
378
|
|
|
* @param string|array $content |
379
|
|
|
*/ |
380
|
|
|
public function setContent($content = '') { |
381
|
|
|
$this->content = $content; |
382
|
|
|
return $this; |
383
|
|
|
} |
384
|
|
|
|
385
|
|
|
/** |
386
|
|
|
* get DOM object |
387
|
|
|
* |
388
|
|
|
* @return the $_DOMDoc |
389
|
|
|
*/ |
390
|
|
|
public function getDOMDoc() { |
391
|
|
|
if ( ! $this->_DOMDoc instanceof \DOMDocument ) { |
392
|
|
|
$this->_DOMDoc = new \DOMDocument(); |
393
|
|
|
} |
394
|
|
|
return $this->_DOMDoc; |
395
|
|
|
} |
396
|
|
|
|
397
|
|
|
/** |
398
|
|
|
* set DOM object |
399
|
|
|
* |
400
|
|
|
* @param \DOMDocument $_DOMDoc |
401
|
|
|
*/ |
402
|
|
|
public function setDOMDoc(\DOMDocument $_DOMDoc) { |
403
|
|
|
$this->_DOMDoc = $_DOMDoc; |
404
|
|
|
return $this; |
405
|
|
|
} |
406
|
|
|
|
407
|
|
|
} |
408
|
|
|
|
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.