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\Components; |
17
|
|
|
|
18
|
|
|
use Zend\View\HelperPluginManager; |
19
|
|
|
use Locale; |
20
|
|
|
|
21
|
|
|
class Languagemenu extends \UIComponents\View\Helper\AbstractHelper |
22
|
|
|
|
23
|
|
|
{ |
24
|
|
|
|
25
|
|
|
/** |
26
|
|
|
* @var Detector $detector |
27
|
|
|
*/ |
28
|
|
|
protected $detector; |
29
|
|
|
|
30
|
|
|
/** |
31
|
|
|
* Set the class to be used on the list container |
32
|
|
|
* |
33
|
|
|
* @var string || null |
34
|
|
|
*/ |
35
|
|
|
protected $class; |
36
|
|
|
|
37
|
|
|
/** |
38
|
|
|
* Method used to construct a title for each item |
39
|
|
|
* |
40
|
|
|
* @var string || null |
41
|
|
|
*/ |
42
|
|
|
protected $titleMethod = 'displayLanguage'; |
43
|
|
|
|
44
|
|
|
/** |
45
|
|
|
* Flag to specify specifies whether the title should be in the current locale |
46
|
|
|
* |
47
|
|
|
* @var boolean default false |
48
|
|
|
*/ |
49
|
|
|
protected $titleInCurrentLocale = false; |
50
|
|
|
|
51
|
|
|
/** |
52
|
|
|
* Method used to construct a label for each item |
53
|
|
|
* |
54
|
|
|
* @var string || null |
55
|
|
|
*/ |
56
|
|
|
protected $labelMethod = 'displayLanguage'; |
57
|
|
|
|
58
|
|
|
/** |
59
|
|
|
* Flag to specify specifies whether the label should be in the current locale |
60
|
|
|
* |
61
|
|
|
* @var boolean default true |
62
|
|
|
*/ |
63
|
|
|
protected $labelInCurrentLocale = true; |
64
|
|
|
|
65
|
|
|
/** |
66
|
|
|
* Flag to specify the current locale should be omitted from the menu |
67
|
|
|
* |
68
|
|
|
* @var boolean default false |
69
|
|
|
*/ |
70
|
|
|
protected $omitCurrent = false; |
71
|
|
|
|
72
|
|
|
/** |
73
|
|
|
* default CSS class to use for li elements |
74
|
|
|
* |
75
|
|
|
* @var string |
76
|
|
|
*/ |
77
|
|
|
protected $defaultLiClass = ''; |
78
|
|
|
|
79
|
|
|
/** |
80
|
|
|
* CSS class to use for the ul sub-menu element |
81
|
|
|
* |
82
|
|
|
* @var string |
83
|
|
|
*/ |
84
|
|
|
protected $subUlClass = 'dropdown-menu'; |
85
|
|
|
|
86
|
|
|
/** |
87
|
|
|
* CSS class to use for the 1. level (NOT root level!) ul sub-menu element |
88
|
|
|
* |
89
|
|
|
* @var string |
90
|
|
|
*/ |
91
|
|
|
protected $subUlClassLevel1 = 'dropdown-menu'; |
92
|
|
|
|
93
|
|
|
/** |
94
|
|
|
* CSS class to use for the active li sub-menu element |
95
|
|
|
* |
96
|
|
|
* @var string |
97
|
|
|
*/ |
98
|
|
|
protected $subLiClass = 'dropdown-submenu'; |
99
|
|
|
|
100
|
|
|
/** |
101
|
|
|
* CSS class to use for the active li sub-menu element |
102
|
|
|
* |
103
|
|
|
* @var string |
104
|
|
|
*/ |
105
|
|
|
protected $subLiClassLevel0 = 'dropdown'; |
106
|
|
|
|
107
|
|
|
/** |
108
|
|
|
* CSS class prefix to use for the menu element's icon class |
109
|
|
|
* |
110
|
|
|
* @var string |
111
|
|
|
*/ |
112
|
|
|
protected $iconPrefixClass = 'icon-'; |
113
|
|
|
|
114
|
|
|
/** |
115
|
|
|
* HREF string to use for the sub-menu toggle element's HREF attribute, |
116
|
|
|
* to override current page's href/'htmlify' setting |
117
|
|
|
* |
118
|
|
|
* @var string |
119
|
|
|
*/ |
120
|
|
|
protected $hrefSubToggleOverride = null; |
121
|
|
|
|
122
|
|
|
/** |
123
|
|
|
* Partial view script to use for rendering menu link/item |
124
|
|
|
* |
125
|
|
|
* @var string|array |
126
|
|
|
*/ |
127
|
|
|
protected $htmlifyPartial = null; |
128
|
|
|
|
129
|
|
|
/** |
130
|
|
|
* @param Detector $detector |
131
|
|
|
*/ |
132
|
|
|
public function setDetector($detector) |
133
|
|
|
{ |
134
|
|
|
$this->detector = $detector; |
135
|
|
|
return $this; |
136
|
|
|
} |
137
|
|
|
|
138
|
|
|
/** |
139
|
|
|
* @return Detector $detector |
140
|
|
|
*/ |
141
|
|
|
public function getDetector() |
142
|
|
|
{ |
143
|
|
|
if (!$this->detector) { |
144
|
|
|
$serviceLocator = $this->getServiceLocator(); |
145
|
|
|
if ($serviceLocator instanceof HelperPluginManager) { |
146
|
|
|
$serviceLocator = $serviceLocator->getServiceLocator(); |
147
|
|
|
} |
148
|
|
|
$this->detector = $serviceLocator->get('SlmLocale\Locale\Detector'); |
|
|
|
|
149
|
|
|
} |
150
|
|
|
return $this->detector; |
|
|
|
|
151
|
|
|
} |
152
|
|
|
|
153
|
|
|
/** |
154
|
|
|
* @param string $class |
155
|
|
|
*/ |
156
|
|
|
public function setUlClass($class) |
157
|
|
|
{ |
158
|
|
|
$this->class = $class; |
159
|
|
|
return $this; |
160
|
|
|
} |
161
|
|
|
|
162
|
|
|
/** |
163
|
|
|
* @return string |
164
|
|
|
*/ |
165
|
|
|
public function getUlClass() |
166
|
|
|
{ |
167
|
|
|
return $this->class; |
168
|
|
|
} |
169
|
|
|
|
170
|
|
|
/** |
171
|
|
|
* @param string $itemTitleMethod |
|
|
|
|
172
|
|
|
*/ |
173
|
|
|
public function setTitleMethod($titleMethod) |
174
|
|
|
{ |
175
|
|
|
$this->checkLocaleMethod($titleMethod); |
176
|
|
|
|
177
|
|
|
$this->titleMethod = $titleMethod; |
178
|
|
|
return $this; |
179
|
|
|
} |
180
|
|
|
|
181
|
|
|
/** |
182
|
|
|
* @return string |
183
|
|
|
*/ |
184
|
|
|
public function getTitleMethod() |
185
|
|
|
{ |
186
|
|
|
return $this->titleMethod; |
187
|
|
|
} |
188
|
|
|
|
189
|
|
|
/** |
190
|
|
|
* @param boolean $flag |
191
|
|
|
*/ |
192
|
|
|
public function setTitleInCurrentLocale($flag) |
193
|
|
|
{ |
194
|
|
|
$this->titleInCurrentLocale = (bool) $flag; |
195
|
|
|
return $this; |
196
|
|
|
} |
197
|
|
|
|
198
|
|
|
/** |
199
|
|
|
* @return boolean |
200
|
|
|
*/ |
201
|
|
|
public function getTitleInCurrentLocale() |
202
|
|
|
{ |
203
|
|
|
return $this->titleInCurrentLocale; |
204
|
|
|
} |
205
|
|
|
|
206
|
|
|
/** |
207
|
|
|
* @param string $labelMethod |
208
|
|
|
*/ |
209
|
|
|
public function setLabelMethod($labelMethod) |
210
|
|
|
{ |
211
|
|
|
$this->checkLocaleMethod($labelMethod); |
212
|
|
|
|
213
|
|
|
$this->labelMethod = $labelMethod; |
214
|
|
|
return $this; |
215
|
|
|
} |
216
|
|
|
|
217
|
|
|
/** |
218
|
|
|
* @return string |
219
|
|
|
*/ |
220
|
|
|
public function getLabelMethod() |
221
|
|
|
{ |
222
|
|
|
return $this->labelMethod; |
223
|
|
|
} |
224
|
|
|
|
225
|
|
|
/** |
226
|
|
|
* @param boolean $flag |
227
|
|
|
*/ |
228
|
|
|
public function setLabelInCurrentLocale($flag) |
229
|
|
|
{ |
230
|
|
|
$this->labelInCurrentLocale = (bool) $flag; |
231
|
|
|
return $this; |
232
|
|
|
} |
233
|
|
|
|
234
|
|
|
/** |
235
|
|
|
* @return boolean |
236
|
|
|
*/ |
237
|
|
|
public function getLabelInCurrentLocale() |
238
|
|
|
{ |
239
|
|
|
return $this->labelInCurrentLocale; |
240
|
|
|
} |
241
|
|
|
|
242
|
|
|
/** |
243
|
|
|
* @param boolean $omitCurrent |
244
|
|
|
*/ |
245
|
|
|
public function setOmitCurrent($omitCurrent) |
246
|
|
|
{ |
247
|
|
|
$this->omitCurrent = (bool) $omitCurrent; |
248
|
|
|
return $this; |
249
|
|
|
} |
250
|
|
|
|
251
|
|
|
/** |
252
|
|
|
* @return boolean |
253
|
|
|
*/ |
254
|
|
|
public function omitCurrent() |
255
|
|
|
{ |
256
|
|
|
return $this->omitCurrent; |
257
|
|
|
} |
258
|
|
|
|
259
|
|
|
/** |
260
|
|
|
* @return the $defaultLiClass |
261
|
|
|
*/ |
262
|
|
|
public function getDefaultLiClass() { |
263
|
|
|
return $this->defaultLiClass; |
264
|
|
|
} |
265
|
|
|
|
266
|
|
|
/** |
267
|
|
|
* @param string $defaultLiClass |
268
|
|
|
*/ |
269
|
|
|
public function setDefaultLiClass($defaultLiClass) { |
270
|
|
|
$this->defaultLiClass = $defaultLiClass; |
271
|
|
|
return $this; |
272
|
|
|
} |
273
|
|
|
|
274
|
|
|
/** |
275
|
|
|
* @return the $subUlClass |
276
|
|
|
*/ |
277
|
|
|
public function getSubUlClass() { |
278
|
|
|
return $this->subUlClass; |
279
|
|
|
} |
280
|
|
|
|
281
|
|
|
/** |
282
|
|
|
* @param string $subUlClass |
283
|
|
|
*/ |
284
|
|
|
public function setSubUlClass($subUlClass) { |
285
|
|
|
$this->subUlClass = $subUlClass; |
286
|
|
|
return $this; |
287
|
|
|
} |
288
|
|
|
|
289
|
|
|
/** |
290
|
|
|
* @return the $subUlClassLevel1 |
291
|
|
|
*/ |
292
|
|
|
public function getSubUlClassLevel1() { |
293
|
|
|
return $this->subUlClassLevel1; |
294
|
|
|
} |
295
|
|
|
|
296
|
|
|
/** |
297
|
|
|
* @param string $subUlClassLevel1 |
298
|
|
|
*/ |
299
|
|
|
public function setSubUlClassLevel1($subUlClassLevel1) { |
300
|
|
|
$this->subUlClassLevel1 = $subUlClassLevel1; |
301
|
|
|
return $this; |
302
|
|
|
} |
303
|
|
|
|
304
|
|
|
/** |
305
|
|
|
* @return the $subLiClass |
306
|
|
|
*/ |
307
|
|
|
public function getSubLiClass() { |
308
|
|
|
return $this->subLiClass; |
309
|
|
|
} |
310
|
|
|
|
311
|
|
|
/** |
312
|
|
|
* @param string $subLiClass |
313
|
|
|
*/ |
314
|
|
|
public function setSubLiClass($subLiClass) { |
315
|
|
|
$this->subLiClass = $subLiClass; |
316
|
|
|
return $this; |
317
|
|
|
} |
318
|
|
|
|
319
|
|
|
/** |
320
|
|
|
* @return the $subLiClassLevel0 |
321
|
|
|
*/ |
322
|
|
|
public function getSubLiClassLevel0() { |
323
|
|
|
return $this->subLiClassLevel0; |
324
|
|
|
} |
325
|
|
|
|
326
|
|
|
/** |
327
|
|
|
* @param string $subLiClassLevel0 |
328
|
|
|
*/ |
329
|
|
|
public function setSubLiClassLevel0($subLiClassLevel0) { |
330
|
|
|
$this->subLiClassLevel0 = $subLiClassLevel0; |
331
|
|
|
return $this; |
332
|
|
|
} |
333
|
|
|
|
334
|
|
|
/** |
335
|
|
|
* @return the $iconPrefixClass |
336
|
|
|
*/ |
337
|
|
|
public function getIconPrefixClass() { |
338
|
|
|
return $this->iconPrefixClass; |
339
|
|
|
} |
340
|
|
|
|
341
|
|
|
/** |
342
|
|
|
* @param string $iconPrefixClass |
343
|
|
|
*/ |
344
|
|
|
public function setIconPrefixClass($iconPrefixClass) { |
345
|
|
|
$this->iconPrefixClass = $iconPrefixClass; |
346
|
|
|
return $this; |
347
|
|
|
} |
348
|
|
|
|
349
|
|
|
/** |
350
|
|
|
* @return the $hrefSubToggleOverride |
351
|
|
|
*/ |
352
|
|
|
public function getHrefSubToggleOverride() { |
353
|
|
|
return $this->hrefSubToggleOverride; |
354
|
|
|
} |
355
|
|
|
|
356
|
|
|
/** |
357
|
|
|
* @param string $hrefSubToggleOverride |
358
|
|
|
*/ |
359
|
|
|
public function setHrefSubToggleOverride($hrefSubToggleOverride) { |
360
|
|
|
$this->hrefSubToggleOverride = $hrefSubToggleOverride; |
361
|
|
|
return $this; |
362
|
|
|
} |
363
|
|
|
|
364
|
|
|
/** |
365
|
|
|
* Sets which partial view script to use for rendering menu |
366
|
|
|
* |
367
|
|
|
* @param string|array $partial partial view script or null. If an array is |
368
|
|
|
* given, it is expected to contain two |
369
|
|
|
* values; the partial view script to use, |
370
|
|
|
* and the module where the script can be |
371
|
|
|
* found. |
372
|
|
|
* @return self |
373
|
|
|
*/ |
374
|
|
View Code Duplication |
public function setHtmlifyPartial($partial) |
|
|
|
|
375
|
|
|
{ |
376
|
|
|
if (null === $partial || is_string($partial) || is_array($partial)) { |
377
|
|
|
$this->htmlifyPartial = $partial; |
378
|
|
|
} |
379
|
|
|
|
380
|
|
|
return $this; |
381
|
|
|
} |
382
|
|
|
|
383
|
|
|
/** |
384
|
|
|
* Returns partial view script to use for rendering menu |
385
|
|
|
* |
386
|
|
|
* @return string|array|null |
387
|
|
|
*/ |
388
|
|
|
public function getHtmlifyPartial() |
389
|
|
|
{ |
390
|
|
|
return $this->htmlifyPartial; |
391
|
|
|
} |
392
|
|
|
|
393
|
|
|
/** |
394
|
|
|
* View helper entry point: |
395
|
|
|
* Retrieves helper and optionally sets component options to operate on |
396
|
|
|
* |
397
|
|
|
* @param array|StdClass $options [optional] component options to operate on |
398
|
|
|
* @return self |
399
|
|
|
*/ |
400
|
|
|
public function __invoke($options = array()) |
401
|
|
|
{ |
402
|
|
|
parent::__invoke($options); |
403
|
|
|
return $this; |
404
|
|
|
} |
405
|
|
|
|
406
|
|
|
/** |
407
|
|
|
* render component |
408
|
|
|
* |
409
|
|
|
* @param boolean $output |
410
|
|
|
* |
411
|
|
|
* @return string |
412
|
|
|
*/ |
413
|
|
View Code Duplication |
public function render($output = false) |
|
|
|
|
414
|
|
|
{ |
415
|
|
|
try { |
416
|
|
|
|
417
|
|
|
if ($output) { |
418
|
|
|
echo $this->buildComponent(); |
419
|
|
|
} |
420
|
|
|
return $this->buildComponent(); |
421
|
|
|
|
422
|
|
|
} catch (\Exception $e) { |
423
|
|
|
|
424
|
|
|
$msg = get_class($e) . ': ' . $e->getMessage() . "\n" . $e->getTraceAsString(); |
425
|
|
|
trigger_error($msg, E_USER_ERROR); |
426
|
|
|
return ''; |
427
|
|
|
|
428
|
|
|
} |
429
|
|
|
} |
430
|
|
|
|
431
|
|
|
/** |
432
|
|
|
* build markup |
433
|
|
|
* |
434
|
|
|
* @return string |
435
|
|
|
*/ |
436
|
|
|
public function buildComponent() |
437
|
|
|
{ |
438
|
|
|
if (!($detector = $this->getDetector())) { |
439
|
|
|
throw new \RuntimeException('To assemble an url, a detector is required'); |
440
|
|
|
} |
441
|
|
|
|
442
|
|
|
$class = $this->getUlClass(); |
443
|
|
|
$liclass = $this->getSubLiClassLevel0(); |
444
|
|
|
$subulclass = $this->getSubUlClassLevel1(); |
445
|
|
|
$iconprefixclass = $this->getIconPrefixClass(); |
446
|
|
|
|
447
|
|
|
$list = ''; |
448
|
|
|
$current = Locale::getDefault(); |
449
|
|
|
foreach($detector->getSupported() as $locale) { |
450
|
|
|
if ($this->omitCurrent() && $current === $locale) { |
451
|
|
|
continue; |
452
|
|
|
} |
453
|
|
|
|
454
|
|
|
$titleLocale = $this->getTitleInCurrentLocale() ? $locale : $current; |
455
|
|
|
$labelLocale = $this->getLabelInCurrentLocale() ? $locale : $current; |
456
|
|
|
|
457
|
|
|
$url = $this->getView()->localeUrl($locale); |
|
|
|
|
458
|
|
|
$title = $this->getLocaleProperty($this->getTitleMethod(), $locale, $titleLocale); |
|
|
|
|
459
|
|
|
$label = $this->getLocaleProperty($this->getLabelMethod(), $locale, $labelLocale); |
460
|
|
|
$primary = $this->getLocaleProperty('primaryLanguage', $locale, true); |
461
|
|
|
$displayName = $this->getLocaleProperty('displayName', $locale, $labelLocale); |
462
|
|
|
|
463
|
|
|
$item = sprintf( |
464
|
|
|
'<li><a href="%s" title="%s"%s>%s</a></li>' . "\n", |
465
|
|
|
$url, |
466
|
|
|
$displayName, |
467
|
|
|
($current === $locale) ? ' class="active"' : '', |
468
|
|
|
(($iconprefixclass) ? '<span class="' . $iconprefixclass . $primary . '"></span> ' : '') . $label |
469
|
|
|
); |
470
|
|
|
|
471
|
|
|
$list .= $item; |
472
|
|
|
} |
473
|
|
|
$attributes = $this->getAttributes(); |
474
|
|
|
$html = |
475
|
|
|
'<ul'.(($class) ? sprintf(' class="%s"', $class) : '').' '.($this->htmlAttribs($attributes)).'>'. |
476
|
|
|
'<li'.(($liclass) ? sprintf(' class="%s"', $liclass) : '').'>'. |
477
|
|
|
'<a href="" class="'.(($liclass) ? $liclass.'-toggle' : '').'" data-toggle="'.(($liclass) ? $liclass : '').'" role="button" aria-haspopup="true" aria-expanded="false" title="'.Locale::getDisplayName(null).'">'. |
478
|
|
|
'<span class="'.(($iconprefixclass) ? $iconprefixclass : '').Locale::getPrimaryLanguage(null).'"></span> '. |
479
|
|
|
''.Locale::getDisplayLanguage(null). // ' - '.Locale::getDefault().' - '.Locale::getPrimaryLanguage(null).''. |
480
|
|
|
'<span class="caret"></span>'. |
481
|
|
|
'</a>'. |
482
|
|
|
sprintf( |
483
|
|
|
'<ul%s>%s</ul>', |
484
|
|
|
($subulclass) ? sprintf(' class="%s"', $subulclass) : '', |
485
|
|
|
$list |
486
|
|
|
). |
487
|
|
|
'</li>'. |
488
|
|
|
'</ul>' |
489
|
|
|
; |
490
|
|
|
|
491
|
|
|
return $html; |
492
|
|
|
|
493
|
|
|
return '<h2>'.__CLASS__.'</h2>'; |
|
|
|
|
494
|
|
|
} |
495
|
|
|
|
496
|
|
|
/** |
497
|
|
|
* Check whether method part of the Locale class is |
498
|
|
|
* |
499
|
|
|
* @param string $method Method to check |
500
|
|
|
* @throws RuntimeException If method is not part of locale |
501
|
|
|
* @return true |
502
|
|
|
*/ |
503
|
|
|
protected function checkLocaleMethod($method) |
504
|
|
|
{ |
505
|
|
|
$options = array( |
506
|
|
|
'displayLanguage', |
507
|
|
|
'displayName', |
508
|
|
|
'displayRegion', |
509
|
|
|
'displayScript', |
510
|
|
|
'displayVariant', |
511
|
|
|
'primaryLanguage', |
512
|
|
|
'region', |
513
|
|
|
'script' |
514
|
|
|
); |
515
|
|
|
|
516
|
|
|
if (!in_array($method, $options)) { |
517
|
|
|
throw new RuntimeException(sprintf( |
518
|
|
|
'Unknown method "%s" for Locale, expecting one of these: %s.', |
519
|
|
|
$method, |
520
|
|
|
implode(', ', $options) |
521
|
|
|
)); |
522
|
|
|
} |
523
|
|
|
} |
524
|
|
|
|
525
|
|
|
/** |
526
|
|
|
* Retrieves a value by property from Locale |
527
|
|
|
* |
528
|
|
|
* @param $property |
529
|
|
|
* @param $locale |
530
|
|
|
* @param bool $in_locale |
531
|
|
|
* @return mixed |
532
|
|
|
*/ |
533
|
|
|
protected function getLocaleProperty($property, $locale, $in_locale = false) |
534
|
|
|
{ |
535
|
|
|
$callback = sprintf('\Locale::get%s', ucfirst($property)); |
536
|
|
|
|
537
|
|
|
$args = array($locale); |
538
|
|
|
|
539
|
|
|
if ($in_locale && !in_array($property, array('primaryLanguage', 'region', 'script'))) { |
540
|
|
|
$args[] = $in_locale; |
541
|
|
|
} |
542
|
|
|
|
543
|
|
|
return call_user_func_array($callback, $args); |
544
|
|
|
} |
545
|
|
|
|
546
|
|
|
} |
Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.
For example, imagine you have a variable
$accountId
that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to theid
property of an instance of theAccount
class. This class holds a proper account, so the id value must no longer be false.Either this assignment is in error or a type check should be added for that assignment.