Completed
Branch 09branch (31301e)
by Anton
06:38
created

TwigEngine::makeTwig()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 17
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 8
nc 2
nop 2
dl 0
loc 17
rs 9.4285
c 0
b 0
f 0
1
<?php
2
/**
3
 * spiral
4
 *
5
 * @author    Wolfy-J
6
 */
7
8
namespace Spiral\Views\Engines;
9
10
use Spiral\Core\ContainerInterface;
11
use Spiral\Debug\Traits\BenchmarkTrait;
12
use Spiral\Files\FilesInterface;
13
use Spiral\Views\EngineInterface;
14
use Spiral\Views\Engines\Prototypes\AbstractEngine;
15
use Spiral\Views\Engines\Twig\Exceptions\CompileException;
16
use Spiral\Views\Engines\Twig\LoaderBridge;
17
use Spiral\Views\Engines\Twig\TwigCache;
18
use Spiral\Views\Engines\Twig\TwigView;
19
use Spiral\Views\EnvironmentInterface;
20
use Spiral\Views\LoaderInterface;
21
use Spiral\Views\Loaders\ModifiableLoader;
22
use Spiral\Views\ViewInterface;
23
24
/**
25
 * Wraps and control twig engine.
26
 */
27
class TwigEngine extends AbstractEngine
28
{
29
    use BenchmarkTrait;
30
31
    /**
32
     * Set of class names (processors) to be applied to view sources befor giving it to Twig.
33
     *
34
     * @var array
35
     */
36
    protected $modifiers = [];
37
38
    /**
39
     * @var \Twig_Environment
40
     */
41
    protected $twig;
42
43
    /**
44
     * @var FilesInterface
45
     */
46
    protected $files;
47
48
    /**
49
     * @var ContainerInterface
50
     */
51
    protected $container;
52
53
    /**
54
     * TwigEngine constructor.
55
     *
56
     * @param EnvironmentInterface    $environment
57
     * @param LoaderInterface         $loader
58
     * @param FilesInterface|null     $files
59
     * @param ContainerInterface|null $container
60
     * @param array                   $modifiers
61
     * @param array                   $extensions
62
     * @param array                   $options
63
     */
64
    public function __construct(
65
        EnvironmentInterface $environment,
66
        LoaderInterface $loader,
67
        FilesInterface $files = null,
68
        ContainerInterface $container = null,
69
        array $modifiers = [],
70
        array $extensions = [],
71
        array $options = []
72
    ) {
73
        parent::__construct($environment, $loader);
74
        $this->container = $container;
75
        $this->files = $files;
76
        $this->modifiers = $modifiers;
77
78
        //Initiating twig Environment
79
        $this->twig = $this->makeTwig($extensions, $options);
80
    }
81
82
    /**
83
     * Get associated twig environment.
84
     *
85
     * @return \Twig_Environment
86
     */
87
    public function getTwig()
88
    {
89
        return $this->twig;
90
    }
91
92
    /**
93
     * {@inheritdoc}
94
     *
95
     * @throws CompileException
96
     */
97
    public function get(string $path): ViewInterface
98
    {
99
        $benchmark = $this->benchmark('load', $path);
100
101
        try {
102
            return new TwigView($this->twig->load($path));
103
        } catch (\Twig_Error_Syntax $exception) {
104
            //Let's clarify exception location
105
            throw CompileException::fromTwig($exception);
106
        } finally {
107
            $this->benchmark($benchmark);
108
        }
109
    }
110
111
    /**
112
     * {@inheritdoc}
113
     */
114
    public function render(string $path, array $context = []): string
115
    {
116
        $benchmark = $this->benchmark('render', $path);
117
        try {
118
            return $this->get($path)->render($context);
119
        } finally {
120
            $this->benchmark($benchmark);
121
        }
122
    }
123
124
    /**
125
     * {@inheritdoc}
126
     */
127
    public function compile(string $path, bool $reset = false)
128
    {
129
        if ($reset) {
130
            $cache = $this->twig->getCache();
131
            $this->twig->setCache(false);
132
        }
133
134
        //This must force twig to compile template
135
        $this->get($path);
136
137
        if ($reset && !empty($cache)) {
138
            //Restoring cache
139
            $this->twig->setCache($cache);
140
        }
141
    }
142
143
    /**
144
     * {@inheritdoc}
145
     */
146
    public function withLoader(LoaderInterface $loader): EngineInterface
147
    {
148
        /**
149
         * @var self $engine
150
         */
151
        $engine = parent::withLoader($loader);
152
153
        $engine->twig = clone $this->twig;
154
        $engine->twig->setLoader($engine->makeLoader());
155
156
        return $engine;
157
    }
158
159
    /**
160
     * {@inheritdoc}
161
     *
162
     * @return $this
163
     */
164
    public function withEnvironment(EnvironmentInterface $environment): EngineInterface
165
    {
166
        /**
167
         * @var self $engine
168
         */
169
        $engine = parent::withEnvironment($environment);
170
171
        $engine->twig = clone $this->twig;
172
        $engine->twig->setLoader($engine->makeLoader());
173
        $engine->twig->setCache($engine->makeCache());
174
175
        return $engine;
176
    }
177
178
    /**
179
     * Initiating twig environment.
180
     *
181
     * @param array $extensions
182
     * @param array $options
183
     *
184
     * @return \Twig_Environment
185
     */
186
    protected function makeTwig(array $extensions, array $options): \Twig_Environment
187
    {
188
        //Initiating Twig Environment
189
        $twig = $this->container->make(\Twig_Environment::class, [
190
            'loader'  => $this->makeLoader(),
191
            'options' => $options
192
        ]);
193
194
        $twig->setCache($this->makeCache());
195
196
        foreach ($extensions as $extension) {
197
            //Each extension can be delivered thought container
198
            $twig->addExtension($this->container->get($extension));
199
        }
200
201
        return $twig;
202
    }
203
204
    /**
205
     * In most of cases twig will get view processors to be executed before twig itself, to run
206
     * such processors we need special wrapper at top of environment.
207
     *
208
     * @return \Twig_LoaderInterface
209
     */
210 View Code Duplication
    private function makeLoader(): \Twig_LoaderInterface
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
211
    {
212
        $modifiers = [];
213
        foreach ($this->modifiers as $modifier) {
214
            if (is_object($modifier)) {
215
                $modifiers[] = $modifier;
216
            } else {
217
                $modifiers[] = $this->container->make($modifier);
218
            }
219
        }
220
221
        return new LoaderBridge(
222
            new ModifiableLoader($this->environment, $this->loader, $modifiers)
223
        );
224
    }
225
226
    /**
227
     * @return bool|TwigCache
228
     */
229
    private function makeCache()
230
    {
231
        if (!$this->environment->isCachable()) {
232
            return false;
233
        }
234
235
        return new TwigCache($this->files, $this->environment);
236
    }
237
}