Twig   A
last analyzed

Complexity

Total Complexity 22

Size/Duplication

Total Lines 255
Duplicated Lines 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
wmc 22
eloc 39
c 2
b 0
f 0
dl 0
loc 255
rs 10

17 Methods

Rating   Name   Duplication   Size   Complexity  
A fromRequest() 0 10 2
A getLoader() 0 3 1
A getIterator() 0 3 1
A offsetExists() 0 3 1
A create() 0 14 4
A addRuntimeLoader() 0 3 1
A offsetUnset() 0 3 1
A offsetGet() 0 7 2
A fetchBlock() 0 5 1
A render() 0 5 1
A count() 0 3 1
A offsetSet() 0 3 1
A addExtension() 0 3 1
A getEnvironment() 0 3 1
A fetch() 0 5 1
A fetchFromString() 0 5 1
A __construct() 0 4 1
1
<?php
2
/** @noinspection PhpParameterNameChangedDuringInheritanceInspection */
3
4
/**
5
 * Copied from https://github.com/slimphp/Twig-View
6
 * @license https://github.com/slimphp/Twig-View/blob/master/LICENSE.md (MIT License)
7
 */
8
9
declare(strict_types=1);
10
11
namespace Jasny\Controller\View;
12
13
use ArrayAccess;
14
use ArrayIterator;
15
use Psr\Http\Message\ResponseInterface;
16
use Psr\Http\Message\ServerRequestInterface;
17
use ReturnTypeWillChange;
18
use RuntimeException;
19
use Throwable;
20
use Twig\Environment;
21
use Twig\Error\LoaderError;
22
use Twig\Error\RuntimeError;
23
use Twig\Error\SyntaxError;
24
use Twig\Extension\ExtensionInterface;
25
use Twig\Loader\FilesystemLoader;
26
use Twig\Loader\LoaderInterface;
27
use Twig\RuntimeLoader\RuntimeLoaderInterface;
28
29
use function array_key_exists;
30
use function array_merge;
31
use function count;
32
use function is_array;
33
use function is_string;
34
35
/**
36
 * Twig View
37
 *
38
 * This class is a view helper built on top of the Twig templating component.
39
 * Twig is a PHP component created by Fabien Potencier.
40
 *
41
 * @link https://twig.symfony.com/
42
 *
43
 * @codeCoverageIgnore
44
 *
45
 * @implements ArrayAccess<string, mixed>
46
 */
