1
|
|
|
<?php |
2
|
|
|
/* |
3
|
|
|
* This file is part of the Patternseek ComponentView library. |
4
|
|
|
* |
5
|
|
|
* (c) 2014 Tolan Blundell <[email protected]> |
6
|
|
|
* |
7
|
|
|
* For the full copyright and license information, please view the LICENSE |
8
|
|
|
* file that was distributed with this source code. |
9
|
|
|
*/ |
10
|
|
|
|
11
|
|
|
namespace PatternSeek\ComponentView; |
12
|
|
|
|
13
|
|
|
use PatternSeek\ComponentView\Template\AbstractTemplate; |
14
|
|
|
use PatternSeek\ComponentView\ViewState\ViewState; |
15
|
|
|
use PatternSeek\DependencyInjector\DependencyInjector; |
16
|
|
|
use Psr\Log\LoggerInterface; |
17
|
|
|
use Psr\Log\LogLevel; |
18
|
|
|
|
19
|
|
|
/** |
20
|
|
|
* Class AbstractViewComponent |
21
|
|
|
* @package PatternSeek\ComponentView |
22
|
|
|
*/ |
23
|
|
|
abstract class AbstractViewComponent |
24
|
|
|
{ |
25
|
|
|
|
26
|
|
|
/** |
27
|
|
|
* @var ExecHelper |
28
|
|
|
*/ |
29
|
|
|
public $exec; |
30
|
|
|
/** |
31
|
|
|
* Message to display when rendering component. Won't be serialised to will only be displayed once. |
32
|
|
|
* @var string |
33
|
|
|
*/ |
34
|
|
|
public $flashMessage; |
35
|
|
|
/** |
36
|
|
|
* Error to display when rendering component. Won't be serialised to will only be displayed once. |
37
|
|
|
* @var string |
38
|
|
|
*/ |
39
|
|
|
public $flashError; |
40
|
|
|
/** |
41
|
|
|
* If we have a parent in $parent, $handle is the parent's handle/identifier for us |
42
|
|
|
* @var string |
43
|
|
|
*/ |
44
|
|
|
public $handle; |
45
|
|
|
/** |
46
|
|
|
* @var ViewState An object containing state elements |
47
|
|
|
*/ |
48
|
|
|
protected $state; |
49
|
|
|
/** |
50
|
|
|
* @var AbstractViewComponent |
51
|
|
|
*/ |
52
|
|
|
protected $parent; |
53
|
|
|
/** |
54
|
|
|
* @var AbstractViewComponent[] |
55
|
|
|
*/ |
56
|
|
|
public $childComponents = [ ]; |
57
|
|
|
|
58
|
|
|
/** |
59
|
|
|
* @var AbstractTemplate |
60
|
|
|
*/ |
61
|
|
|
protected $template; |
62
|
|
|
|
63
|
|
|
/** |
64
|
|
|
* @var LoggerInterface |
65
|
|
|
*/ |
66
|
|
|
protected $logger; |
67
|
|
|
|
68
|
|
|
/** |
69
|
|
|
* @var array |
70
|
|
|
*/ |
71
|
|
|
protected $props; |
72
|
|
|
|
73
|
|
|
/** |
74
|
|
|
* If set the render() will skip any processing and immediately return this response |
75
|
|
|
* |
76
|
|
|
* @var Response |
77
|
|
|
*/ |
78
|
|
|
private $forceResponse; |
79
|
|
|
|
80
|
|
|
/** |
81
|
|
|
* @param null $handle |
82
|
|
|
* @param AbstractViewComponent $parent |
83
|
|
|
* @param ExecHelper $execHelper |
84
|
|
|
* @param LoggerInterface $logger |
85
|
|
|
* @internal param array $initConfig |
86
|
|
|
*/ |
87
|
|
|
public function __construct( |
88
|
|
|
$handle = null, |
89
|
|
|
AbstractViewComponent $parent = null, |
90
|
|
|
ExecHelper $execHelper = null, |
91
|
|
|
LoggerInterface $logger = null |
92
|
|
|
){ |
93
|
|
|
// Null means we are root |
94
|
|
|
$this->parent = $parent; |
95
|
|
|
|
96
|
|
|
// Null means we are root |
97
|
|
|
$this->handle = $handle; |
98
|
|
|
|
99
|
|
|
if (null === $execHelper) { |
100
|
|
|
$execHelper = new ExecHelper(); |
101
|
|
|
} |
102
|
|
|
$this->setExec( $execHelper ); |
103
|
|
|
|
104
|
|
|
$this->handleDependencyInjection(); |
105
|
|
|
|
106
|
|
|
$this->setLogger( $logger ); |
107
|
|
|
|
108
|
|
|
// Set up the state container |
109
|
|
|
$this->initState(); |
110
|
|
|
} |
111
|
|
|
|
112
|
|
|
/** |
113
|
|
|
* @param string $message |
114
|
|
|
* @param string $level A constant from LogLevel |
115
|
|
|
*/ |
116
|
|
|
protected function log( $message, $level ){ |
117
|
|
|
if( isset( $this->logger ) ){ |
118
|
|
|
$class = get_class( $this ); |
119
|
|
|
$message = "[{$class}] {$message}"; |
120
|
|
|
$this->logger->log( $level, $message ); |
121
|
|
|
} |
122
|
|
|
} |
123
|
|
|
|
124
|
|
|
/** |
125
|
|
|
* User this to serialise ViewComponents as extra steps may be added later. |
126
|
|
|
* @return string |
127
|
|
|
*/ |
128
|
|
|
public function dehydrate(){ |
129
|
|
|
$this->log( "Dehydrating", LogLevel::DEBUG ); |
130
|
|
|
return serialize( $this ); |
131
|
|
|
} |
132
|
|
|
|
133
|
|
|
/** |
134
|
|
|
* Use this to unserialise ViewComponents |
135
|
|
|
* @param $serialised |
136
|
|
|
* @param ExecHelper $execHelper |
137
|
|
|
* @param LoggerInterface $logger |
138
|
|
|
* @return AbstractViewComponent |
139
|
|
|
*/ |
140
|
|
|
|
141
|
|
|
public static function rehydrate( $serialised, ExecHelper $execHelper, LoggerInterface $logger = null ){ |
142
|
|
|
/** @var AbstractViewComponent $view */ |
143
|
|
|
$view = unserialize( $serialised ); |
144
|
|
|
$view->setExec( $execHelper ); |
145
|
|
|
$view->handleDependencyInjection(); |
146
|
|
|
$view->setLogger( $logger ); |
147
|
|
|
$view->log( "Rehydrated", LogLevel::DEBUG ); |
148
|
|
|
return $view; |
149
|
|
|
} |
150
|
|
|
|
151
|
|
|
/** |
152
|
|
|
* @return array |
153
|
|
|
*/ |
154
|
|
|
public function __sleep() |
155
|
|
|
{ |
156
|
|
|
return [ |
157
|
|
|
'childComponents', |
158
|
|
|
'handle', |
159
|
|
|
'parent', |
160
|
|
|
'state' |
161
|
|
|
]; |
162
|
|
|
} |
163
|
|
|
|
164
|
|
|
/** |
165
|
|
|
* Entry point for rendering a component tree. Call updateView() first. |
166
|
|
|
* @param string|null $execMethodName An optional method on this or a subcomponent to execute before rendering |
167
|
|
|
* @param array|null $execArgs |
168
|
|
|
* @throws \Exception |
169
|
|
|
* @return Response |
170
|
|
|
*/ |
171
|
|
|
public function render( $execMethodName = null, array $execArgs = null ) |
172
|
|
|
{ |
173
|
|
|
$this->state->validate(); |
174
|
|
|
|
175
|
|
|
// updateState() on any component can call $this->getRootComponent()->forceResponse() |
|
|
|
|
176
|
|
|
// to force a particular response, usually a redirect. |
177
|
|
|
if (null !== $this->forceResponse) { |
178
|
|
|
return $this->forceResponse; |
179
|
|
|
} |
180
|
|
|
|
181
|
|
|
$this->initTemplate(); |
182
|
|
|
|
183
|
|
|
// If we're called with an 'exec' then run it instead of rendering the whole tree. |
184
|
|
|
// It may still render the whole tree or it may just render a portion or just return JSON |
185
|
|
|
if ($execMethodName) { // Used to test for null but it could easily be an empty string |
|
|
|
|
186
|
|
|
$this->log( "Rendering with exec: {$execMethodName}, args:".var_export($execArgs, true ), LogLevel::DEBUG ); |
187
|
|
|
$out = $this->execMethod( $execMethodName, $execArgs ); |
188
|
|
|
}else { |
189
|
|
|
$this->log( "Rendering without exec", LogLevel::DEBUG ); |
190
|
|
|
$out = $this->template->render( $this->state, $this->props ); |
191
|
|
|
if (!( $out instanceof Response )) { |
192
|
|
|
throw new \Exception( get_class( $this->template ) . " returned invalid response. Should have been an instance of ViewComponentResponse" ); |
193
|
|
|
} |
194
|
|
|
} |
195
|
|
|
return $out; |
196
|
|
|
} |
197
|
|
|
|
198
|
|
|
/** |
199
|
|
|
* Execute a component method within the page or component. |
200
|
|
|
* Called first on a top level component which then passes the call down to the appropriate sub-component (or executes on itself if appropriate). |
201
|
|
|
* @param array|string $methodName A methodname in the format subComponent.anotherSubComponent.methodName. Either dotted string as described, or parts in an array. The top level page component shouldn't be included |
202
|
|
|
* @param array $args |
203
|
|
|
* @throws \Exception |
204
|
|
|
* @return Response |
205
|
|
|
*/ |
206
|
|
|
protected function execMethod( $methodName, array $args = null ) |
207
|
|
|
{ |
208
|
|
|
if (!is_array( $methodName )) { |
209
|
|
|
$methodName = explode( '.', $methodName ); |
210
|
|
|
} |
211
|
|
|
if (count( $methodName ) == 1) { |
212
|
|
|
$methodName = $methodName[ 0 ] . 'Handler'; |
213
|
|
|
$out = $this->$methodName( $args ); |
214
|
|
|
}else { |
215
|
|
|
$childName = array_shift( $methodName ); |
216
|
|
|
$child = $this->childComponents[ $childName ]; |
217
|
|
|
if ($child instanceof AbstractViewComponent) { |
218
|
|
|
$out = $child->execMethod( $methodName, $args ); |
219
|
|
|
}else { |
220
|
|
|
throw new \Exception( implode( ".", $methodName ) . " is not a valid method." ); |
221
|
|
|
} |
222
|
|
|
} |
223
|
|
|
if (!( $out instanceof Response )) { |
224
|
|
|
$nameStr = is_array( $methodName )?implode( ".", $methodName ):$methodName; |
225
|
|
|
throw new \Exception( $nameStr . " returned invalid response. Should have been an instance of ViewComponentResponse" ); |
226
|
|
|
} |
227
|
|
|
return $out; |
228
|
|
|
} |
229
|
|
|
|
230
|
|
|
/** |
231
|
|
|
* @param $execMethod |
232
|
|
|
* @return string |
233
|
|
|
*/ |
234
|
|
|
public function getExecPath( $execMethod ) |
235
|
|
|
{ |
236
|
|
|
$path = $this->getPath(); |
237
|
|
|
return ( $path === null?$execMethod:$path . '.' . $execMethod ); |
238
|
|
|
} |
239
|
|
|
|
240
|
|
|
/** |
241
|
|
|
* @return AbstractViewComponent |
242
|
|
|
*/ |
243
|
|
|
public function getParent() |
244
|
|
|
{ |
245
|
|
|
return $this->parent; |
246
|
|
|
} |
247
|
|
|
|
248
|
|
|
|
249
|
|
|
/** |
250
|
|
|
* @param $string |
251
|
|
|
*/ |
252
|
|
|
protected function setFlashMessage( $string ) |
253
|
|
|
{ |
254
|
|
|
$this->flashMessage = $string; |
255
|
|
|
} |
256
|
|
|
|
257
|
|
|
/** |
258
|
|
|
* @param $string |
259
|
|
|
*/ |
260
|
|
|
protected function setFlashError( $string ) |
261
|
|
|
{ |
262
|
|
|
$this->flashError = $string; |
263
|
|
|
} |
264
|
|
|
|
265
|
|
|
/** |
266
|
|
|
* Get the root component of the hierarchy |
267
|
|
|
* |
268
|
|
|
* @return AbstractViewComponent |
269
|
|
|
*/ |
270
|
|
|
protected function getRootComponent() |
271
|
|
|
{ |
272
|
|
|
$cur = $this; |
273
|
|
|
while ($cur->parent !== null) { |
274
|
|
|
$cur = $cur->parent; |
275
|
|
|
} |
276
|
|
|
return $cur; |
277
|
|
|
} |
278
|
|
|
|
279
|
|
|
/** |
280
|
|
|
* Load or configure the component's template as necessary. |
281
|
|
|
* Called just before the template is used so can depend on $this->state to select template. |
282
|
|
|
* |
283
|
|
|
* @return void |
284
|
|
|
*/ |
285
|
|
|
abstract protected function initTemplate(); |
286
|
|
|
|
287
|
|
|
/** |
288
|
|
|
* Initialise $this->state with either a new ViewState or an appropriate subclass |
289
|
|
|
* @return void |
290
|
|
|
*/ |
291
|
|
|
abstract protected function initState(); |
292
|
|
|
|
293
|
|
|
/** |
294
|
|
|
* Return the this object's path in the current component hierarchy |
295
|
|
|
* @return string |
296
|
|
|
*/ |
297
|
|
|
protected function getPath() |
298
|
|
|
{ |
299
|
|
|
if (null === $this->parent) { |
300
|
|
|
return null; |
301
|
|
|
} |
302
|
|
|
if (null !== ( $pPath = $this->parent->getPath() )) { |
303
|
|
|
return $pPath . '.' . $this->handle; |
304
|
|
|
}else { |
305
|
|
|
return $this->handle; |
306
|
|
|
} |
307
|
|
|
} |
308
|
|
|
|
309
|
|
|
/** |
310
|
|
|
* Can create a child component on this component and return it. |
311
|
|
|
* |
312
|
|
|
* @param string $handle |
313
|
|
|
* @param string $type |
314
|
|
|
* @param array $props |
315
|
|
|
* @return AbstractViewComponent |
316
|
|
|
* @throws \Exception |
317
|
|
|
*/ |
318
|
|
|
protected function addOrUpdateChild( $handle, $type, array $props = [ ] ) |
319
|
|
|
{ |
320
|
|
|
$this->log( "Adding/updating child '{$handle}' of type {$type}", LogLevel::DEBUG ); |
321
|
|
|
if (!isset( $this->childComponents[ $handle ] )) { |
322
|
|
|
if( ! class_exists( $type ) ){ |
323
|
|
|
throw new \Exception( "Class '{$type}' for sub-component does not exist." ); |
324
|
|
|
} |
325
|
|
|
$child = new $type( $handle, $this, $this->exec, $this->logger ); |
326
|
|
|
$this->childComponents[ $handle ] = $child; |
327
|
|
|
}else { |
328
|
|
|
// exec, di and logger are set recursively in rehydrate() |
329
|
|
|
$child = $this->childComponents[ $handle ]; |
330
|
|
|
} |
331
|
|
|
$child->updateProps( $props ); |
332
|
|
|
$child->updateState(); |
333
|
|
|
} |
334
|
|
|
|
335
|
|
|
/** |
336
|
|
|
* Render a child component. |
337
|
|
|
* |
338
|
|
|
* @param $handle |
339
|
|
|
* @return Response |
340
|
|
|
* @throws \Exception |
341
|
|
|
*/ |
342
|
|
|
public function renderChild( $handle ) |
343
|
|
|
{ |
344
|
|
|
if (!$this->childComponents[ $handle ]) { |
345
|
|
|
$message = "Attempted to render nonexistent child component with handle '{$handle}'"; |
346
|
|
|
$this->log( $message, LogLevel::CRITICAL ); |
347
|
|
|
throw new \Exception( $message ); |
348
|
|
|
} |
349
|
|
|
return $this->childComponents[ $handle ]->render()->content; |
350
|
|
|
} |
351
|
|
|
|
352
|
|
|
/** |
353
|
|
|
* Using $this->props and $this->state, optionally update state and create/update child components via addOrUpdateChild(). |
354
|
|
|
* @return void |
355
|
|
|
*/ |
356
|
|
|
protected function updateState() |
357
|
|
|
{ |
358
|
|
|
// |
359
|
|
|
} |
360
|
|
|
|
361
|
|
|
/** |
362
|
|
|
* testInputs() compares a set of named inputs (props or args) in the associative array $inputs with an input specification. |
363
|
|
|
* It MUST be used by implementations' doUpdateState() and *Handler() methods to verify their input. |
364
|
|
|
* |
365
|
|
|
* $inputSpec is an array describing allowed inputs with a similar design to php method sigs. |
366
|
|
|
* The keys are field names, the values are 0 to 2 entry arrays with the following entries: [type,default]. |
367
|
|
|
* Type can be set to null to allow any type, or if there is no default it can be left empty. |
368
|
|
|
* If default is not set then the field is required. If default is null then that us used as the default value. |
369
|
|
|
* As defaults can be any value, it's possible to create an object or callable to use as a default. |
370
|
|
|
* Type can be any of the types described at http://www.php.net/manual/en/function.gettype.php except null or unknown type. In addition it can be any class name, callable, float, bool or int. |
371
|
|
|
* E.g. |
372
|
|
|
* [ |
373
|
|
|
* 'anyTypeRequired'=>[], |
374
|
|
|
* 'anyTypeRequired2'=>[null], |
375
|
|
|
* 'anyTypeOptional'=>[null,null], |
376
|
|
|
* 'boolRequired'=>['bool'], |
377
|
|
|
* 'boolRequired2'=>['boolean'], |
378
|
|
|
* 'intOptional'=>['int',3], |
379
|
|
|
* 'intRequired'=>['integer'], |
380
|
|
|
* 'doubleRequired'=>['double'], |
381
|
|
|
* 'floatRequired'=>['float'], |
382
|
|
|
* 'stringRequired'=>['string'], |
383
|
|
|
* 'arrayRequired'=>['array'], |
384
|
|
|
* 'objectRequired'=>['object'], |
385
|
|
|
* 'resourceRequired'=>['resource'], |
386
|
|
|
* 'callableRequired'=>['callable'], |
387
|
|
|
* 'SomeClassRequired'=>['SomeClass'], |
388
|
|
|
* 'SomeClassOptional'=>['SomeClass',null], |
389
|
|
|
* 'SomeClassWithPrebuiltDefault'=>['SomeClass', new SomeClass( 'something' )], |
390
|
|
|
* ] |
391
|
|
|
* @param array $inputSpec See above |
392
|
|
|
* @param array $inputs |
393
|
|
|
* @throws \Exception |
394
|
|
|
*/ |
395
|
|
|
protected function testInputs( array $inputSpec, array &$inputs ) |
396
|
|
|
{ |
397
|
|
|
|
398
|
|
|
foreach ($inputSpec as $fieldName => $fieldSpec) { |
399
|
|
|
// Required field |
400
|
|
View Code Duplication |
if (( count( $fieldSpec ) < 2 )) { |
|
|
|
|
401
|
|
|
if (!isset( $inputs[ $fieldName ] )) { |
402
|
|
|
$calledFunc = debug_backtrace()[1]['function']; |
403
|
|
|
$callerFunc = debug_backtrace()[2]['function']; |
404
|
|
|
$callerClass = debug_backtrace()[2]['class']; |
405
|
|
|
$parentText = ''; |
406
|
|
|
if( $this->parent !== null ){ |
407
|
|
|
$parentText = " (parent component is ".get_class($this->parent).")"; |
408
|
|
|
} |
409
|
|
|
throw new \Exception( $fieldName . " is a required field for " . get_class( $this )."::{$calledFunc}() called from {$callerClass}::{$callerFunc}(){$parentText}" ); |
410
|
|
|
} |
411
|
|
|
} |
412
|
|
|
// Set default is unset |
413
|
|
|
if (!isset( $inputs[ $fieldName ] )) { |
414
|
|
|
$inputs[ $fieldName ] = $fieldSpec[ 1 ]; |
415
|
|
|
} |
416
|
|
|
// Check type |
417
|
|
|
// Any type allowed, continue |
418
|
|
|
if (!isset( $fieldSpec[ 0 ] ) || $fieldSpec[ 0 ] === null) { |
419
|
|
|
continue; |
420
|
|
|
} |
421
|
|
|
$requiredType = $fieldSpec[ 0 ]; |
422
|
|
|
$input = $inputs[ $fieldName ]; |
423
|
|
|
// Specific type required |
424
|
|
|
// Null is allowed |
425
|
|
|
if (!is_null( $input )) { |
426
|
|
|
switch ($requiredType) { |
427
|
|
|
case "boolean": |
428
|
|
|
case "bool": |
429
|
|
|
$failed = !is_bool( $input ); |
430
|
|
|
break; |
431
|
|
|
case "integer": |
432
|
|
|
case "int": |
433
|
|
|
$failed = !is_int( $input+0 ); |
434
|
|
|
break; |
435
|
|
|
case "double": |
436
|
|
|
$failed = !is_double( $input+0 ); |
437
|
|
|
break; |
438
|
|
|
case "float": |
439
|
|
|
$failed = !is_float( $input+0 ); |
440
|
|
|
break; |
441
|
|
|
case "string": |
442
|
|
|
$failed = !is_string( $input ); |
443
|
|
|
break; |
444
|
|
|
case "array": |
445
|
|
|
$failed = !is_array( $input ); |
446
|
|
|
break; |
447
|
|
|
case "object": |
448
|
|
|
$failed = !is_object( $input ); |
449
|
|
|
break; |
450
|
|
|
case "resource": |
451
|
|
|
$failed = !is_resource( $input ); |
452
|
|
|
break; |
453
|
|
|
case "callable": |
454
|
|
|
$failed = !is_callable( $input ); |
455
|
|
|
break; |
456
|
|
|
default: |
457
|
|
|
$failed = !( $input instanceof $requiredType ); |
458
|
|
|
} |
459
|
|
View Code Duplication |
if ($failed) { |
|
|
|
|
460
|
|
|
$calledFunc = debug_backtrace()[1]['function']; |
461
|
|
|
$callerFunc = debug_backtrace()[2]['function']; |
462
|
|
|
$callerClass = debug_backtrace()[2]['class']; |
463
|
|
|
$parentText = ''; |
464
|
|
|
if( $this->parent !== null ){ |
465
|
|
|
$parentText = " (parent component is ".get_class($this->parent).")"; |
466
|
|
|
} |
467
|
|
|
throw new \Exception( $fieldName . " should be of type " . $requiredType . "in " . get_class( $this )."::{$calledFunc}() called from {$callerClass}::{$callerFunc}(){$parentText}" ); |
468
|
|
|
} |
469
|
|
|
} |
470
|
|
|
} |
471
|
|
|
} |
472
|
|
|
|
473
|
|
|
/** |
474
|
|
|
* Update the full component view tree. |
475
|
|
|
* |
476
|
|
|
* @var array $props |
477
|
|
|
*/ |
478
|
|
|
public function updateView( $props ) |
479
|
|
|
{ |
480
|
|
|
$this->updateProps( $props ); |
481
|
|
|
$this->updateState(); |
482
|
|
|
} |
483
|
|
|
|
484
|
|
|
/** |
485
|
|
|
* Update the component's properties ('input') array |
486
|
|
|
* |
487
|
|
|
* @var array $props |
488
|
|
|
*/ |
489
|
|
|
protected function updateProps( $props ) |
490
|
|
|
{ |
491
|
|
|
$this->log( "Storing new props: " . var_export( $props, true ), LogLevel::DEBUG ); |
492
|
|
|
$this->props = $props; |
493
|
|
|
} |
494
|
|
|
|
495
|
|
|
protected function forceResponse( Response $response ) |
496
|
|
|
{ |
497
|
|
|
$this->forceResponse = $response; |
498
|
|
|
} |
499
|
|
|
|
500
|
|
|
/** |
501
|
|
|
* @param ExecHelper $execHelper |
502
|
|
|
*/ |
503
|
|
|
private function setExec( ExecHelper $execHelper ) |
504
|
|
|
{ |
505
|
|
|
$this->exec = clone $execHelper; |
506
|
|
|
$this->exec->setComponent( $this ); |
507
|
|
|
foreach( $this->childComponents as $child ){ |
508
|
|
|
$child->setExec( $execHelper ); |
509
|
|
|
} |
510
|
|
|
} |
511
|
|
|
|
512
|
|
|
/** |
513
|
|
|
* |
514
|
|
|
*/ |
515
|
|
|
private function handleDependencyInjection() |
516
|
|
|
{ |
517
|
|
|
// It's a little strange that the object injects its own |
518
|
|
|
// dependencies but it means that callers don't need to do |
519
|
|
|
// it manually and you still get the advantage that the deps |
520
|
|
|
// are specified in the optional injectDependencies() method's |
521
|
|
|
// signature |
522
|
|
|
$this->log( "Dependency injection...", LogLevel::DEBUG ); |
523
|
|
|
DependencyInjector::instance()->injectIntoMethod( $this ); |
524
|
|
|
foreach( $this->childComponents as $child ){ |
525
|
|
|
$child->handleDependencyInjection(); |
526
|
|
|
} |
527
|
|
|
} |
528
|
|
|
|
529
|
|
|
/** |
530
|
|
|
* @param LoggerInterface $logger |
531
|
|
|
*/ |
532
|
|
|
private function setLogger( LoggerInterface $logger = null ) |
533
|
|
|
{ |
534
|
|
|
if( null !== $logger ){ |
535
|
|
|
$this->logger = $logger; |
536
|
|
|
/** @var AbstractViewComponent $child */ |
537
|
|
|
foreach( $this->childComponents as $child ){ |
538
|
|
|
$child->setLogger( $logger ); |
539
|
|
|
} |
540
|
|
|
} |
541
|
|
|
} |
542
|
|
|
} |
543
|
|
|
|
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.
The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.
This check looks for comments that seem to be mostly valid code and reports them.