Completed
Push — add_append_feature ( b5a788...d2d302 )
by Jonathan
02:04
created

Template::render()   C

Complexity

Conditions 7
Paths 31

Size

Total Lines 41
Code Lines 25

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 27
CRAP Score 7.0022

Importance

Changes 0
Metric Value
dl 0
loc 41
ccs 27
cts 28
cp 0.9643
rs 6.7272
c 0
b 0
f 0
cc 7
eloc 25
nc 31
nop 1
crap 7.0022
1
<?php
2
3
namespace League\Plates\Template;
4
5
use Exception;
6
use League\Plates\Engine;
7
use LogicException;
8
use Throwable;
9
10
/**
11
 * Container which holds template data and provides access to template functions.
12
 */
13
class Template
14
{
15
    /**
16
     * Instance of the template engine.
17
     * @var Engine
18
     */
19
    protected $engine;
20
21
    /**
22
     * The name of the template.
23
     * @var Name
24
     */
25
    protected $name;
26
27
    /**
28
     * The data assigned to the template.
29
     * @var array
30
     */
31
    protected $data = array();
32
33
    /**
34
     * An array of section content.
35
     * @var array
36
     */
37
    protected $sections = array();
38
39
    /**
40
     * The name of the section currently being rendered.
41
     * @var string
42
     */
43
    protected $currentSection;
44
45
    /**
46
     * The name of the template layout.
47
     * @var string
48
     */
49
    protected $layoutName;
50
51
    /**
52
     * The data assigned to the template layout.
53
     * @var array
54
     */
55
    protected $layoutData;
56
57
    /**
58
     * Create new Template instance.
59
     * @param Engine $engine
60
     * @param string $name
61
     */
62 124
    public function __construct(Engine $engine, $name)
63
    {
64 124
        $this->engine = $engine;
65 124
        $this->name = new Name($engine, $name);
66
67 124
        $this->data($this->engine->getData($name));
68 124
    }
69
70
    /**
71
     * Magic method used to call extension functions.
72
     * @param  string $name
73
     * @param  array  $arguments
74
     * @return mixed
75
     */
76 8
    public function __call($name, $arguments)
77
    {
78 8
        return $this->engine->getFunction($name)->call($this, $arguments);
79
    }
80
81
    /**
82
     * Alias for render() method.
83
     * @throws \Throwable
84
     * @throws \Exception
85
     * @return string
86
     */
87 4
    public function __toString()
88
    {
89 4
        return $this->render();
90
    }
91
92
    /**
93
     * Assign or get template data.
94
     * @param  array $data
95
     * @return mixed
96
     */
97 124
    public function data(array $data = null)
98
    {
99 124
        if (is_null($data)) {
100 4
            return $this->data;
101
        }
102
103 124
        $this->data = array_merge($this->data, $data);
104 124
    }
105
106
    /**
107
     * Check if the template exists.
108
     * @return boolean
109
     */
110 108
    public function exists()
111
    {
112 108
        return $this->name->doesPathExist();
113
    }
114
115
    /**
116
     * Get the template path.
117
     * @return string
118
     */
119 104
    public function path()
120
    {
121 104
        return $this->name->getPath();
122
    }
123
124
    /**
125
     * Render the template and layout.
126
     * @param  array  $data
127
     * @throws \Throwable
128
     * @throws \Exception
129
     * @return string
130
     */
131 100
    public function render(array $data = array())
132
    {
133 100
        $this->data($data);
134 100
        unset($data);
135 100
        extract($this->data);
136
137 100
        if (!$this->exists()) {
138 4
            throw new LogicException(
139 4
                'The template "' . $this->name->getName() . '" could not be found at "' . $this->path() . '".'
140 3
            );
141
        }
142
143
        try {
144 96
            $level = ob_get_level();
145 96
            ob_start();
146
147 96
            include $this->path();
148
149 72
            $content = ob_get_clean();
150
151 72
            if (isset($this->layoutName)) {
152 20
                $layout = $this->engine->make($this->layoutName);
153 20
                $layout->sections = array_merge($this->sections, array('content' => $content));
154 20
                $content = $layout->render($this->layoutData);
155 15
            }
156
157 72
            return $content;
158 24
        } catch (Throwable $e) {
0 ignored issues
show
Bug introduced by
The class Throwable does not exist. Is this class maybe located in a folder that is not analyzed, or in a newer version of your dependencies than listed in your composer.lock/composer.json?
Loading history...
159 6
            while (ob_get_level() > $level) {
160 6
                ob_end_clean();
161
            }
162
163 6
            throw $e;
164 18
        } catch (Exception $e) {
165 18
            while (ob_get_level() > $level) {
166 18
                ob_end_clean();
167 18
            }
168
169 18
            throw $e;
170
        }
171
    }
172
173
    /**
174
     * Set the template's layout.
175
     * @param  string $name
176
     * @param  array  $data
177
     * @return null
178
     */
179 20
    public function layout($name, array $data = array())
180
    {
181 20
        $this->layoutName = $name;
182 20
        $this->layoutData = $data;
183 20
    }
184
185
    /**
186
     * Start a new section block.
187
     * @param  string $name
188
     * @return null
189
     */
190 20
    public function start($name)
191
    {
192 20
        if ($name === 'content') {
193 4
            throw new LogicException(
194 1
                'The section name "content" is reserved.'
195 3
            );
196
        }
197
198 16
        if ($this->currentSection) {
199 4
            throw new LogicException('You cannot nest sections within other sections.');
200
        }
201
202 16
        $this->currentSection = $name;
203
204 16
        ob_start();
205 16
    }
206
207
    /**
208
     * Stop the current section block.
209
     * @return null
210
     */
211 16
    public function stop()
212
    {
213 16
        if (is_null($this->currentSection)) {
214 4
            throw new LogicException(
215 1
                'You must start a section before you can stop it.'
216 3
            );
217
        }
218
219 12
        $this->sections[$this->currentSection] = ob_get_clean();
220 12
        $this->currentSection = null;
221 12
    }
222
223
    /**
224
     * Stop the current section block and append the results.
225
     * @return null
226
     */
227 12
    public function append()
228
    {
229 12
        if (is_null($this->currentSection)) {
230 4
            throw new LogicException(
231 1
                'You must start a section before you can append it.'
232 3
            );
233
        }
234
235 8
        $this->sections[$this->currentSection] .= ob_get_clean();
236 8
        $this->currentSection = null;
237 8
    }
238
239
    /**
240
     * Returns the content for a section block.
241
     * @param  string      $name    Section name
242
     * @param  string      $default Default section content
243
     * @return string|null
244
     */
245 20
    public function section($name, $default = null)
246
    {
247 20
        if (!isset($this->sections[$name])) {
248 8
            return $default;
249
        }
250
251 12
        return $this->sections[$name];
252
    }
253
254
    /**
255
     * Fetch a rendered template.
256
     * @param  string $name
257
     * @param  array  $data
258
     * @return string
259
     */
260 4
    public function fetch($name, array $data = array())
261
    {
262 4
        return $this->engine->render($name, $data);
263
    }
264
265
    /**
266
     * Output a rendered template.
267
     * @param  string $name
268
     * @param  array  $data
269
     * @return null
270
     */
271 4
    public function insert($name, array $data = array())
272
    {
273 4
        echo $this->engine->render($name, $data);
274 4
    }
275
276
    /**
277
     * Apply multiple functions to variable.
278
     * @param  mixed  $var
279
     * @param  string $functions
280
     * @return mixed
281
     */
282 12
    public function batch($var, $functions)
283
    {
284 12
        foreach (explode('|', $functions) as $function) {
285 12
            if ($this->engine->doesFunctionExist($function)) {
286 4
                $var = call_user_func(array($this, $function), $var);
287 12
            } elseif (is_callable($function)) {
288 8
                $var = call_user_func($function, $var);
289 6
            } else {
290 4
                throw new LogicException(
291 6
                    'The batch function could not find the "' . $function . '" function.'
292 3
                );
293
            }
294 6
        }
295
296 8
        return $var;
297
    }
298
299
    /**
300
     * Escape string.
301
     * @param  string      $string
302
     * @param  null|string $functions
303
     * @return string
304
     */
305 12
    public function escape($string, $functions = null)
306
    {
307 12
        static $flags;
308
309 12
        if (!isset($flags)) {
310 4
            $flags = ENT_QUOTES | (defined('ENT_SUBSTITUTE') ? ENT_SUBSTITUTE : 0);
311 3
        }
312
313 12
        if ($functions) {
314 4
            $string = $this->batch($string, $functions);
315 3
        }
316
317 12
        return htmlspecialchars($string, $flags, 'UTF-8');
318
    }
319
320
    /**
321
     * Alias to escape function.
322
     * @param  string      $string
323
     * @param  null|string $functions
324
     * @return string
325
     */
326 4
    public function e($string, $functions = null)
327
    {
328 4
        return $this->escape($string, $functions);
329
    }
330
}
331