47
class Twig implements ArrayAccess
48
{
49
    /**
50
     * Twig loader
51
     */
52
    protected LoaderInterface $loader;
53
54
    /**
55
     * Twig environment
56
     */
57
    protected Environment $environment;
58
59
    /**
60
     * Default view variables
61
     *
62
     * @var array<string, mixed>
63
     */
64
    protected array $defaultVariables = [];
65
66
    /**
67
     * @param ServerRequestInterface $request
68
     * @param string                 $attributeName
69
     *
70
     * @return Twig
71
     */
72
    public static function fromRequest(ServerRequestInterface $request, string $attributeName = 'view'): self
73
    {
74
        $twig = $request->getAttribute($attributeName);
75
        if (!($twig instanceof self)) {
76
            throw new RuntimeException(
77
                'Twig could not be found in the server request attributes using the key "' . $attributeName . '".'
78
            );
79
        }
80
81
        return $twig;
82
    }
83
84
    /**
85
     * @param string|string[]      $path     Path(s) to templates directory
86
     * @param array<string, mixed> $settings Twig environment settings
87
     *
88
     * @throws LoaderError When the template cannot be found
89
     *
90
     * @return Twig
91
     */
92
    public static function create(string | array $path, array $settings = []): self
93
    {
94
        $loader = new FilesystemLoader();
95
96
        $paths = is_array($path) ? $path : [$path];
0 ignored issues
show
introduced by
The condition is_array($path) is always true.
Loading history...
97
        foreach ($paths as $namespace => $cur) {
98
            if (is_string($namespace)) {
99
                $loader->setPaths($cur, $namespace);
100
            } else {
101
                $loader->addPath($cur);
102
            }
103
        }
104
105
        return new self($loader, $settings);
106
    }
107
108
    /**
109
     * @param LoaderInterface      $loader   Twig loader
110
     * @param array<string, mixed> $settings Twig environment settings
111
     */
112
    public function __construct(LoaderInterface $loader, array $settings = [])
113
    {
114
        $this->loader = $loader;
115
        $this->environment = new Environment($this->loader, $settings);
116
    }
117
118
    /**
119
     * Proxy method to add an extension to the Twig environment
120
     *
121
     * @param ExtensionInterface $extension A single extension instance or an array of instances
122
     */
123
    public function addExtension(ExtensionInterface $extension): void
124
    {
125
        $this->environment->addExtension($extension);
126
    }
127
128
    /**
129
     * Proxy method to add a runtime loader to the Twig environment
130
     *
131
     * @param RuntimeLoaderInterface $runtimeLoader
132
     */
133
    public function addRuntimeLoader(RuntimeLoaderInterface $runtimeLoader): void
134
    {
135
        $this->environment->addRuntimeLoader($runtimeLoader);
136
    }
137
138
    /**
139
     * Fetch rendered template
140
     *
141
     * @param  string               $template Template pathname relative to templates directory
142
     * @param  array<string, mixed> $data     Associative array of template variables
143
     *
144
     * @throws LoaderError  When the template cannot be found
145
     * @throws SyntaxError  When an error occurred during compilation
146
     * @throws RuntimeError When an error occurred during rendering
147
     *
148
     * @return string
149
     */
150
    public function fetch(string $template, array $data = []): string
151
    {
152
        $data = array_merge($this->defaultVariables, $data);
153
154
        return $this->environment->render($template, $data);
155
    }
156
157
    /**
158
     * Fetch rendered block
159
     *
160
     * @param  string               $template Template pathname relative to templates directory
161
     * @param  string               $block    Name of the block within the template
162
     * @param  array<string, mixed> $data     Associative array of template variables
163
     *
164
     * @throws Throwable   When an error occurred during rendering
165
     * @throws LoaderError When the template cannot be found
166
     * @throws SyntaxError When an error occurred during compilation
167
     *
168
     * @return string
169
     */
170
    public function fetchBlock(string $template, string $block, array $data = []): string
171
    {
172
        $data = array_merge($this->defaultVariables, $data);
173
174
        return $this->environment->resolveTemplate($template)->renderBlock($block, $data);
175
    }
176
177
    /**
178
     * Fetch rendered string
179
     *
180
     * @param  string               $string String
181
     * @param  array<string, mixed> $data   Associative array of template variables
182
     *
183
     * @throws LoaderError When the template cannot be found
184
     * @throws SyntaxError When an error occurred during compilation
185
     *
186
     * @return string
187
     */
188
    public function fetchFromString(string $string = '', array $data = []): string
189
    {
190
        $data = array_merge($this->defaultVariables, $data);
191
192
        return $this->environment->createTemplate($string)->render($data);
193
    }
194
195
    /**
196
     * Output rendered template
197
     *
198
     * @param  ResponseInterface    $response
199
     * @param  string               $template Template pathname relative to templates directory
200
     * @param  array<string, mixed> $data Associative array of template variables
201
     *
202
     * @throws LoaderError  When the template cannot be found
203
     * @throws SyntaxError  When an error occurred during compilation
204
     * @throws RuntimeError When an error occurred during rendering
205
     *
206
     * @return ResponseInterface
207
     */
208
    public function render(ResponseInterface $response, string $template, array $data = []): ResponseInterface
209
    {
210
        $response->getBody()->write($this->fetch($template, $data));
211
212
        return $response;
213
    }
214
215
    /**
216
     * Return Twig loader
217
     *
218
     * @return LoaderInterface
219
     */
220
    public function getLoader(): LoaderInterface
221
    {
222
        return $this->loader;
223
    }
224
225
    /**
226
     * Return Twig environment
227
     *
228
     * @return Environment
229
     */
230
    public function getEnvironment(): Environment
231
    {
232
        return $this->environment;
233
    }
234
235
    /**
236
     * Does this collection have a given key?
237
     *
238
     * @param  string $key The data key
239
     *
240
     * @return bool
241
     */
242
    public function offsetExists($key): bool
243
    {
244
        return array_key_exists($key, $this->defaultVariables);
245
    }
246
247
    /**
248
     * Get collection item for key
249
     *
250
     * @param string $key The data key
251
     *
252
     * @return mixed The key's value, or the default value
253
     */
254
    #[ReturnTypeWillChange]
255
    public function offsetGet($key): mixed
256
    {
257
        if (!$this->offsetExists($key)) {
258
            return null;
259
        }
260
        return $this->defaultVariables[$key];
261
    }
262
263
    /**
264
     * Set collection item
265
     *
266
     * @param string $key   The data key
267
     * @param mixed  $value The data value
268
     */
269
    public function offsetSet($key, mixed $value): void
0 ignored issues
show
introduced by
Parameter #1 $key (string) of method Jasny\Controller\View\Twig::offsetSet() should be contravariant with parameter $offset (string|null) of method ArrayAccess<string,mixed>::offsetSet()
Loading history...
270
    {
271
        $this->defaultVariables[$key] = $value;
272
    }
273
274
    /**
275
     * Remove item from collection
276
     *
277
     * @param string $key The data key
278
     */
279
    public function offsetUnset($key): void
280
    {
281
        unset($this->defaultVariables[$key]);
282
    }
283
284
    /**
285
     * Get number of items in collection
286
     *
287
     * @return int
288
     */
289
    public function count(): int
290
    {
291
        return count($this->defaultVariables);
292
    }
293
294
    /**
295
     * Get collection iterator
296
     *
297
     * @return ArrayIterator<string, mixed>
298
     */
299
    public function getIterator(): ArrayIterator
300
    {
301
        return new ArrayIterator($this->defaultVariables);
302
    }
303
}