Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
42 / 42
100.00% covered (success)
100.00%
15 / 15
CRAP
100.00% covered (success)
100.00%
1 / 1
View
100.00% covered (success)
100.00%
42 / 42
100.00% covered (success)
100.00%
15 / 15
32
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
5
 hasTemplate
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getTemplate
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getOutput
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 isFile
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
2
 isStream
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
2
 getData
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 get
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setTemplate
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
7
 setData
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 set
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 merge
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 filter
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
4
 render
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
3
 __toString
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2declare(strict_types=1);
3/**
4 * Pop PHP Framework (https://www.popphp.org/)
5 *
6 * @link       https://github.com/popphp/popphp-framework
7 * @author     Nick Sagona, III <nick@popphp.org>
8 * @copyright  Copyright (c) 2009-2026 Nick Sagona, III
9 * @license    https://www.popphp.org/license     New BSD License
10 */
11
12/**
13 * @namespace
14 */
15namespace Pop\View;
16
17use Pop\Filter\FilterableTrait;
18use Pop\Utils;
19
20/**
21 * View class
22 *
23 * @category   Pop
24 * @package    Pop\View
25 * @author     Nick Sagona, III <nick@popphp.org>
26 * @copyright  Copyright (c) 2009-2026 Nick Sagona, III
27 * @license    https://www.popphp.org/license     New BSD License
28 * @version    5.0.0
29 */
30class View extends Utils\ArrayObject
31{
32
33    use FilterableTrait;
34
35    /**
36     * View template object
37     * @var ?Template\TemplateInterface
38     */
39    protected ?Template\TemplateInterface $template = null;
40
41    /**
42     * Model data
43     * @var mixed
44     */
45    protected mixed $data = [];
46
47    /**
48     * View output string
49     * @var ?string
50     */
51    protected ?string $output = null;
52
53    /**
54     * Constructor
55     *
56     * Instantiate the view object
57     *
58     * @param  mixed  $template
59     * @param  ?array $data
60     * @param  mixed  $filters
61     */
62    public function __construct(mixed $template = null, ?array $data = null, mixed $filters = null)
63    {
64        if ($template !== null) {
65            $this->setTemplate($template);
66        }
67        if ($data !== null) {
68            parent::__construct($data);
69        }
70        if ($filters !== null) {
71            if (is_array($filters)) {
72                $this->addFilters($filters);
73            } else {
74                $this->addFilter($filters);
75            }
76        }
77    }
78
79    /**
80     * Has a view template
81     *
82     * @return bool
83     */
84    public function hasTemplate(): bool
85    {
86        return ($this->template !== null);
87    }
88
89    /**
90     * Get view template
91     *
92     * @return Template\TemplateInterface
93     */
94    public function getTemplate(): Template\TemplateInterface
95    {
96        return $this->template;
97    }
98
99    /**
100     * Get rendered output
101     *
102     * @return string
103     */
104    public function getOutput(): string
105    {
106        return $this->output;
107    }
108
109    /**
110     * Is view template a file
111     *
112     * @return bool
113     */
114    public function isFile(): bool
115    {
116        return (($this->template !== null) && ($this->template instanceof Template\File));
117    }
118
119    /**
120     * Is view template a stream
121     *
122     * @return bool
123     */
124    public function isStream(): bool
125    {
126        return (($this->template !== null) && ($this->template instanceof Template\Stream));
127    }
128
129    /**
130     * Get all model data
131     *
132     * @return array
133     */
134    public function getData(): array
135    {
136        return $this->data;
137    }
138
139    /**
140     * Get data
141     *
142     * @param  string $key
143     * @return mixed
144     */
145    public function get(string $key): mixed
146    {
147        return $this->data[$key] ?? null;
148    }
149
150    /**
151     * Set view template
152     *
153     * @param  mixed $template
154     * @return static
155     */
156    public function setTemplate(mixed $template): static
157    {
158        if (!($template instanceof Template\TemplateInterface)) {
159            // If a native PHP file template
160            if (((str_ends_with($template, '.phtml')) ||
161                    (substr($template, -5, 4) == '.php') ||
162                    (str_ends_with($template, '.php'))) && (strlen($template) <= 255) && (file_exists($template))) {
163                $template = new Template\File($template);
164            // If a string template, or a string template from a non-PHP file
165            } else {
166                $template = new Template\Stream($template);
167            }
168        }
169        $this->template = $template;
170        return $this;
171    }
172
173    /**
174     * Set all model data
175     *
176     * @param  array $data
177     * @return static
178     */
179    public function setData(array $data = []): static
180    {
181        $this->data = $data;
182        return $this;
183    }
184
185    /**
186     * Set model data
187     *
188     * @param  string $name
189     * @param  mixed  $value
190     * @return static
191     */
192    public function set(string $name, mixed $value): static
193    {
194        $this->data[$name] = $value;
195        return $this;
196    }
197
198    /**
199     * Merge new model data
200     *
201     * @param  array $data
202     * @return static
203     */
204    public function merge(array $data): static
205    {
206        $this->data = array_merge($this->data, $data);
207        return $this;
208    }
209
210    /**
211     * Filter values
212     *
213     * @param  mixed $values
214     * @return mixed
215     */
216    public function filter(mixed $values): mixed
217    {
218        foreach ($this->filters as $filter) {
219            if (is_array($values)) {
220                foreach ($values as $key => $value) {
221                    $values[$key] = $filter->filter($value, (string)$key);
222                }
223            } else {
224                $values = [$filter->filter($values)];
225            }
226        }
227
228        return $values;
229    }
230
231    /**
232     * Render the view
233     *
234     * @throws Exception|Template\Exception
235     * @return ?string
236     */
237    public function render(): ?string
238    {
239        if ($this->template === null) {
240            throw new Exception('A template asset has not been assigned.');
241        }
242
243        if ($this->hasFilters()) {
244            $this->data = $this->filter($this->data);
245        }
246
247        $this->output = $this->template->render($this->data);
248        return $this->output;
249    }
250
251    /**
252     * Return rendered view as string
253     *
254     * @return string
255     */
256    public function __toString(): string
257    {
258        return $this->render();
259    }
260
261}