This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | namespace Alpha\View; |
||
4 | |||
5 | use Alpha\Controller\Front\FrontController; |
||
6 | use Alpha\Util\Logging\Logger; |
||
7 | use Alpha\Util\Config\ConfigProvider; |
||
8 | use Alpha\Model\ActiveRecord; |
||
9 | use Alpha\Model\Type\DEnum; |
||
10 | use Alpha\Exception\IllegalArguementException; |
||
11 | use Alpha\Util\Service\ServiceFactory; |
||
12 | use Alpha\View\Renderer\RendererProviderInterface; |
||
13 | use ReflectionClass; |
||
14 | |||
15 | /** |
||
16 | * The master rendering view class for the Alpha Framework. |
||
17 | * |
||
18 | * @since 1.0 |
||
19 | * |
||
20 | * @author John Collins <[email protected]> |
||
21 | * @license http://www.opensource.org/licenses/bsd-license.php The BSD License |
||
22 | * @copyright Copyright (c) 2019, John Collins (founder of Alpha Framework). |
||
23 | * All rights reserved. |
||
24 | * |
||
25 | * <pre> |
||
26 | * Redistribution and use in source and binary forms, with or |
||
27 | * without modification, are permitted provided that the |
||
28 | * following conditions are met: |
||
29 | * |
||
30 | * * Redistributions of source code must retain the above |
||
31 | * copyright notice, this list of conditions and the |
||
32 | * following disclaimer. |
||
33 | * * Redistributions in binary form must reproduce the above |
||
34 | * copyright notice, this list of conditions and the |
||
35 | * following disclaimer in the documentation and/or other |
||
36 | * materials provided with the distribution. |
||
37 | * * Neither the name of the Alpha Framework nor the names |
||
38 | * of its contributors may be used to endorse or promote |
||
39 | * products derived from this software without specific |
||
40 | * prior written permission. |
||
41 | * |
||
42 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND |
||
43 | * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, |
||
44 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
||
45 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
||
46 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR |
||
47 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||
48 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
||
49 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
||
50 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
||
51 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
||
52 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE |
||
53 | * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||
54 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||
55 | * </pre> |
||
56 | */ |
||
57 | class View |
||
58 | { |
||
59 | /** |
||
60 | * The business object that will be rendered. |
||
61 | * |
||
62 | * @var \Alpha\Model\ActiveRecord |
||
63 | * |
||
64 | * @since 1.0 |
||
65 | */ |
||
66 | protected $record; |
||
67 | |||
68 | /** |
||
69 | * The rendering provider that will be used to render the active record. |
||
70 | * |
||
71 | * @var \Alpha\View\Renderer\RendererProviderInterface |
||
72 | * |
||
73 | * @since 1.2 |
||
74 | */ |
||
75 | private static $provider; |
||
76 | |||
77 | /** |
||
78 | * Trace logger. |
||
79 | * |
||
80 | * @var Logger |
||
81 | * |
||
82 | * @since 1.0 |
||
83 | */ |
||
84 | private static $logger = null; |
||
85 | |||
86 | /** |
||
87 | * Constructor for the View. As this is protected, use the View::getInstance method from a public scope. |
||
88 | * |
||
89 | * @param ActiveRecord $record The main business object that this view is going to render |
||
90 | * @param string $acceptHeader Optionally pass the HTTP Accept header to select the correct renderer provider. |
||
91 | * |
||
92 | * @throws \Alpha\Exception\IllegalArguementException |
||
93 | * |
||
94 | * @since 1.0 |
||
95 | */ |
||
96 | protected function __construct($record, $acceptHeader = null) |
||
97 | { |
||
98 | self::$logger = new Logger('View'); |
||
99 | self::$logger->debug('>>__construct(Record=['.var_export($record, true).'], acceptHeader=['.$acceptHeader.'])'); |
||
100 | |||
101 | $config = ConfigProvider::getInstance(); |
||
102 | |||
103 | if ($record instanceof ActiveRecord) { |
||
104 | $this->record = $record; |
||
105 | } else { |
||
106 | throw new IllegalArguementException('The record type provided ['.get_class($record).'] is not defined anywhere!'); |
||
107 | } |
||
108 | |||
109 | self::setProvider($config->get('app.renderer.provider.name'), $acceptHeader); |
||
110 | self::$provider->setRecord($this->record); |
||
111 | |||
112 | self::$logger->debug('<<__construct'); |
||
113 | } |
||
114 | |||
115 | /** |
||
116 | * Static method which returns a View object or a custom child view for the Record specified |
||
117 | * if one exists. |
||
118 | * |
||
119 | * @param ActiveRecord $record The main business object that this view is going to render |
||
120 | * @param bool $returnParent Flag to enforce the return of this object instead of a child (defaults to false) |
||
121 | * @param string $acceptHeader Optionally pass the HTTP Accept header to select the correct renderer provider. |
||
122 | * |
||
123 | * @return View Returns a View object, or a child view object if one exists for this record |
||
124 | * |
||
125 | * @since 1.0 |
||
126 | */ |
||
127 | public static function getInstance($record, $returnParent = false, $acceptHeader = null) |
||
128 | { |
||
129 | if (self::$logger == null) { |
||
130 | self::$logger = new Logger('View'); |
||
131 | } |
||
132 | self::$logger->debug('>>getInstance(Record=['.var_export($record, true).'], returnParent=['.$returnParent.'], acceptHeader=['.$acceptHeader.'])'); |
||
133 | |||
134 | $class = new ReflectionClass($record); |
||
135 | $childView = $class->getShortname(); |
||
136 | $childView = $childView.'View'; |
||
137 | |||
138 | // Check to see if a custom view exists for this record, and if it does return that view instead |
||
139 | if (!$returnParent) { |
||
140 | $className = '\Alpha\View\\'.$childView; |
||
141 | |||
142 | if (class_exists($className)) { |
||
143 | self::$logger->debug('<<getInstance [new '.$className.'('.get_class($record).')]'); |
||
144 | |||
145 | $instance = new $className($record, $acceptHeader); |
||
146 | |||
147 | return $instance; |
||
148 | } |
||
149 | |||
150 | $className = '\View\\'.$childView; |
||
151 | |||
152 | if (class_exists('\View\\'.$childView)) { |
||
153 | self::$logger->debug('<<getInstance [new '.$className.'('.get_class($record).')]'); |
||
154 | |||
155 | $instance = new $className($record, $acceptHeader); |
||
156 | |||
157 | return $instance; |
||
158 | } |
||
159 | |||
160 | self::$logger->debug('<<getInstance [new View('.get_class($record).', '.$acceptHeader.')]'); |
||
161 | |||
162 | return new self($record, $acceptHeader); |
||
163 | } else { |
||
164 | self::$logger->debug('<<getInstance [new View('.get_class($record).', '.$acceptHeader.')]'); |
||
165 | |||
166 | return new self($record, $acceptHeader); |
||
167 | } |
||
168 | } |
||
169 | |||
170 | /** |
||
171 | * Simple setter for the view business object. |
||
172 | * |
||
173 | * @param \Alpha\Model\ActiveRecord $record |
||
174 | * |
||
175 | * @throws \Alpha\Exception\IllegalArguementException |
||
176 | * |
||
177 | * @since 1.0 |
||
178 | */ |
||
179 | public function setRecord($record) |
||
180 | { |
||
181 | self::$logger->debug('>>setRecord(Record=['.var_export($record, true).'])'); |
||
182 | |||
183 | if ($record instanceof \Alpha\Model\ActiveRecord) { |
||
184 | $this->record = $record; |
||
185 | self::$provider->setRecord($this->record); |
||
186 | } else { |
||
187 | throw new IllegalArguementException('The Record provided ['.get_class($record).'] is not defined anywhere!'); |
||
188 | } |
||
189 | |||
190 | self::$logger->debug('<<setRecord'); |
||
191 | } |
||
192 | |||
193 | /** |
||
194 | * Gets the Record attached to this view (if any). |
||
195 | * |
||
196 | * @return \Alpha\Model\ActiveRecord |
||
197 | * |
||
198 | * @since 1.0 |
||
199 | */ |
||
200 | public function getRecord() |
||
201 | { |
||
202 | return $this->record; |
||
203 | } |
||
204 | |||
205 | /** |
||
206 | * Renders the default create view. |
||
207 | * |
||
208 | * @param array $fields Hash array of fields to pass to the template |
||
209 | * |
||
210 | * @return string |
||
211 | * |
||
212 | * @since 1.0 |
||
213 | */ |
||
214 | public function createView($fields = array()) |
||
215 | { |
||
216 | self::$logger->debug('>>createView(fields=['.var_export($fields, true).'])'); |
||
217 | |||
218 | if (method_exists($this, 'before_createView_callback')) { |
||
219 | $this->{'before_createView_callback'}(); |
||
220 | } |
||
221 | |||
222 | $body = self::$provider->createView($fields); |
||
223 | |||
224 | if (method_exists($this, 'after_createView_callback')) { |
||
225 | $this->{'after_createView_callback'}(); |
||
226 | } |
||
227 | |||
228 | self::$logger->debug('<<createView'); |
||
229 | |||
230 | return $body; |
||
231 | } |
||
232 | |||
233 | /** |
||
234 | * Renders a form to enable object editing. |
||
235 | * |
||
236 | * @param array $fields Hash array of fields to pass to the template |
||
237 | * |
||
238 | * @return string |
||
239 | * |
||
240 | * @since 1.0 |
||
241 | */ |
||
242 | public function editView($fields = array()) |
||
243 | { |
||
244 | self::$logger->debug('>>editView(fields=['.var_export($fields, true).'])'); |
||
245 | |||
246 | if (method_exists($this, 'before_editView_callback')) { |
||
247 | $this->{'before_editView_callback'}(); |
||
248 | } |
||
249 | |||
250 | $body = self::$provider->editView($fields); |
||
251 | |||
252 | if (method_exists($this, 'after_editView_callback')) { |
||
253 | $this->{'after_editView_callback'}(); |
||
254 | } |
||
255 | |||
256 | self::$logger->debug('<<editView'); |
||
257 | |||
258 | return $body; |
||
259 | } |
||
260 | |||
261 | /** |
||
262 | * Renders the list view. |
||
263 | * |
||
264 | * @param array $fields Hash array of fields to pass to the template |
||
265 | * |
||
266 | * @return string |
||
267 | * |
||
268 | * @since 1.0 |
||
269 | */ |
||
270 | public function listView($fields = array()) |
||
271 | { |
||
272 | self::$logger->debug('>>listView(fields=['.var_export($fields, true).'])'); |
||
273 | |||
274 | if (method_exists($this, 'before_listView_callback')) { |
||
275 | $this->{'before_listView_callback'}(); |
||
276 | } |
||
277 | |||
278 | $body = self::$provider->listView($fields); |
||
279 | |||
280 | if (method_exists($this, 'after_listView_callback')) { |
||
281 | $this->{'after_listView_callback'}(); |
||
282 | } |
||
283 | |||
284 | self::$logger->debug('<<listView'); |
||
285 | |||
286 | return $body; |
||
287 | } |
||
288 | |||
289 | /** |
||
290 | * Renders a detailed view of the object (read-only). |
||
291 | * |
||
292 | * @param array $fields Hash array of fields to pass to the template |
||
293 | * |
||
294 | * @return string |
||
295 | * |
||
296 | * @since 1.0 |
||
297 | */ |
||
298 | public function detailedView($fields = array()) |
||
299 | { |
||
300 | self::$logger->debug('>>detailedView(fields=['.var_export($fields, true).'])'); |
||
301 | |||
302 | if (method_exists($this, 'before_detailedView_callback')) { |
||
303 | $this->{'before_detailedView_callback'}(); |
||
304 | } |
||
305 | |||
306 | $body = self::$provider->detailedView($fields); |
||
307 | |||
308 | if (method_exists($this, 'after_detailedView_callback')) { |
||
309 | $this->{'after_detailedView_callback'}(); |
||
310 | } |
||
311 | |||
312 | self::$logger->debug('<<detailedView'); |
||
313 | |||
314 | return $body; |
||
315 | } |
||
316 | |||
317 | /** |
||
318 | * Renders the admin view for the business object screen. |
||
319 | * |
||
320 | * @param array $fields Hash array of fields to pass to the template |
||
321 | * |
||
322 | * @return string |
||
323 | * |
||
324 | * @since 1.0 |
||
325 | */ |
||
326 | public function adminView($fields = array()) |
||
327 | { |
||
328 | self::$logger->debug('>>adminView(fields=['.var_export($fields, true).'])'); |
||
329 | |||
330 | if (method_exists($this, 'before_adminView_callback')) { |
||
331 | $this->{'before_adminView_callback'}(); |
||
332 | } |
||
333 | |||
334 | $body = self::$provider->adminView($fields); |
||
335 | |||
336 | if (method_exists($this, 'after_adminView_callback')) { |
||
337 | $this->{'after_adminView_callback'}(); |
||
338 | } |
||
339 | |||
340 | self::$logger->debug('<<adminView'); |
||
341 | |||
342 | return $body; |
||
343 | } |
||
344 | |||
345 | /** |
||
346 | * Method to render the page header content. |
||
347 | * |
||
348 | * @param \Alpha\Controller\Controller $controller |
||
349 | * |
||
350 | * @return string |
||
351 | * |
||
352 | * @throws \Alpha\Exception\IllegalArguementException |
||
353 | * |
||
354 | * @since 1.0 |
||
355 | */ |
||
356 | public static function displayPageHead($controller) |
||
357 | { |
||
358 | if (self::$logger == null) { |
||
359 | self::$logger = new Logger('View'); |
||
360 | } |
||
361 | self::$logger->debug('>>displayPageHead(controller=['.var_export($controller, true).'])'); |
||
362 | |||
363 | if (method_exists($controller, 'before_displayPageHead_callback')) { |
||
364 | $controller->{'before_displayPageHead_callback'}(); |
||
365 | } |
||
366 | |||
367 | $config = ConfigProvider::getInstance(); |
||
368 | |||
369 | if (!self::$provider instanceof RendererProviderInterface) { |
||
370 | self::setProvider($config->get('app.renderer.provider.name')); |
||
371 | } |
||
372 | |||
373 | $provider = self::$provider; |
||
374 | $header = $provider::displayPageHead($controller); |
||
375 | |||
376 | if (method_exists($controller, 'after_displayPageHead_callback')) { |
||
377 | $header .= $controller->{'after_displayPageHead_callback'}(); |
||
378 | } |
||
379 | |||
380 | self::$logger->debug('<<displayPageHead ['.$header.']'); |
||
381 | |||
382 | return $header; |
||
383 | } |
||
384 | |||
385 | /** |
||
386 | * Method to render the page footer content. |
||
387 | * |
||
388 | * @param \Alpha\Controller\Controller $controller |
||
389 | * |
||
390 | * @return string |
||
391 | * |
||
392 | * @since 1.0 |
||
393 | */ |
||
394 | public static function displayPageFoot($controller) |
||
395 | { |
||
396 | if (self::$logger == null) { |
||
397 | self::$logger = new Logger('View'); |
||
398 | } |
||
399 | |||
400 | self::$logger->debug('>>displayPageFoot(controller=['.get_class($controller).'])'); |
||
401 | |||
402 | $config = ConfigProvider::getInstance(); |
||
403 | |||
404 | $footer = ''; |
||
405 | |||
406 | if (method_exists($controller, 'before_displayPageFoot_callback')) { |
||
407 | $footer .= $controller->before_displayPageFoot_callback(); |
||
0 ignored issues
–
show
|
|||
408 | } |
||
409 | |||
410 | if (!self::$provider instanceof RendererProviderInterface) { |
||
411 | self::setProvider($config->get('app.renderer.provider.name')); |
||
412 | } |
||
413 | |||
414 | $provider = self::$provider; |
||
415 | $footer .= $provider::displayPageFoot($controller); |
||
416 | |||
417 | if (method_exists($controller, 'after_displayPageFoot_callback')) { |
||
418 | $footer .= $controller->{'after_displayPageFoot_callback'}(); |
||
419 | } |
||
420 | |||
421 | self::$logger->debug('<<displayPageFoot ['.$footer.']'); |
||
422 | |||
423 | return $footer; |
||
424 | } |
||
425 | |||
426 | /** |
||
427 | * Method for rendering the pagination links. |
||
428 | * |
||
429 | * @param \Alpha\Controller\Controller $controller |
||
430 | * |
||
431 | * @return string |
||
432 | * |
||
433 | * @since 3.0 |
||
434 | */ |
||
435 | public static function displayPageLinks($controller) |
||
436 | { |
||
437 | $config = ConfigProvider::getInstance(); |
||
438 | |||
439 | $html = ''; |
||
440 | $recordCount = $controller->getRecordCount(); |
||
0 ignored issues
–
show
The method
getRecordCount() does not exist on Alpha\Controller\Controller . Did you maybe mean getRecord() ?
This check marks calls to methods that do not seem to exist on an object. This is most likely the result of a method being renamed without all references to it being renamed likewise. ![]() |
|||
441 | $start = $controller->getStart(); |
||
0 ignored issues
–
show
The method
getStart() does not exist on Alpha\Controller\Controller . Did you maybe mean getStartTime() ?
This check marks calls to methods that do not seem to exist on an object. This is most likely the result of a method being renamed without all references to it being renamed likewise. ![]() |
|||
442 | $limit = $controller->getLimit(); |
||
0 ignored issues
–
show
It seems like you code against a specific sub-type and not the parent class
Alpha\Controller\Controller as the method getLimit() does only exist in the following sub-classes of Alpha\Controller\Controller : Alpha\Controller\ActiveRecordController , Alpha\Controller\ArticleController , Alpha\Controller\DEnumController , Alpha\Controller\SequenceController , Alpha\Controller\TagController . Maybe you want to instanceof check for one of these explicitly?
Let’s take a look at an example: abstract class User
{
/** @return string */
abstract public function getPassword();
}
class MyUser extends User
{
public function getPassword()
{
// return something
}
public function getDisplayName()
{
// return some name.
}
}
class AuthSystem
{
public function authenticate(User $user)
{
$this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
// do something.
}
}
In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break. Available Fixes
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types
inside the if block in such a case.
![]() |
|||
443 | |||
444 | // the index of the last record displayed on this page |
||
445 | $last = $start+$config->get('app.list.page.amount'); |
||
446 | |||
447 | // ensure that the last index never overruns the total record count |
||
448 | if ($last > $recordCount) { |
||
449 | $last = $recordCount ; |
||
450 | } |
||
451 | |||
452 | // render a message for an empty list |
||
453 | if ($recordCount > 0) { |
||
454 | $html .= '<ul class="pagination">'; |
||
455 | } else { |
||
456 | $html .= '<p align="center">The list is empty. </p>'; |
||
457 | |||
458 | return $html; |
||
459 | } |
||
460 | |||
461 | // render "Previous" link |
||
462 | if ($start > 0) { |
||
463 | // handle secure URLs |
||
464 | if ($controller->getRequest()->getParam('token', null) != null) { |
||
465 | $url = FrontController::generateSecureURL('act=Alpha\Controller\ActiveRecordController&ActiveRecordType='.$controller->getRequest()->getParam('ActiveRecordType').'&start='.($start-$controller->getLimit()).'&limit='.$limit); |
||
0 ignored issues
–
show
It seems like you code against a specific sub-type and not the parent class
Alpha\Controller\Controller as the method getLimit() does only exist in the following sub-classes of Alpha\Controller\Controller : Alpha\Controller\ActiveRecordController , Alpha\Controller\ArticleController , Alpha\Controller\DEnumController , Alpha\Controller\SequenceController , Alpha\Controller\TagController . Maybe you want to instanceof check for one of these explicitly?
Let’s take a look at an example: abstract class User
{
/** @return string */
abstract public function getPassword();
}
class MyUser extends User
{
public function getPassword()
{
// return something
}
public function getDisplayName()
{
// return some name.
}
}
class AuthSystem
{
public function authenticate(User $user)
{
$this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
// do something.
}
}
In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break. Available Fixes
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types
inside the if block in such a case.
![]() |
|||
466 | } else { |
||
467 | $url = '/records/'.urlencode($controller->getRequest()->getParam('ActiveRecordType')).'/'.($start-$limit).'/'.$limit; |
||
468 | } |
||
469 | $html .= '<li><a href="'.$url.'"><<-Previous</a></li>'; |
||
470 | } elseif ($recordCount > $limit) { |
||
471 | $html .= '<li class="disabled"><a href="#"><<-Previous</a></li>'; |
||
472 | } |
||
473 | |||
474 | // render the page index links |
||
475 | if ($recordCount > $limit) { |
||
476 | $page = 1; |
||
477 | |||
478 | for ($i = 0; $i < $recordCount ; $i += $limit) { |
||
479 | if ($i != $start) { |
||
480 | // handle secure URLs |
||
481 | if ($controller->getRequest()->getParam('token', null) != null) { |
||
482 | $url = FrontController::generateSecureURL('act=Alpha\Controller\ActiveRecordController&ActiveRecordType='.$controller->getRequest()->getParam('ActiveRecordType').'&start='.$i.'&limit='.$limit); |
||
483 | } else { |
||
484 | $url = '/records/'.urlencode($controller->getRequest()->getParam('ActiveRecordType')).'/'.$i.'/'.$limit; |
||
485 | } |
||
486 | $html .= '<li><a href="'.$url.'">'.$page.'</a></li>'; |
||
487 | } elseif ($recordCount > $limit) { // render an anchor for the current page |
||
488 | $html .= '<li class="active"><a href="#">'.$page.'</a></li>'; |
||
489 | } |
||
490 | |||
491 | ++$page; |
||
492 | } |
||
493 | } |
||
494 | |||
495 | // render "Next" link |
||
496 | if ($recordCount > $last) { |
||
497 | // handle secure URLs |
||
498 | if ($controller->getRequest()->getParam('token', null) != null) { |
||
499 | $url = FrontController::generateSecureURL('act=Alpha\Controller\ActiveRecordController&ActiveRecordType='.$controller->getRequest()->getParam('ActiveRecordType').'&start='.($start+$limit).'&limit='.$limit); |
||
500 | } else { |
||
501 | $url = '/records/'.urlencode($controller->getRequest()->getParam('ActiveRecordType')).'/'.($start+$limit.'/'.$limit); |
||
502 | } |
||
503 | $html .= '<li><a href="'.$url.'">Next->></a></li>'; |
||
504 | } elseif ($recordCount > $limit) { |
||
505 | $html .= '<li class="disabled"><a href="#">Next->></a></li>'; |
||
506 | } |
||
507 | |||
508 | $html .= '</ul>'; |
||
509 | |||
510 | return $html; |
||
511 | } |
||
512 | |||
513 | /** |
||
514 | * Renders the content for an update (e.g. successful save) message. |
||
515 | * |
||
516 | * @param string $message |
||
517 | * |
||
518 | * @return string |
||
519 | * |
||
520 | * @since 1.0 |
||
521 | */ |
||
522 | public static function displayUpdateMessage($message) |
||
523 | { |
||
524 | if (self::$logger == null) { |
||
525 | self::$logger = new Logger('View'); |
||
526 | } |
||
527 | self::$logger->debug('>>displayUpdateMessage(message=['.$message.'])'); |
||
528 | |||
529 | $config = ConfigProvider::getInstance(); |
||
530 | |||
531 | if (!self::$provider instanceof RendererProviderInterface) { |
||
532 | self::setProvider($config->get('app.renderer.provider.name')); |
||
533 | } |
||
534 | |||
535 | $provider = self::$provider; |
||
536 | $message = $provider::displayUpdateMessage($message); |
||
537 | |||
538 | self::$logger->debug('<<displayUpdateMessage ['.$message.']'); |
||
539 | |||
540 | return $message; |
||
541 | } |
||
542 | |||
543 | /** |
||
544 | * Renders the content for an error (e.g. save failed) message. |
||
545 | * |
||
546 | * @param string $message |
||
547 | * |
||
548 | * @return string |
||
549 | * |
||
550 | * @since 1.0 |
||
551 | */ |
||
552 | public static function displayErrorMessage($message) |
||
553 | { |
||
554 | if (self::$logger == null) { |
||
555 | self::$logger = new Logger('View'); |
||
556 | } |
||
557 | self::$logger->debug('>>displayErrorMessage(message=['.$message.'])'); |
||
558 | |||
559 | $config = ConfigProvider::getInstance(); |
||
560 | |||
561 | if (!self::$provider instanceof RendererProviderInterface) { |
||
562 | self::setProvider($config->get('app.renderer.provider.name')); |
||
563 | } |
||
564 | |||
565 | $provider = self::$provider; |
||
566 | $message = $provider::displayErrorMessage($message); |
||
567 | |||
568 | self::$logger->debug('<<displayErrorMessage ['.$message.']'); |
||
569 | |||
570 | return $message; |
||
571 | } |
||
572 | |||
573 | /** |
||
574 | * Renders an error page with the supplied error code (typlically a HTTP code) and a message. |
||
575 | * |
||
576 | * @param string $code |
||
577 | * @param string $message |
||
578 | * |
||
579 | * @return string |
||
580 | * |
||
581 | * @since 1.0 |
||
582 | */ |
||
583 | public static function renderErrorPage($code, $message) |
||
584 | { |
||
585 | if (self::$logger == null) { |
||
586 | self::$logger = new Logger('View'); |
||
587 | } |
||
588 | self::$logger->debug('>>renderErrorPage(code=['.$code.'],message=['.$message.'])'); |
||
589 | |||
590 | $config = ConfigProvider::getInstance(); |
||
591 | |||
592 | if (!self::$provider instanceof RendererProviderInterface) { |
||
593 | self::setProvider($config->get('app.renderer.provider.name')); |
||
594 | } |
||
595 | |||
596 | $provider = self::$provider; |
||
597 | $message = $provider::renderErrorPage($code, $message); |
||
598 | |||
599 | self::$logger->debug('<<renderErrorPage ['.$message.']'); |
||
600 | |||
601 | return $message; |
||
602 | } |
||
603 | |||
604 | /** |
||
605 | * Method to render a hidden HTML form for posting the ID of an object to be deleted. |
||
606 | * |
||
607 | * @param string $URI The URI that the form will point to |
||
608 | * |
||
609 | * @return string |
||
610 | * |
||
611 | * @since 1.0 |
||
612 | */ |
||
613 | public static function renderDeleteForm($URI) |
||
614 | { |
||
615 | if (self::$logger == null) { |
||
616 | self::$logger = new Logger('View'); |
||
617 | } |
||
618 | self::$logger->debug('>>renderDeleteForm()'); |
||
619 | |||
620 | $config = ConfigProvider::getInstance(); |
||
621 | |||
622 | if (!self::$provider instanceof RendererProviderInterface) { |
||
623 | self::setProvider($config->get('app.renderer.provider.name')); |
||
624 | } |
||
625 | |||
626 | $provider = self::$provider; |
||
627 | $html = $provider::renderDeleteForm($URI); |
||
628 | |||
629 | self::$logger->debug('<<renderDeleteForm ['.$html.']'); |
||
630 | |||
631 | return $html; |
||
632 | } |
||
633 | |||
634 | /** |
||
635 | * Method to render a HTML form with two hidden, hashed (MD5) form fields to be used as |
||
636 | * a check to ensure that a post to the controller is being sent from the same server |
||
637 | * as hosting it. |
||
638 | * |
||
639 | * @return string |
||
640 | * |
||
641 | * @since 1.0 |
||
642 | */ |
||
643 | public static function renderSecurityFields() |
||
644 | { |
||
645 | if (self::$logger == null) { |
||
646 | self::$logger = new Logger('View'); |
||
647 | } |
||
648 | self::$logger->debug('>>renderSecurityFields()'); |
||
649 | |||
650 | $config = ConfigProvider::getInstance(); |
||
651 | |||
652 | if (!self::$provider instanceof RendererProviderInterface) { |
||
653 | self::setProvider($config->get('app.renderer.provider.name')); |
||
654 | } |
||
655 | |||
656 | $provider = self::$provider; |
||
657 | $html = $provider::renderSecurityFields(); |
||
658 | |||
659 | self::$logger->debug('<<renderSecurityFields ['.$html.']'); |
||
660 | |||
661 | return $html; |
||
662 | } |
||
663 | |||
664 | /** |
||
665 | * Method to render the default Integer HTML. |
||
666 | * |
||
667 | * @param string $name The field name |
||
668 | * @param string $label The label to apply to the field |
||
669 | * @param string $mode The field mode (create/edit/view) |
||
670 | * @param string $value The field value (optional) |
||
671 | * |
||
672 | * @return string |
||
673 | * |
||
674 | * @since 1.0 |
||
675 | */ |
||
676 | public function renderIntegerField($name, $label, $mode, $value = '') |
||
677 | { |
||
678 | self::$logger->debug('>>renderIntegerField(name=['.$name.'], label=['.$label.'], mode=['.$mode.'], value=['.$value.']'); |
||
679 | |||
680 | $html = self::$provider->renderIntegerField($name, $label, $mode, $value); |
||
681 | |||
682 | self::$logger->debug('<<renderIntegerField ['.$html.']'); |
||
683 | |||
684 | return $html; |
||
685 | } |
||
686 | |||
687 | /** |
||
688 | * Method to render the default Double HTML. |
||
689 | * |
||
690 | * @param string $name The field name |
||
691 | * @param string $label The label to apply to the field |
||
692 | * @param string $mode The field mode (create/edit/view) |
||
693 | * @param string $value The field value (optional) |
||
694 | * |
||
695 | * @return string |
||
696 | * |
||
697 | * @since 1.0 |
||
698 | */ |
||
699 | public function renderDoubleField($name, $label, $mode, $value = '') |
||
700 | { |
||
701 | self::$logger->debug('>>renderDoubleField(name=['.$name.'], label=['.$label.'], mode=['.$mode.'], value=['.$value.'])'); |
||
702 | |||
703 | $html = self::$provider->renderDoubleField($name, $label, $mode, $value); |
||
704 | |||
705 | self::$logger->debug('<<renderDoubleField ['.$html.']'); |
||
706 | |||
707 | return $html; |
||
708 | } |
||
709 | |||
710 | /** |
||
711 | * Method to render the default Boolean HTML. |
||
712 | * |
||
713 | * @param string $name The field name |
||
714 | * @param string $label The label to apply to the field |
||
715 | * @param string $mode The field mode (create/edit/view) |
||
716 | * @param string $value The field value (optional) |
||
717 | * |
||
718 | * @return string |
||
719 | * |
||
720 | * @since 1.0 |
||
721 | */ |
||
722 | public function renderBooleanField($name, $label, $mode, $value = '') |
||
723 | { |
||
724 | self::$logger->debug('>>renderBooleanField(name=['.$name.'], label=['.$label.'], mode=['.$mode.'], value=['.$value.'])'); |
||
725 | |||
726 | $html = self::$provider->renderBooleanField($name, $label, $mode, $value); |
||
727 | |||
728 | self::$logger->debug('<<renderBooleanField ['.$html.']'); |
||
729 | |||
730 | return $html; |
||
731 | } |
||
732 | |||
733 | /** |
||
734 | * Method to render the default Enum HTML. |
||
735 | * |
||
736 | * @param string $name The field name |
||
737 | * @param string $label The label to apply to the field |
||
738 | * @param string $mode The field mode (create/edit/view) |
||
739 | * @param array $options The Enum options |
||
740 | * @param string $value The field value (optional) |
||
741 | * |
||
742 | * @return string |
||
743 | * |
||
744 | * @since 1.0 |
||
745 | */ |
||
746 | public function renderEnumField($name, $label, $mode, $options, $value = '') |
||
747 | { |
||
748 | self::$logger->debug('>>renderEnumField(name=['.$name.'], label=['.$label.'], mode=['.$mode.'], value=['.$value.'])'); |
||
749 | |||
750 | $html = self::$provider->renderEnumField($name, $label, $mode, $options, $value); |
||
751 | |||
752 | self::$logger->debug('<<renderEnumField ['.$html.']'); |
||
753 | |||
754 | return $html; |
||
755 | } |
||
756 | |||
757 | /** |
||
758 | * Method to render the default DEnum HTML. |
||
759 | * |
||
760 | * @param string $name The field name |
||
761 | * @param string $label The label to apply to the field |
||
762 | * @param string $mode The field mode (create/edit/view) |
||
763 | * @param array $options The DEnum options |
||
764 | * @param string $value The field value (optional) |
||
765 | * |
||
766 | * @return string |
||
767 | * |
||
768 | * @since 1.0 |
||
769 | */ |
||
770 | public function renderDEnumField($name, $label, $mode, $options, $value = '') |
||
771 | { |
||
772 | self::$logger->debug('>>renderDEnumField(name=['.$name.'], label=['.$label.'], mode=['.$mode.'], value=['.$value.'])'); |
||
773 | |||
774 | $html = self::$provider->renderDEnumField($name, $label, $mode, $options, $value); |
||
775 | |||
776 | self::$logger->debug('<<renderDEnumField ['.$html.']'); |
||
777 | |||
778 | return $html; |
||
779 | } |
||
780 | |||
781 | /** |
||
782 | * Method to render the default field HTML when type is not known. |
||
783 | * |
||
784 | * @param string $name The field name |
||
785 | * @param string $label The label to apply to the field |
||
786 | * @param string $mode The field mode (create/edit/view) |
||
787 | * @param string $value The field value (optional) |
||
788 | * |
||
789 | * @return string |
||
790 | * |
||
791 | * @since 1.0 |
||
792 | */ |
||
793 | public function renderDefaultField($name, $label, $mode, $value = '') |
||
794 | { |
||
795 | self::$logger->debug('>>renderDefaultField(name=['.$name.'], label=['.$label.'], mode=['.$mode.'], value=['.$value.'])'); |
||
796 | |||
797 | $html = self::$provider->renderDefaultField($name, $label, $mode, $value); |
||
798 | |||
799 | self::$logger->debug('<<renderDefaultField ['.$html.']'); |
||
800 | |||
801 | return $html; |
||
802 | } |
||
803 | |||
804 | /** |
||
805 | * render the default Text HTML. |
||
806 | * |
||
807 | * @param string $name The field name |
||
808 | * @param string $label The label to apply to the field |
||
809 | * @param string $mode The field mode (create/edit/view) |
||
810 | * @param string $value The field value (optional) |
||
811 | * |
||
812 | * @return string |
||
813 | * |
||
814 | * @since 1.0 |
||
815 | */ |
||
816 | public function renderTextField($name, $label, $mode, $value = '') |
||
817 | { |
||
818 | self::$logger->debug('>>renderTextField(name=['.$name.'], label=['.$label.'], mode=['.$mode.'], value=['.$value.'])'); |
||
819 | |||
820 | $html = self::$provider->renderTextField($name, $label, $mode, $value); |
||
821 | |||
822 | self::$logger->debug('<<renderTextField ['.$html.']'); |
||
823 | |||
824 | return $html; |
||
825 | } |
||
826 | |||
827 | /** |
||
828 | * render the default Relation HTML. |
||
829 | * |
||
830 | * @param string $name The field name |
||
831 | * @param string $label The label to apply to the field |
||
832 | * @param string $mode The field mode (create/edit/view) |
||
833 | * @param string $value The field value (optional) |
||
834 | * @param bool $expanded Render the related fields in expanded format or not (optional) |
||
835 | * @param bool $buttons Render buttons for expanding/contacting the related fields (optional) |
||
836 | * |
||
837 | * @return string |
||
838 | * |
||
839 | * @since 1.0 |
||
840 | */ |
||
841 | public function renderRelationField($name, $label, $mode, $value = '', $expanded = false, $buttons = true) |
||
842 | { |
||
843 | self::$logger->debug('>>renderRelationField(name=['.$name.'], label=['.$label.'], mode=['.$mode.'], value=['.$value.'], expanded=['.$expanded.'], buttons=['.$buttons.'])'); |
||
844 | |||
845 | $html = self::$provider->renderRelationField($name, $label, $mode, $value, $expanded, $buttons); |
||
846 | |||
847 | self::$logger->debug('<<renderRelationField ['.$html.']'); |
||
848 | |||
849 | return $html; |
||
850 | } |
||
851 | |||
852 | /** |
||
853 | * Renders all fields for the current Record in edit/create/view mode. |
||
854 | * |
||
855 | * @param string $mode (view|edit|create) |
||
856 | * @param array $filterFields Optional list of field names to exclude from rendering |
||
857 | * @param array $readOnlyFields Optional list of fields to render in a readonly fashion when rendering in create or edit mode |
||
858 | * |
||
859 | * @return string |
||
860 | * |
||
861 | * @since 1.0 |
||
862 | */ |
||
863 | public function renderAllFields($mode, $filterFields = array(), $readOnlyFields = array()) |
||
864 | { |
||
865 | self::$logger->debug('>>renderAllFields(mode=['.$mode.'], filterFields=['.var_export($filterFields, true).'], readOnlyFields=['.var_export($readOnlyFields, true).'])'); |
||
866 | |||
867 | $html = self::$provider->renderAllFields($mode, $filterFields, $readOnlyFields); |
||
868 | |||
869 | self::$logger->debug('<<renderAllFields ['.$html.']'); |
||
870 | |||
871 | return $html; |
||
872 | } |
||
873 | |||
874 | /** |
||
875 | * Loads a template for the Record specified if one exists. Lower level custom templates |
||
876 | * take precedence. |
||
877 | * |
||
878 | * @param \Alpha\Model\ActiveRecord $record |
||
879 | * @param string $mode |
||
880 | * @param array $fields |
||
881 | * |
||
882 | * @return string |
||
883 | * |
||
884 | * @since 1.0 |
||
885 | * |
||
886 | * @throws \Alpha\Exception\IllegalArguementException |
||
887 | */ |
||
888 | public static function loadTemplate($record, $mode, $fields = array()) |
||
889 | { |
||
890 | self::$logger->debug('>>loadTemplate(Record=['.var_export($record, true).'], mode=['.$mode.'], fields=['.var_export($fields, true).'])'); |
||
891 | |||
892 | $config = ConfigProvider::getInstance(); |
||
893 | |||
894 | // for each Record property, create a local variable holding its value |
||
895 | $reflection = new ReflectionClass(get_class($record)); |
||
896 | $properties = $reflection->getProperties(); |
||
897 | |||
898 | foreach ($properties as $propObj) { |
||
899 | $propName = $propObj->name; |
||
900 | |||
901 | if ($propName != 'logger' && !$propObj->isPrivate()) { |
||
902 | $prop = $record->getPropObject($propName); |
||
903 | if ($prop instanceof DEnum) { |
||
904 | ${$propName} = $prop->getDisplayValue(); |
||
905 | } else { |
||
906 | ${$propName} = $record->get($propName); |
||
907 | } |
||
908 | } |
||
909 | } |
||
910 | |||
911 | // loop over the $fields array and create a local variable for each key value |
||
912 | foreach (array_keys($fields) as $fieldName) { |
||
913 | ${$fieldName} = $fields[$fieldName]; |
||
914 | } |
||
915 | |||
916 | $filename = $mode.'.phtml'; |
||
917 | $class = new ReflectionClass($record); |
||
918 | $className = $class->getShortname(); |
||
919 | |||
920 | $customPath = $config->get('app.root').'src/View/Html/Templates/'.$className.'/'.$filename; |
||
921 | $defaultPath1 = $config->get('app.root').'vendor/alphadevx/alpha/Alpha/View/Renderer/Html/Templates/'.$className.'/'.$filename; |
||
922 | $defaultPath2 = $config->get('app.root').'vendor/alphadevx/alpha/Alpha/View/Renderer/Html/Templates/'.$filename; |
||
923 | $defaultPath3 = $config->get('app.root').'Alpha/View/Renderer/Html/Templates/'.$className.'/'.$filename; |
||
924 | $defaultPath4 = $config->get('app.root').'Alpha/View/Renderer/Html/Templates/'.$filename; |
||
925 | |||
926 | // Check to see if a custom template exists for this record, and if it does load that |
||
927 | if (file_exists($customPath)) { |
||
928 | self::$logger->debug('Loading template ['.$customPath.']'); |
||
929 | ob_start(); |
||
930 | require $customPath; |
||
931 | $html = ob_get_clean(); |
||
932 | |||
933 | self::$logger->debug('<<loadTemplate'); |
||
934 | return $html; |
||
935 | } elseif (file_exists($defaultPath1)) { |
||
936 | self::$logger->debug('Loading template ['.$defaultPath1.']'); |
||
937 | ob_start(); |
||
938 | require $defaultPath1; |
||
939 | $html = ob_get_clean(); |
||
940 | |||
941 | self::$logger->debug('<<loadTemplate'); |
||
942 | return $html; |
||
943 | } elseif (file_exists($defaultPath2)) { |
||
944 | self::$logger->debug('Loading template ['.$defaultPath2.']'); |
||
945 | ob_start(); |
||
946 | require $defaultPath2; |
||
947 | $html = ob_get_clean(); |
||
948 | |||
949 | self::$logger->debug('<<loadTemplate'); |
||
950 | return $html; |
||
951 | } elseif (file_exists($defaultPath3)) { |
||
952 | self::$logger->debug('Loading template ['.$defaultPath3.']'); |
||
953 | ob_start(); |
||
954 | require $defaultPath3; |
||
955 | $html = ob_get_clean(); |
||
956 | |||
957 | self::$logger->debug('<<loadTemplate'); |
||
958 | return $html; |
||
959 | } elseif (file_exists($defaultPath4)) { |
||
960 | self::$logger->debug('Loading template ['.$defaultPath4.']'); |
||
961 | ob_start(); |
||
962 | require $defaultPath4; |
||
963 | $html = ob_get_clean(); |
||
964 | |||
965 | self::$logger->debug('<<loadTemplate'); |
||
966 | return $html; |
||
967 | } else { |
||
968 | self::$logger->debug('<<loadTemplate'); |
||
969 | throw new IllegalArguementException('No ['.$mode.'] HTML template found for class ['.$className.']'); |
||
970 | } |
||
971 | } |
||
972 | |||
973 | /** |
||
974 | * Loads a template fragment from the Renderer/[type]/Fragments/[filename.ext] location. |
||
975 | * |
||
976 | * @param string $type Currently only html supported, later json and xml. |
||
977 | * @param string $fileName The name of the fragment file |
||
978 | * @param array $fields A hash array of field values to pass to the template fragment. |
||
979 | * |
||
980 | * @return string |
||
981 | * |
||
982 | * @since 1.2 |
||
983 | * |
||
984 | * @throws \Alpha\Exception\IllegalArguementException |
||
985 | */ |
||
986 | public static function loadTemplateFragment($type, $fileName, $fields = array()) |
||
987 | { |
||
988 | if (self::$logger == null) { |
||
989 | self::$logger = new Logger('View'); |
||
990 | } |
||
991 | self::$logger->debug('>>loadTemplateFragment(type=['.$type.'], fileName=['.$fileName.'], fields=['.var_export($fields, true).'])'); |
||
992 | |||
993 | $config = ConfigProvider::getInstance(); |
||
994 | |||
995 | // loop over the $fields array and create a local variable for each key value |
||
996 | foreach (array_keys($fields) as $fieldName) { |
||
997 | ${$fieldName} = $fields[$fieldName]; |
||
998 | } |
||
999 | |||
1000 | $customPath = $config->get('app.root').'src/View/'.ucfirst($type).'/Fragments/'.$fileName; |
||
1001 | $defaultPath1 = $config->get('app.root').'vendor/alphadevx/alpha/Alpha/View/Renderer/'.ucfirst($type).'/Fragments/'.$fileName; |
||
1002 | $defaultPath2 = $config->get('app.root').'Alpha/View/Renderer/'.ucfirst($type).'/Fragments/'.$fileName; |
||
1003 | |||
1004 | // Check to see if a custom template exists for this record, and if it does load that |
||
1005 | if (file_exists($customPath)) { |
||
1006 | self::$logger->debug('Loading template ['.$customPath.']'); |
||
1007 | ob_start(); |
||
1008 | require $customPath; |
||
1009 | $html = ob_get_clean(); |
||
1010 | |||
1011 | self::$logger->debug('<<loadTemplateFragment'); |
||
1012 | return $html; |
||
1013 | } elseif (file_exists($defaultPath1)) { |
||
1014 | self::$logger->debug('Loading template ['.$defaultPath1.']'); |
||
1015 | ob_start(); |
||
1016 | require $defaultPath1; |
||
1017 | $html = ob_get_clean(); |
||
1018 | |||
1019 | self::$logger->debug('<<loadTemplateFragment'); |
||
1020 | return $html; |
||
1021 | } elseif (file_exists($defaultPath2)) { |
||
1022 | self::$logger->debug('Loading template ['.$defaultPath2.']'); |
||
1023 | ob_start(); |
||
1024 | require $defaultPath2; |
||
1025 | $html = ob_get_clean(); |
||
1026 | |||
1027 | self::$logger->debug('<<loadTemplateFragment'); |
||
1028 | return $html; |
||
1029 | } else { |
||
1030 | self::$logger->debug('<<loadTemplateFragment'); |
||
1031 | throw new IllegalArguementException('Template fragment not found in ['.$customPath.'] or ['.$defaultPath1.'] or ['.$defaultPath2.']!'); |
||
1032 | } |
||
1033 | } |
||
1034 | |||
1035 | /** |
||
1036 | * Enables you to set an explicit type of RendererProviderInterface implementation to use for rendering the records |
||
1037 | * attached to this view. |
||
1038 | * |
||
1039 | * @param string $ProviderClassName The name of the RendererProviderInterface implementation to use in this view object |
||
1040 | * @param string $acceptHeader Optional pass the HTTP Accept header to select the correct renderer provider. |
||
1041 | * |
||
1042 | * @since 1.2 |
||
1043 | * |
||
1044 | * @throws \Alpha\Exception\IllegalArguementException |
||
1045 | */ |
||
1046 | public static function setProvider($ProviderClassName, $acceptHeader = null) |
||
1047 | { |
||
1048 | if ($ProviderClassName == 'auto') { |
||
1049 | $ProviderClassName = 'Alpha\View\Renderer\Html\RendererProviderHTML'; |
||
1050 | |||
1051 | if ($acceptHeader == 'application/json') { |
||
1052 | $ProviderClassName = 'Alpha\View\Renderer\Json\RendererProviderJSON'; |
||
1053 | } |
||
1054 | |||
1055 | self::$provider = ServiceFactory::getInstance($ProviderClassName, 'Alpha\View\Renderer\RendererProviderInterface'); |
||
1056 | } else { |
||
1057 | if (class_exists($ProviderClassName)) { |
||
1058 | $provider = new $ProviderClassName(); |
||
1059 | |||
1060 | if ($provider instanceof RendererProviderInterface) { |
||
1061 | self::$provider = ServiceFactory::getInstance($ProviderClassName, 'Alpha\View\Renderer\RendererProviderInterface'); |
||
1062 | } else { |
||
1063 | throw new IllegalArguementException('The provider class ['.$ProviderClassName.'] does not implement the RendererProviderInterface interface!'); |
||
1064 | } |
||
1065 | } else { |
||
1066 | throw new IllegalArguementException('The provider class ['.$ProviderClassName.'] does not exist!'); |
||
1067 | } |
||
1068 | } |
||
1069 | } |
||
1070 | |||
1071 | /** |
||
1072 | * Get the current view renderer provider. |
||
1073 | * |
||
1074 | * @return \Alpha\View\Renderer\RendererProviderInterface |
||
1075 | * |
||
1076 | * @since 2.0 |
||
1077 | */ |
||
1078 | public static function getProvider() |
||
1079 | { |
||
1080 | if (self::$provider instanceof RendererProviderInterface) { |
||
1081 | return self::$provider; |
||
1082 | } else { |
||
1083 | $config = ConfigProvider::getInstance(); |
||
1084 | |||
1085 | self::$provider = ServiceFactory::getInstance($config->get('app.renderer.provider.name'), 'Alpha\View\Renderer\RendererProviderInterface'); |
||
1086 | |||
1087 | return self::$provider; |
||
0 ignored issues
–
show
The return type of
return self::$provider; (stdClass ) is incompatible with the return type documented by Alpha\View\View::getProvider of type Alpha\View\Renderer\RendererProviderInterface .
If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design. Let’s take a look at an example: class Author {
private $name;
public function __construct($name) {
$this->name = $name;
}
public function getName() {
return $this->name;
}
}
abstract class Post {
public function getAuthor() {
return 'Johannes';
}
}
class BlogPost extends Post {
public function getAuthor() {
return new Author('Johannes');
}
}
class ForumPost extends Post { /* ... */ }
function my_function(Post $post) {
echo strtoupper($post->getAuthor());
}
Our function ![]() |
|||
1088 | } |
||
1089 | } |
||
1090 | } |
||
1091 |
Let’s take a look at an example:
In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.
Available Fixes
Change the type-hint for the parameter:
Add an additional type-check:
Add the method to the parent class: