View::setTemplate()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
dl 0
loc 11
ccs 0
cts 10
cp 0
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 7
nc 2
nop 2
crap 6
1
<?php
2
3
/**
4
 *
5
 * This file is part of the Apix Project.
6
 *
7
 * (c) Franck Cassedanne <franck at ouarz.net>
8
 *
9
 * @license     http://opensource.org/licenses/BSD-3-Clause  New BSD License
10
 *
11
 */
12
13
namespace Apix\View;
14
15
class View
16
{
17
18
    /**
19
     * Holds a ViewModel object.
20
     * @var	ViewModel
21
     */
22
    protected $view_model;
23
24
    /**
25
     * Holds a Template object.
26
     * @var	Template
27
     */
28
    protected $template;
29
30
    /**
31
     * View constructor, sets the ViewModel.
32
     *
33
     * @see http://en.wikipedia.org/wiki/Model_View_ViewModel
34
     * @param ViewModel $view_model Optional. The view model to set.
35
     * @param array     $model_data Optional. An array of data to model.
36
     */
37
    public function __construct(ViewModel $view_model = null, array $model_data = null)
38
    {
39
        if (null !== $view_model) {
40
            $this->setViewModel($view_model);
41
        }
42
43
        if (null !== $model_data) {
44
            $this->view_model->set($model_data);
45
        }
46
    }
47
48
    /**
49
     * Sets the ViewModel object.
50
     *
51
     * @param  ViewModel $view_model The view model to set.
52
     * @return ViewModel Provides method chaining.
53
     */
54
    public function setViewModel(ViewModel $view_model)
55
    {
56
        return $this->view_model = $view_model;
57
    }
58
59
    /**
60
     * Returns the current ViewModel object.
61
     *
62
     * @return ViewModel
63
     */
64
    public function getViewModel()
65
    {
66
        return $this->view_model;
67
    }
68
69
    /**
70
     * Sets the Template instance.
71
     *
72
     * If a string is passed as $template
73
     * then it will be used a the path to the template and a Template
74
     * instance will be created using [Template::$default_class].
75
     *
76
     * @param Template|string|null $template A string or an instance of Template.
77
     */
78
    public function setTemplate($template, array $options = null)
79
    {
80
        if (!$template instanceof Template) {
81
            $t = new Template();
82
            $t->setEngine($template);
83
            $class = $t->getEngine();
84
            $template = new $class($options);
85
        }
86
87
        $this->template = $template;
88
    }
89
90
    /**
91
     * Renders the given layout or retrieved from the view model if null.
92
     *
93
     * @param  string|null Template layout to render.
94
     * @return string
95
     */
96
    public function render($layout = null)
97
    {
98
        $layout = is_string($layout)
99
                    ? $layout
100
                    : $this->view_model->getLayout();
101
102
        $this->template->setLayout( $layout );
103
104
        return $this->template->render( $this->view_model );
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Apix\View\Template as the method render() does only exist in the following sub-classes of Apix\View\Template: Apix\View\Template\Mustache. 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...
105
    }
106
107
    /**
108
     * Returns a string representaion of the view.
109
     * That magic method does not play nicely with exception so best avoided!
110
     *
111
     * @todo  depreciate this!!!
112
     * @return string
113
     */
114
    public function __toString()
115
    {
116
        return $this->render();
117
    }
118
119
}
120