Completed
Push — develop ( 4f2388...3f4b0b )
by John
02:50
created

View::setBO()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 12
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 12
rs 9.4285
cc 2
eloc 7
nc 2
nop 1
1
<?php
2
3
namespace Alpha\View;
4
5
use Alpha\Util\Logging\Logger;
6
use Alpha\Util\Config\ConfigProvider;
7
use Alpha\Model\ActiveRecord;
8
use Alpha\Model\Type\DEnum;
9
use Alpha\Exception\IllegalArguementException;
10
use Alpha\View\Renderer\RendererProviderFactory;
11
use Alpha\View\Renderer\RendererProviderInterface;
12
use ReflectionClass;
13
14
/**
15
 * The master rendering view class for the Alpha Framework.
16
 *
17
 * @since 1.0
18
 *
19
 * @author John Collins <[email protected]>
20
 * @license http://www.opensource.org/licenses/bsd-license.php The BSD License
21
 * @copyright Copyright (c) 2017, John Collins (founder of Alpha Framework).
22
 * All rights reserved.
23
 *
24
 * <pre>
25
 * Redistribution and use in source and binary forms, with or
26
 * without modification, are permitted provided that the
27
 * following conditions are met:
28
 *
29
 * * Redistributions of source code must retain the above
30
 *   copyright notice, this list of conditions and the
31
 *   following disclaimer.
32
 * * Redistributions in binary form must reproduce the above
33
 *   copyright notice, this list of conditions and the
34
 *   following disclaimer in the documentation and/or other
35
 *   materials provided with the distribution.
36
 * * Neither the name of the Alpha Framework nor the names
37
 *   of its contributors may be used to endorse or promote
38
 *   products derived from this software without specific
39
 *   prior written permission.
40
 *
41
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
42
 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
43
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
44
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
45
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
46
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
47
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
48
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
49
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
50
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
51
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
52
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
53
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
54
 * </pre>
55
 */
