Completed
Pull Request — v3 (#246)
by
unknown
03:07
created

Template::stop()   B

Complexity

Conditions 6
Paths 9

Size

Total Lines 30

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 7.3329

Importance

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