Test Failed
Push — master ( 147d4d...670e11 )
by Alain
03:28
created

AbstractView::__call()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 0
Metric Value
dl 0
loc 13
ccs 0
cts 0
cp 0
rs 9.8333
c 0
b 0
f 0
cc 3
nc 2
nop 2
crap 12
1
<?php declare(strict_types=1);
2
/**
3
 * Bright Nucleus View Component.
4
 *
5
 * @package   BrightNucleus\View
6
 * @author    Alain Schlesser <[email protected]>
7
 * @license   MIT
8
 * @link      http://www.brightnucleus.com/
9
 * @copyright 2016-2017 Alain Schlesser, Bright Nucleus
10
 */
11
12
namespace BrightNucleus\View\View;
13
14
use BrightNucleus\Config\Exception\FailedToProcessConfigException;
15
use BrightNucleus\View\Exception\FailedToInstantiateView;
16
use BrightNucleus\View\View;
17
use BrightNucleus\View\Engine\Engine;
18
use BrightNucleus\View\ViewBuilder;
19
use BrightNucleus\Views;
20
use Closure;
21
22
/**
23
 * Abstract class AbstractView.
24
 *
25
 * @since   0.1.0
26
 *
27
 * @package BrightNucleus\View\View
28
 * @author  Alain Schlesser <[email protected]>
29
 */
30
abstract class AbstractView implements View
31
{
32
33
    /**
34
     * URI of the view.
35
     *
36
     * The underscores are used to prevent accidental use of these properties from within the rendering closure.
37
     *
38
     * @since 0.1.0
39
     *
40
     * @var string
41
     */
42
    protected $_uri_;
43
44
    /**
45
     * Engine to use for the view.
46
     *
47
     * The underscores are used to prevent accidental use of these properties from within the rendering closure.
48
     *
49
     * @since 0.1.0
50
     *
51
     * @var Engine
52
     */
53
    protected $_engine_;
54
55
    /**
56
     * ViewBuilder instance.
57
     *
58
     * The underscores are used to prevent accidental use of these properties from within the rendering closure.
59
     *
60
     * @since 0.2.0
61
     *
62
     * @var ViewBuilder
63
     */
64
    protected $_builder_;
65
66 29
    /**
67
     * The context with which the view will be rendered.
68 29
     *
69 29
     * The underscores are used to prevent accidental use of these properties from within the rendering closure.
70 29
     *
71
     * @since 0.4.0
72
     *
73
     * @var array
74
     */
75
    protected $_context_ = [];
76
77
    /**
78
     * Instantiate an AbstractView object.
79
     *
80
     * @since 0.1.0
81
     *
82 29
     * @param string      $uri         URI for the view.
83
     * @param Engine      $engine      Engine to use for the view.
84 29
     * @param ViewBuilder $viewBuilder View builder instance to use.
0 ignored issues
show
Documentation introduced by
Should the type for parameter $viewBuilder not be null|ViewBuilder?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
85 29
     */
86
    public function __construct(string $uri, Engine $engine, ViewBuilder $viewBuilder = null)
87 29
    {
88 29
        $this->_uri_     = $uri;
89
        $this->_engine_  = $engine;
90 29
        $this->_builder_ = $viewBuilder ?? Views::getViewBuilder();
91
    }
92
93 29
    /**
94 29
     * Render the view.
95
     *
96
     * @since 0.1.0
97
     *
98
     * @param array $context Optional. The context in which to render the view.
99
     * @param bool  $echo    Optional. Whether to echo the output immediately. Defaults to false.
100
     *
101
     * @return string Rendered HTML.
102
     * @throws FailedToProcessConfigException If the Config could not be processed.
103
     */
104
    public function render(array $context = [], bool $echo = false): string
105
    {
106
        $this->assimilateContext($context);
107
108
        $closure = Closure::bind(
109
            $this->_engine_->getRenderCallback($this->_uri_, $context),
110
            $this,
111 1
            static::class
112
        );
113 1
114 1
        $output = $closure();
115
116
        if ($echo) {
117 1
            echo $output;
118 1
        }
119
120 1
        return $output;
121
    }
122
123
    /**
124
     * Render a partial view (or section) for a given URI.
125
     *
126
     * @since 0.2.0
127
     *
128
     * @param string      $view    View identifier to create a view for.
129
     * @param array       $context Optional. The context in which to render the view.
0 ignored issues
show
Documentation introduced by
Should the type for parameter $context not be null|array? Also, consider making the array more specific, something like array<String>, or String[].

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive. In addition it looks for parameters that have the generic type array and suggests a stricter type like array<String>.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
130
     * @param string|null $type    Type of view to create.
131
     *
132 29
     * @return string Rendered HTML content.
133
     * @throws FailedToProcessConfigException If the Config could not be processed.
134 29
     * @throws FailedToInstantiateView If the View could not be instantiated.
135
     */
136 29
    public function section(string $view, array $context = null, $type = null): string
137
    {
138
        if (null === $context) {
139
            $context = $this->_context_;
140
        }
141
142
        $viewObject = $this->_builder_->create($view, $type);
143
144 29
        return $viewObject->render($context);
145
    }
146 29
147
    /**
148
     * Get the entire array of contextual data.
149 29
     *
150
     * @since 0.4.0
151
     *
152
     * @return array Array of contextual data.
153
     */
154
    public function getContext(): array
155
    {
156
        return $this->_context_;
157
    }
158 29
159
    /**
160 29
     * Associate a view builder with this view.
161 29
     *
162 29
     * @since 0.2.0
163
     *
164 29
     * @param ViewBuilder $builder
165
     *
166
     * @return View
167
     */
168
    public function setBuilder(ViewBuilder $builder): View
169
    {
170
        $this->_builder_ = $builder;
171
172
        return $this;
173
    }
174
175
    /**
176
     * Assimilate the context to make it available as properties.
177
     *
178
     * @since 0.2.0
179
     *
180
     * @param array $context Context to assimilate.
181
     */
182
    protected function assimilateContext(array $context = [])
183
    {
184
        $this->_context_ = $context;
185
        foreach ($context as $key => $value) {
186
            $this->$key = $value;
187
        }
188
    }
189
190
    /**
191
     * Turn invokable objects as properties into methods of the view.
192
     *
193
     * @param string $method    Method that was called on the view.
194
     * @param array  $arguments Array of arguments that were used.
195
     * @return mixed Return value of the invokable object.
196
     */
197
    public function __call($method, $arguments) {
198
        if ( ! property_exists($this, $method)
199
             || ! is_callable($this->$method)) {
200
            trigger_error(
201
                "Call to undefined method {$method} on a view.",
202
                E_USER_ERROR
203
            );
204
        }
205
206
        $callable = $this->$method;
207
208
        return $callable(...$arguments);
209
    }
210
}
211