Completed
Branch 09branch (0a5c88)
by Anton
05:50
created

TwigEngine::wrapLoader()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 13
Code Lines 8

Duplication

Lines 13
Ratio 100 %

Importance

Changes 0
Metric Value
cc 3
eloc 8
nc 3
nop 0
dl 13
loc 13
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\ContextLoader;
16
use Spiral\Views\Engines\Twig\Exceptions\SyntaxException;
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\ViewInterface;
22
23
/**
24
 * Wraps and control twig engine.
25
 */
26
class TwigEngine extends AbstractEngine
27
{
28
    use BenchmarkTrait;
29
30
    /**
31
     * Set of class names (processors) to be applied to view sources befor giving it to Twig.
32
     *
33
     * @var array
34
     */
35
    protected $modifiers = [];
36
37
    /**
38
     * @var \Twig_Environment
39
     */
40
    protected $twig;
41
42
    /**
43
     * @var FilesInterface
44
     */
45
    protected $files;
46
47
    /**
48
     * @var ContainerInterface
49
     */
50
    protected $container;
51
52
    /**
53
     * TwigEngine constructor.
54
     *
55
     * @param EnvironmentInterface    $environment
56
     * @param LoaderInterface         $loader
57
     * @param FilesInterface|null     $files
58
     * @param ContainerInterface|null $container
59
     * @param array                   $modifiers
60
     * @param array                   $extensions
61
     * @param array                   $options
62
     */
63
    public function __construct(
64
        EnvironmentInterface $environment,
65
        LoaderInterface $loader,
66
        FilesInterface $files = null,
67
        ContainerInterface $container = null,
68
        array $modifiers = [],
69
        array $extensions = [],
70
        array $options = []
71
    ) {
72
        parent::__construct($environment, $loader);
73
        $this->container = $container;
74
        $this->files = $files;
75
        $this->modifiers = $modifiers;
76
77
        //Initiating twig Environment
78
        $this->twig = $this->createTwig($extensions, $options);
79
    }
80
81
    /**
82
     * Get associated twig environment.
83
     *
84
     * @return \Twig_Environment
85
     */
86
    public function getTwig()
87
    {
88
        return $this->twig;
89
    }
90
91
    /**
92
     * {@inheritdoc}
93
     *
94
     * @throws SyntaxException
95
     */
96
    public function get(string $path): ViewInterface
97
    {
98
        $benchmark = $this->benchmark('load', $path);
99
        try {
100
            //Yeah... we are using internal method for now, the only alternative is to wrap
101
            //template wrapper, but there is already too much wrappers in a world
102
            return $this->twig->loadTemplate($path);
103
        } catch (\Twig_Error_Syntax $exception) {
104
            //Let's clarify exception location
105
            throw SyntaxException::fromTwig($exception, $this->loader);
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->wrapLoader());
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->wrapLoader());
173
        $engine->twig->setCache($engine->defineCache());
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 createTwig(array $extensions, array $options): \Twig_Environment
187
    {
188
        //Initiating Twig Environment
189
        $twig = new \Twig_Environment($this->wrapLoader(), $options);
190
        $twig->setCache($this->defineCache());
191
        $twig->setBaseTemplateClass(TwigView::class);
192
193
        foreach ($extensions as $extension) {
194
            //Each extension can be delivered thought container
195
            $twig->addExtension($this->container->get($extension));
196
        }
197
198
        return $twig;
199
    }
200
201
    /**
202
     * In most of cases twig will get view processors to be executed before twig itself, to run
203
     * such processors we need special wrapper at top of environment.
204
     *
205
     * @return LoaderInterface
206
     */
207 View Code Duplication
    private function wrapLoader(): 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...
208
    {
209
        $processors = [];
210
        foreach ($this->modifiers as $modifier) {
211
            if (is_object($modifier)) {
212
                $processors[] = $modifier;
213
            } else {
214
                $processors[] = $this->container->make($modifier);
215
            }
216
        }
217
218
        return new ContextLoader($this->environment, $this->loader, $processors);
219
    }
220
221
    /**
222
     * @return bool|TwigCache
223
     */
224
    private function defineCache()
225
    {
226
        if (!$this->environment->isCachable()) {
227
            return false;
228
        }
229
230
        return new TwigCache($this->files, $this->environment);
231
    }
232
}