56
class View
57
{
58
    /**
59
     * The business object that will be rendered.
60
     *
61
     * @var \Alpha\Model\ActiveRecord
62
     *
63
     * @since 1.0
64
     */
65
    protected $Record;
66
67
    /**
68
     * The rendering provider that will be used to render the active record.
69
     *
70
     * @var \Alpha\View\Renderer\RendererProviderInterface
71
     *
72
     * @since 1.2
73
     */
74
    private static $provider;
75
76
    /**
77
     * Trace logger.
78
     *
79
     * @var Logger
80
     *
81
     * @since 1.0
82
     */
83
    private static $logger = null;
84
85
    /**
86
     * Constructor for the View.  As this is protected, use the View::getInstance method from a public scope.
87
     *
88
     * @param ActiveRecord $Record           The main business object that this view is going to render
89
     * @param string       $acceptHeader Optionally pass the HTTP Accept header to select the correct renderer provider.
90
     *
91
     * @throws \Alpha\Exception\IllegalArguementException
92
     *
93
     * @since 1.0
94
     */
95
    protected function __construct($Record, $acceptHeader = null)
96
    {
97
        self::$logger = new Logger('View');
98
        self::$logger->debug('>>__construct(Record=['.var_export($Record, true).'], acceptHeader=['.$acceptHeader.'])');
99
100
        $config = ConfigProvider::getInstance();
101
102
        if ($Record instanceof ActiveRecord) {
103
            $this->record = $Record;
0 ignored issues
show
Bug introduced by
The property record does not seem to exist. Did you mean Record?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
104
        } else {
105
            throw new IllegalArguementException('The record type provided ['.get_class($Record).'] is not defined anywhere!');
106
        }
107
108
        self::setProvider($config->get('app.renderer.provider.name'), $acceptHeader);
109
        self::$provider->setRecord($this->record);
0 ignored issues
show
Bug introduced by
The property record does not seem to exist. Did you mean Record?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
110
111
        self::$logger->debug('<<__construct');
112
    }
113
114
    /**
115
     * Static method which returns a View object or a custom child view for the Record specified
116
     * if one exists.
117
     *
118
     * @param ActiveRecord $Record           The main business object that this view is going to render
119
     * @param bool         $returnParent Flag to enforce the return of this object instead of a child (defaults to false)
120
     * @param string       $acceptHeader Optionally pass the HTTP Accept header to select the correct renderer provider.
121
     *
122
     * @return View Returns a View object, or a child view object if one exists for this record
123
     *
124
     * @since 1.0
125
     */
126
    public static function getInstance($Record, $returnParent = false, $acceptHeader = null)
127
    {
128
        if (self::$logger == null) {
129
            self::$logger = new Logger('View');
130
        }
131
        self::$logger->debug('>>getInstance(Record=['.var_export($Record, true).'], returnParent=['.$returnParent.'], acceptHeader=['.$acceptHeader.'])');
132
133
        $class = new ReflectionClass($Record);
134
        $childView = $class->getShortname();
135
        $childView = $childView.'View';
136
137
        // Check to see if a custom view exists for this record, and if it does return that view instead
138
        if (!$returnParent) {
139
            $className = '\Alpha\View\\'.$childView;
140
141
            if (class_exists($className)) {
142
                self::$logger->debug('<<getInstance [new '.$className.'('.get_class($Record).')]');
143
144
                $instance = new $className($Record, $acceptHeader);
145
146
                return $instance;
147
            }
148
149
            $className = '\View\\'.$childView;
150
151
            if (class_exists('\View\\'.$childView)) {
152
                self::$logger->debug('<<getInstance [new '.$className.'('.get_class($Record).')]');
153
154
                $instance = new $className($Record, $acceptHeader);
155
156
                return $instance;
157
            }
158
159
            self::$logger->debug('<<getInstance [new View('.get_class($Record).', '.$acceptHeader.')]');
160
161
            return new self($Record, $acceptHeader);
162
        } else {
163
            self::$logger->debug('<<getInstance [new View('.get_class($Record).', '.$acceptHeader.')]');
164
165
            return new self($Record, $acceptHeader);
166
        }
167
    }
168
169
    /**
170
     * Simple setter for the view business object.
171
     *
172
     * @param \Alpha\Model\ActiveRecord $Record
173
     *
174
     * @throws \Alpha\Exception\IllegalArguementException
175
     *
176
     * @since 1.0
177
     */
178
    public function setRecord($Record)
179
    {
180
        self::$logger->debug('>>setRecord(Record=['.var_export($Record, true).'])');
181
182
        if ($Record instanceof \Alpha\Model\ActiveRecord) {
183
            $this->record = $Record;
0 ignored issues
show
Bug introduced by
The property record does not seem to exist. Did you mean Record?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
184
        } else {
185
            throw new IllegalArguementException('The Record provided ['.get_class($Record).'] is not defined anywhere!');
186
        }
187
188
        self::$logger->debug('<<setRecord');
189
    }
190
191
    /**
192
     * Gets the Record attached to this view (if any).
193
     *
194
     * @return \Alpha\Model\ActiveRecord
195
     *
196
     * @since 1.0
197
     */
198
    public function getRecord()
199
    {
200
        return $this->record;
0 ignored issues
show
Bug introduced by
The property record does not seem to exist. Did you mean Record?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
201
    }
202
203
    /**
204
     * Renders the default create view.
205
     *
206
     * @param array $fields Hash array of fields to pass to the template
207
     *
208
     * @return string
209
     *
210
     * @since 1.0
211
     */
212
    public function createView($fields = array())
213
    {
214
        self::$logger->debug('>>createView(fields=['.var_export($fields, true).'])');
215
216
        if (method_exists($this, 'before_createView_callback')) {
217
            $this->{'before_createView_callback'}();
218
        }
219
220
        $body = self::$provider->createView($fields);
221
222
        if (method_exists($this, 'after_createView_callback')) {
223
            $this->{'after_createView_callback'}();
224
        }
225
226
        self::$logger->debug('<<createView');
227
228
        return $body;
229
    }
230
231
    /**
232
     * Renders a form to enable object editing.
233
     *
234
     * @param array $fields Hash array of fields to pass to the template
235
     *
236
     * @return string
237
     *
238
     * @since 1.0
239
     */
240
    public function editView($fields = array())
241
    {
242
        self::$logger->debug('>>editView(fields=['.var_export($fields, true).'])');
243
244
        if (method_exists($this, 'before_editView_callback')) {
245
            $this->{'before_editView_callback'}();
246
        }
247
248
        $body = self::$provider->editView($fields);
249
250
        if (method_exists($this, 'after_editView_callback')) {
251
            $this->{'after_editView_callback'}();
252
        }
253
254
        self::$logger->debug('<<editView');
255
256
        return $body;
257
    }
258
259
    /**
260
     * Renders the list view.
261
     *
262
     * @param array $fields Hash array of fields to pass to the template
263
     *
264
     * @return string
265
     *
266
     * @since 1.0
267
     */
268
    public function listView($fields = array())
269
    {
270
        self::$logger->debug('>>listView(fields=['.var_export($fields, true).'])');
271
272
        if (method_exists($this, 'before_listView_callback')) {
273
            $this->{'before_listView_callback'}();
274
        }
275
276
        $body = self::$provider->listView($fields);
277
278
        if (method_exists($this, 'after_listView_callback')) {
279
            $this->{'after_listView_callback'}();
280
        }
281
282
        self::$logger->debug('<<listView');
283
284
        return $body;
285
    }
286
287
    /**
288
     * Renders a detailed view of the object (read-only).
289
     *
290
     * @param array $fields Hash array of fields to pass to the template
291
     *
292
     * @return string
293
     *
294
     * @since 1.0
295
     */
296
    public function detailedView($fields = array())
297
    {
298
        self::$logger->debug('>>detailedView(fields=['.var_export($fields, true).'])');
299
300
        if (method_exists($this, 'before_detailedView_callback')) {
301
            $this->{'before_detailedView_callback'}();
302
        }
303
304
        $body = self::$provider->detailedView($fields);
305
306
        if (method_exists($this, 'after_detailedView_callback')) {
307
            $this->{'after_detailedView_callback'}();
308
        }
309
310
        self::$logger->debug('<<detailedView');
311
312
        return $body;
313
    }
314
315
    /**
316
     * Renders the admin view for the business object screen.
317
     *
318
     * @param array $fields Hash array of fields to pass to the template
319
     *
320
     * @return string
321
     *
322
     * @since 1.0
323
     */
324
    public function adminView($fields = array())
325
    {
326
        self::$logger->debug('>>adminView(fields=['.var_export($fields, true).'])');
327
328
        if (method_exists($this, 'before_adminView_callback')) {
329
            $this->{'before_adminView_callback'}();
330
        }
331
332
        $body = self::$provider->adminView($fields);
333
334
        if (method_exists($this, 'after_adminView_callback')) {
335
            $this->{'after_adminView_callback'}();
336
        }
337
338
        self::$logger->debug('<<adminView');
339
340
        return $body;
341
    }
342
343
    /**
344
     * Method to render the page header content.
345
     *
346
     * @param \Alpha\Controller\Controller $controller
347
     *
348
     * @return string
349
     *
350
     * @throws \Alpha\Exception\IllegalArguementException
351
     *
352
     * @since 1.0
353
     */
354
    public static function displayPageHead($controller)
355
    {
356
        if (self::$logger == null) {
357
            self::$logger = new Logger('View');
358
        }
359
        self::$logger->debug('>>displayPageHead(controller=['.var_export($controller, true).'])');
360
361
        if (method_exists($controller, 'before_displayPageHead_callback')) {
362
            $controller->{'before_displayPageHead_callback'}();
363
        }
364
365
        $config = ConfigProvider::getInstance();
366
367
        if (!self::$provider instanceof RendererProviderInterface) {
368
            self::setProvider($config->get('app.renderer.provider.name'));
369
        }
370
371
        $provider = self::$provider;
372
        $header = $provider::displayPageHead($controller);
373
374
        if (method_exists($controller, 'after_displayPageHead_callback')) {
375
            $header .= $controller->{'after_displayPageHead_callback'}();
376
        }
377
378
        self::$logger->debug('<<displayPageHead ['.$header.']');
379
380
        return $header;
381
    }
382
383
    /**
384
     * Method to render the page footer content.
385
     *
386
     * @param \Alpha\Controller\Controller $controller
387
     *
388
     * @return string
389
     *
390
     * @since 1.0
391
     */
392
    public static function displayPageFoot($controller)
393
    {
394
        if (self::$logger == null) {
395
            self::$logger = new Logger('View');
396
        }
397
398
        self::$logger->debug('>>displayPageFoot(controller=['.get_class($controller).'])');
399
400
        $config = ConfigProvider::getInstance();
401
402
        $footer = '';
403
404
        if (method_exists($controller, 'before_displayPageFoot_callback')) {
405
            $footer .= $controller->before_displayPageFoot_callback();
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Alpha\Controller\Controller as the method before_displayPageFoot_callback() does only exist in the following sub-classes of Alpha\Controller\Controller: Alpha\Controller\ActiveRecordController, Alpha\Controller\ArticleController, Alpha\Controller\DEnumController, Alpha\Controller\LoginController, Alpha\Controller\SearchController, 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

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
406
        }
407
408
        if (!self::$provider instanceof RendererProviderInterface) {
409
            self::setProvider($config->get('app.renderer.provider.name'));
410
        }
411
412
        $provider = self::$provider;
413
        $footer .= $provider::displayPageFoot($controller);
414
415
        if (method_exists($controller, 'after_displayPageFoot_callback')) {
416
            $footer .= $controller->after_displayPageFoot_callback();
0 ignored issues
show
Bug introduced by
The method after_displayPageFoot_callback() does not seem to exist on object<Alpha\Controller\Controller>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
417
        }
418
419
        self::$logger->debug('<<displayPageFoot ['.$footer.']');
420
421
        return $footer;
422
    }
423
424
    /**
425
     * Renders the content for an update (e.g. successful save) message.
426
     *
427
     * @param string $message
428
     *
429
     * @return string
430
     *
431
     * @since 1.0
432
     */
433
    public static function displayUpdateMessage($message)
434
    {
435
        if (self::$logger == null) {
436
            self::$logger = new Logger('View');
437
        }
438
        self::$logger->debug('>>displayUpdateMessage(message=['.$message.'])');
439
440
        $config = ConfigProvider::getInstance();
441
442
        if (!self::$provider instanceof RendererProviderInterface) {
443
            self::setProvider($config->get('app.renderer.provider.name'));
444
        }
445
446
        $provider = self::$provider;
447
        $message = $provider::displayUpdateMessage($message);
448
449
        self::$logger->debug('<<displayUpdateMessage ['.$message.']');
450
451
        return $message;
452
    }
453
454
    /**
455
     * Renders the content for an error (e.g. save failed) message.
456
     *
457
     * @param string $message
458
     *
459
     * @return string
460
     *
461
     * @since 1.0
462
     */
463
    public static function displayErrorMessage($message)
464
    {
465
        if (self::$logger == null) {
466
            self::$logger = new Logger('View');
467
        }
468
        self::$logger->debug('>>displayErrorMessage(message=['.$message.'])');
469
470
        $config = ConfigProvider::getInstance();
471
472
        if (!self::$provider instanceof RendererProviderInterface) {
473
            self::setProvider($config->get('app.renderer.provider.name'));
474
        }
475
476
        $provider = self::$provider;
477
        $message = $provider::displayErrorMessage($message);
478
479
        self::$logger->debug('<<displayErrorMessage ['.$message.']');
480
481
        return $message;
482
    }
483
484
    /**
485
     * Renders an error page with the supplied error code (typlically a HTTP code) and a message.
486
     *
487
     * @param string $code
488
     * @param string $message
489
     *
490
     * @return string
491
     *
492
     * @since 1.0
493
     */
494
    public static function renderErrorPage($code, $message)
495
    {
496
        if (self::$logger == null) {
497
            self::$logger = new Logger('View');
498
        }
499
        self::$logger->debug('>>renderErrorPage(code=['.$code.'],message=['.$message.'])');
500
501
        $config = ConfigProvider::getInstance();
502
503
        if (!self::$provider instanceof RendererProviderInterface) {
504
            self::setProvider($config->get('app.renderer.provider.name'));
505
        }
506
507
        $provider = self::$provider;
508
        $message = $provider::renderErrorPage($code, $message);
509
510
        self::$logger->debug('<<renderErrorPage ['.$message.']');
511
512
        return $message;
513
    }
514
515
    /**
516
     * Method to render a hidden HTML form for posting the OID of an object to be deleted.
517
     *
518
     * @param string $URI The URI that the form will point to
519
     *
520
     * @return string
521
     *
522
     * @since 1.0
523
     */
524
    public static function renderDeleteForm($URI)
525
    {
526
        if (self::$logger == null) {
527
            self::$logger = new Logger('View');
528
        }
529
        self::$logger->debug('>>renderDeleteForm()');
530
531
        $config = ConfigProvider::getInstance();
532
533
        if (!self::$provider instanceof RendererProviderInterface) {
534
            self::setProvider($config->get('app.renderer.provider.name'));
535
        }
536
537
        $provider = self::$provider;
538
        $html = $provider::renderDeleteForm($URI);
539
540
        self::$logger->debug('<<renderDeleteForm ['.$html.']');
541
542
        return $html;
543
    }
544
545
    /**
546
     * Method to render a HTML form with two hidden, hashed (MD5) form fields to be used as
547
     * a check to ensure that a post to the controller is being sent from the same server
548
     * as hosting it.
549
     *
550
     * @return string
551
     *
552
     * @since 1.0
553
     */
554
    public static function renderSecurityFields()
555
    {
556
        if (self::$logger == null) {
557
            self::$logger = new Logger('View');
558
        }
559
        self::$logger->debug('>>renderSecurityFields()');
560
561
        $config = ConfigProvider::getInstance();
562
563
        if (!self::$provider instanceof RendererProviderInterface) {
564
            self::setProvider($config->get('app.renderer.provider.name'));
565
        }
566
567
        $provider = self::$provider;
568
        $html = $provider::renderSecurityFields();
569
570
        self::$logger->debug('<<renderSecurityFields ['.$html.']');
571
572
        return $html;
573
    }
574
575
    /**
576
     * Method to render the default Integer HTML.
577
     *
578
     * @param string $name      The field name
579
     * @param string $label     The label to apply to the field
580
     * @param string $mode      The field mode (create/edit/view)
581
     * @param string $value     The field value (optional)
582
     *
583
     * @return string
584
     *
585
     * @since 1.0
586
     */
587
    public function renderIntegerField($name, $label, $mode, $value = '')
588
    {
589
        self::$logger->debug('>>renderIntegerField(name=['.$name.'], label=['.$label.'], mode=['.$mode.'], value=['.$value.']');
590
591
        $html = self::$provider->renderIntegerField($name, $label, $mode, $value);
592
593
        self::$logger->debug('<<renderIntegerField ['.$html.']');
594
595
        return $html;
596
    }
597
598
    /**
599
     * Method to render the default Double HTML.
600
     *
601
     * @param string $name      The field name
602
     * @param string $label     The label to apply to the field
603
     * @param string $mode      The field mode (create/edit/view)
604
     * @param string $value     The field value (optional)
605
     *
606
     * @return string
607
     *
608
     * @since 1.0
609
     */
610
    public function renderDoubleField($name, $label, $mode, $value = '')
611
    {
612
        self::$logger->debug('>>renderDoubleField(name=['.$name.'], label=['.$label.'], mode=['.$mode.'], value=['.$value.'])');
613
614
        $html = self::$provider->renderDoubleField($name, $label, $mode, $value);
615
616
        self::$logger->debug('<<renderDoubleField ['.$html.']');
617
618
        return $html;
619
    }
620
621
    /**
622
     * Method to render the default Boolean HTML.
623
     *
624
     * @param string $name      The field name
625
     * @param string $label     The label to apply to the field
626
     * @param string $mode      The field mode (create/edit/view)
627
     * @param string $value     The field value (optional)
628
     *
629
     * @return string
630
     *
631
     * @since 1.0
632
     */
633
    public function renderBooleanField($name, $label, $mode, $value = '')
634
    {
635
        self::$logger->debug('>>renderBooleanField(name=['.$name.'], label=['.$label.'], mode=['.$mode.'], value=['.$value.'])');
636
637
        $html = self::$provider->renderBooleanField($name, $label, $mode, $value);
638
639
        self::$logger->debug('<<renderBooleanField ['.$html.']');
640
641
        return $html;
642
    }
643
644
    /**
645
     * Method to render the default Enum HTML.
646
     *
647
     * @param string $name      The field name
648
     * @param string $label     The label to apply to the field
649
     * @param string $mode      The field mode (create/edit/view)
650
     * @param array  $options   The Enum options
651
     * @param string $value     The field value (optional)
652
     *
653
     * @return string
654
     *
655
     * @since 1.0
656
     */
657
    public function renderEnumField($name, $label, $mode, $options, $value = '')
658
    {
659
        self::$logger->debug('>>renderEnumField(name=['.$name.'], label=['.$label.'], mode=['.$mode.'], value=['.$value.'])');
660
661
        $html = self::$provider->renderEnumField($name, $label, $mode, $options, $value);
662
663
        self::$logger->debug('<<renderEnumField ['.$html.']');
664
665
        return $html;
666
    }
667
668
    /**
669
     * Method to render the default DEnum HTML.
670
     *
671
     * @param string $name      The field name
672
     * @param string $label     The label to apply to the field
673
     * @param string $mode      The field mode (create/edit/view)
674
     * @param array  $options   The DEnum options
675
     * @param string $value     The field value (optional)
676
     *
677
     * @return string
678
     *
679
     * @since 1.0
680
     */
681
    public function renderDEnumField($name, $label, $mode, $options, $value = '')
682
    {
683
        self::$logger->debug('>>renderDEnumField(name=['.$name.'], label=['.$label.'], mode=['.$mode.'], value=['.$value.'])');
684
685
        $html = self::$provider->renderDEnumField($name, $label, $mode, $options, $value);
686
687
        self::$logger->debug('<<renderDEnumField ['.$html.']');
688
689
        return $html;
690
    }
691
692
    /**
693
     * Method to render the default field HTML when type is not known.
694
     *
695
     * @param string $name      The field name
696
     * @param string $label     The label to apply to the field
697
     * @param string $mode      The field mode (create/edit/view)
698
     * @param string $value     The field value (optional)
699
     *
700
     * @return string
701
     *
702
     * @since 1.0
703
     */
704
    public function renderDefaultField($name, $label, $mode, $value = '')
705
    {
706
        self::$logger->debug('>>renderDefaultField(name=['.$name.'], label=['.$label.'], mode=['.$mode.'], value=['.$value.'])');
707
708
        $html = self::$provider->renderDefaultField($name, $label, $mode, $value);
709
710
        self::$logger->debug('<<renderDefaultField ['.$html.']');
711
712
        return $html;
713
    }
714
715
    /**
716
     * render the default Text HTML.
717
     *
718
     * @param string $name      The field name
719
     * @param string $label     The label to apply to the field
720
     * @param string $mode      The field mode (create/edit/view)
721
     * @param string $value     The field value (optional)
722
     *
723
     * @return string
724
     *
725
     * @since 1.0
726
     */
727
    public function renderTextField($name, $label, $mode, $value = '')
728
    {
729
        self::$logger->debug('>>renderTextField(name=['.$name.'], label=['.$label.'], mode=['.$mode.'], value=['.$value.'])');
730
731
        $html = self::$provider->renderTextField($name, $label, $mode, $value);
732
733
        self::$logger->debug('<<renderTextField ['.$html.']');
734
735
        return $html;
736
    }
737
738
    /**
739
     * render the default Relation HTML.
740
     *
741
     * @param string $name      The field name
742
     * @param string $label     The label to apply to the field
743
     * @param string $mode      The field mode (create/edit/view)
744
     * @param string $value     The field value (optional)
745
     * @param bool   $expanded  Render the related fields in expanded format or not (optional)
746
     * @param bool   $buttons   Render buttons for expanding/contacting the related fields (optional)
747
     *
748
     * @return string
749
     *
750
     * @since 1.0
751
     */
752
    public function renderRelationField($name, $label, $mode, $value = '', $expanded = false, $buttons = true)
753
    {
754
        self::$logger->debug('>>renderRelationField(name=['.$name.'], label=['.$label.'], mode=['.$mode.'], value=['.$value.'], expanded=['.$expanded.'], buttons=['.$buttons.'])');
755
756
        $html = self::$provider->renderRelationField($name, $label, $mode, $value, $expanded, $buttons);
757
758
        self::$logger->debug('<<renderRelationField ['.$html.']');
759
760
        return $html;
761
    }
762
763
    /**
764
     * Renders all fields for the current Record in edit/create/view mode.
765
     *
766
     * @param string $mode           (view|edit|create)
767
     * @param array  $filterFields   Optional list of field names to exclude from rendering
768
     * @param array  $readOnlyFields Optional list of fields to render in a readonly fashion when rendering in create or edit mode
769
     *
770
     * @return string
771
     *
772
     * @since 1.0
773
     */
774
    public function renderAllFields($mode, $filterFields = array(), $readOnlyFields = array())
775
    {
776
        self::$logger->debug('>>renderAllFields(mode=['.$mode.'], filterFields=['.var_export($filterFields, true).'], readOnlyFields=['.var_export($readOnlyFields, true).'])');
777
778
        $html = self::$provider->renderAllFields($mode, $filterFields, $readOnlyFields);
779
780
        self::$logger->debug('<<renderAllFields ['.$html.']');
781
782
        return $html;
783
    }
784
785
    /**
786
     * Loads a template for the Record specified if one exists.  Lower level custom templates
787
     * take precedence.
788
     *
789
     * @param \Alpha\Model\ActiveRecord $Record
790
     * @param string                   $mode
791
     * @param array                    $fields
792
     *
793
     * @return string
794
     *
795
     * @since 1.0
796
     *
797
     * @throws \Alpha\Exception\IllegalArguementException
798
     */
799
    public static function loadTemplate($Record, $mode, $fields = array())
800
    {
801
        self::$logger->debug('>>loadTemplate(Record=['.var_export($Record, true).'], mode=['.$mode.'], fields=['.var_export($fields, true).'])');
802
803
        $config = ConfigProvider::getInstance();
804
805
        // for each Record property, create a local variable holding its value
806
        $reflection = new ReflectionClass(get_class($Record));
807
        $properties = $reflection->getProperties();
808
809
        foreach ($properties as $propObj) {
810
            $propName = $propObj->name;
811
812
            if ($propName != 'logger' && !$propObj->isPrivate()) {
813
                $prop = $Record->getPropObject($propName);
814
                if ($prop instanceof DEnum) {
815
                    ${$propName} = $Record->getPropObject($propName)->getDisplayValue();
0 ignored issues
show
Bug introduced by
The method getDisplayValue() does not seem to exist on object<Alpha\Model\Type\Type>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
816
                } else {
817
                    ${$propName} = $Record->get($propName);
818
                }
819
            }
820
        }
821
822
        // loop over the $fields array and create a local variable for each key value
823
        foreach (array_keys($fields) as $fieldName) {
824
            ${$fieldName} = $fields[$fieldName];
825
        }
826
827
        $filename = $mode.'.phtml';
828
        $class = new ReflectionClass($Record);
829
        $className = $class->getShortname();
830
831
        $customPath = $config->get('app.root').'src/View/Html/Templates/'.$className.'/'.$filename;
832
        $defaultPath1 = $config->get('app.root').'vendor/alphadevx/alpha/Alpha/View/Renderer/Html/Templates/'.$className.'/'.$filename;
833
        $defaultPath2 = $config->get('app.root').'vendor/alphadevx/alpha/Alpha/View/Renderer/Html/Templates/'.$filename;
834
        $defaultPath3 = $config->get('app.root').'Alpha/View/Renderer/Html/Templates/'.$className.'/'.$filename;
835
        $defaultPath4 = $config->get('app.root').'Alpha/View/Renderer/Html/Templates/'.$filename;
836
837
        // Check to see if a custom template exists for this record, and if it does load that
838
        if (file_exists($customPath)) {
839
            self::$logger->debug('Loading template ['.$customPath.']');
840
            ob_start();
841
            require $customPath;
842
            $html = ob_get_clean();
843
844
            self::$logger->debug('<<loadTemplate');
845
            return $html;
846
        } elseif (file_exists($defaultPath1)) {
847
            self::$logger->debug('Loading template ['.$defaultPath1.']');
848
            ob_start();
849
            require $defaultPath1;
850
            $html = ob_get_clean();
851
852
            self::$logger->debug('<<loadTemplate');
853
            return $html;
854
        } elseif (file_exists($defaultPath2)) {
855
            self::$logger->debug('Loading template ['.$defaultPath2.']');
856
            ob_start();
857
            require $defaultPath2;
858
            $html = ob_get_clean();
859
860
            self::$logger->debug('<<loadTemplate');
861
            return $html;
862
        } elseif (file_exists($defaultPath3)) {
863
            self::$logger->debug('Loading template ['.$defaultPath3.']');
864
            ob_start();
865
            require $defaultPath3;
866
            $html = ob_get_clean();
867
868
            self::$logger->debug('<<loadTemplate');
869
            return $html;
870
        } elseif (file_exists($defaultPath4)) {
871
            self::$logger->debug('Loading template ['.$defaultPath4.']');
872
            ob_start();
873
            require $defaultPath4;
874
            $html = ob_get_clean();
875
876
            self::$logger->debug('<<loadTemplate');
877
            return $html;
878
        } else {
879
            self::$logger->debug('<<loadTemplate');
880
            throw new IllegalArguementException('No ['.$mode.'] HTML template found for class ['.$className.']');
881
        }
882
    }
883
884
    /**
885
     * Loads a template fragment from the Renderer/[type]/Fragments/[filename.ext] location.
886
     *
887
     * @param string $type     Currently only html supported, later json and xml.
888
     * @param string $fileName The name of the fragment file
889
     * @param array  $fields   A hash array of field values to pass to the template fragment.
890
     *
891
     * @return string
892
     *
893
     * @since 1.2
894
     *
895
     * @throws \Alpha\Exception\IllegalArguementException
896
     */
897
    public static function loadTemplateFragment($type, $fileName, $fields = array())
898
    {
899
        if (self::$logger == null) {
900
            self::$logger = new Logger('View');
901
        }
902
        self::$logger->debug('>>loadTemplateFragment(type=['.$type.'], fileName=['.$fileName.'], fields=['.var_export($fields, true).'])');
903
904
        $config = ConfigProvider::getInstance();
905
906
        // loop over the $fields array and create a local variable for each key value
907
        foreach (array_keys($fields) as $fieldName) {
908
            ${$fieldName} = $fields[$fieldName];
909
        }
910
911
        $customPath = $config->get('app.root').'src/View/'.ucfirst($type).'/Fragments/'.$fileName;
912
        $defaultPath1 = $config->get('app.root').'vendor/alphadevx/alpha/Alpha/View/Renderer/'.ucfirst($type).'/Fragments/'.$fileName;
913
        $defaultPath2 = $config->get('app.root').'Alpha/View/Renderer/'.ucfirst($type).'/Fragments/'.$fileName;
914
915
        // Check to see if a custom template exists for this record, and if it does load that
916
        if (file_exists($customPath)) {
917
            self::$logger->debug('Loading template ['.$customPath.']');
918
            ob_start();
919
            require $customPath;
920
            $html = ob_get_clean();
921
922
            return $html;
923
        } elseif (file_exists($defaultPath1)) {
924
            self::$logger->debug('Loading template ['.$defaultPath1.']');
925
            ob_start();
926
            require $defaultPath1;
927
            $html = ob_get_clean();
928
929
            return $html;
930
        } elseif (file_exists($defaultPath2)) {
931
            self::$logger->debug('Loading template ['.$defaultPath2.']');
932
            ob_start();
933
            require $defaultPath2;
934
            $html = ob_get_clean();
935
936
            return $html;
937
        } else {
938
            throw new IllegalArguementException('Template fragment not found in ['.$customPath.'] or ['.$defaultPath1.'] or ['.$defaultPath2.']!');
939
        }
940
941
        self::$logger->debug('<<loadTemplateFragment');
0 ignored issues
show
Unused Code introduced by
self::$logger->debug('<<loadTemplateFragment'); does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
942
    }
943
944
    /**
945
     * Enables you to set an explicit type of RendererProviderInterface implementation to use for rendering the records
946
     * attached to this view.
947
     *
948
     * @param string $ProviderClassName The name of the RendererProviderInterface implementation to use in this view object
949
     * @param string $acceptHeader      Optional pass the HTTP Accept header to select the correct renderer provider.
950
     *
951
     * @since 1.2
952
     *
953
     * @throws \Alpha\Exception\IllegalArguementException
954
     */
955
    public static function setProvider($ProviderClassName, $acceptHeader = null)
956
    {
957
        if ($ProviderClassName == 'auto') {
958
            $ProviderClassName = 'Alpha\View\Renderer\Html\RendererProviderHTML';
959
960
            if ($acceptHeader == 'application/json') {
961
                $ProviderClassName = 'Alpha\View\Renderer\Json\RendererProviderJSON';
962
            }
963
964
            self::$provider = RendererProviderFactory::getInstance($ProviderClassName);
965
        } else {
966
            if (class_exists($ProviderClassName)) {
967
                $provider = new $ProviderClassName();
968
969
                if ($provider instanceof RendererProviderInterface) {
970
                    self::$provider = RendererProviderFactory::getInstance($ProviderClassName);
971
                } else {
972
                    throw new IllegalArguementException('The provider class ['.$ProviderClassName.'] does not implement the RendererProviderInterface interface!');
973
                }
974
            } else {
975
                throw new IllegalArguementException('The provider class ['.$ProviderClassName.'] does not exist!');
976
            }
977
        }
978
    }
979
980
    /**
981
     * Get the current view renderer provider.
982
     *
983
     * @return \Alpha\View\Renderer\RendererProviderInterface
984
     *
985
     * @since 2.0
986
     */
987
    public static function getProvider()
988
    {
989
        if (self::$provider instanceof RendererProviderInterface) {
990
            return self::$provider;
991
        } else {
992
            $config = ConfigProvider::getInstance();
993
994
            self::$provider = RendererProviderFactory::getInstance($config->get('app.renderer.provider.name'));
995
996
            return self::$provider;
997
        }
998
    }
999
}
1000