Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
91.38% covered (success)
91.38%
53 / 58
88.24% covered (warning)
88.24%
15 / 17
CRAP
0.00% covered (danger)
0.00%
0 / 1
environment
91.38% covered (success)
91.38%
53 / 58
88.24% covered (warning)
88.24%
15 / 17
30.58
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
14 / 14
100.00% covered (success)
100.00%
1 / 1
2
 get_phpbb_extensions
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
2
 get_phpbb_config
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 get_phpbb_root_path
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 get_filesystem
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 get_web_root_path
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 get_path_helper
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 get_assets_bag
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 get_phpbb_dispatcher
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getNamespaceLookUpOrder
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setNamespaceLookUpOrder
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 render
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 display
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 display_with_assets
100.00% covered (success)
100.00%
12 / 12
100.00% covered (success)
100.00%
1 / 1
4
 inject_assets
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 loadTemplate
75.00% covered (warning)
75.00%
6 / 8
0.00% covered (danger)
0.00%
0 / 1
5.39
 findTemplate
62.50% covered (warning)
62.50%
5 / 8
0.00% covered (danger)
0.00%
0 / 1
6.32
1<?php
2/**
3*
4* This file is part of the phpBB Forum Software package.
5*
6* @copyright (c) phpBB Limited <https://www.phpbb.com>
7* @license GNU General Public License, version 2 (GPL-2.0)
8*
9* For full copyright and license information, please see
10* the docs/CREDITS.txt file.
11*
12*/
13
14namespace phpbb\template\twig;
15
16use phpbb\config\config;
17use phpbb\event\dispatcher_interface;
18use phpbb\extension\manager;
19use phpbb\filesystem\filesystem;
20use phpbb\path_helper;
21use phpbb\template\assets_bag;
22use Twig\Loader\LoaderInterface;
23
24class environment extends \Twig\Environment
25{
26    /** @var config */
27    protected $phpbb_config;
28
29    /** @var filesystem */
30    protected $filesystem;
31
32    /** @var path_helper */
33    protected $phpbb_path_helper;
34
35    /** @var \Symfony\Component\DependencyInjection\ContainerInterface */
36    protected $container;
37
38    /** @var manager */
39    protected $extension_manager;
40
41    /** @var dispatcher_interface */
42    protected $phpbb_dispatcher;
43
44    /** @var string */
45    protected $phpbb_root_path;
46
47    /** @var string */
48    protected $web_root_path;
49
50    /** @var array **/
51    protected $namespace_look_up_order = array('__main__');
52
53    /** @var assets_bag */
54    protected $assets_bag;
55
56    /**
57    * Constructor
58    *
59    * @param assets_bag $assets_bag Assets bag
60    * @param config $phpbb_config The phpBB configuration
61    * @param filesystem $filesystem
62    * @param path_helper $path_helper phpBB path helper
63    * @param string $cache_path The path to the cache directory
64    * @param manager|null $extension_manager phpBB extension manager
65    * @param LoaderInterface|null $loader Twig loader interface
66    * @param dispatcher_interface|null    $phpbb_dispatcher    Event dispatcher object
67    * @param array $options Array of options to pass to Twig
68    */
69    public function __construct(assets_bag $assets_bag, config $phpbb_config, filesystem $filesystem, path_helper $path_helper, $cache_path, manager|null $extension_manager = null, LoaderInterface|null $loader = null, dispatcher_interface|null $phpbb_dispatcher = null, $options = array())
70    {
71        $this->phpbb_config = $phpbb_config;
72
73        $this->filesystem = $filesystem;
74        $this->phpbb_path_helper = $path_helper;
75        $this->extension_manager = $extension_manager;
76        $this->phpbb_dispatcher = $phpbb_dispatcher;
77
78        $this->phpbb_root_path = $this->phpbb_path_helper->get_phpbb_root_path();
79
80        $this->assets_bag = $assets_bag;
81
82        $options = array_merge(array(
83            'cache'            => (defined('IN_INSTALL')) ? false : $cache_path,
84            'debug'            => false,
85            'auto_reload'    => (bool) $this->phpbb_config['load_tplcompile'],
86            'autoescape'    => false,
87        ), $options);
88
89        parent::__construct($loader, $options);
90    }
91
92    /**
93    * Get the list of enabled phpBB extensions
94    *
95    * Used in EVENT node
96    *
97    * @return array
98    */
99    public function get_phpbb_extensions()
100    {
101        return ($this->extension_manager) ? $this->extension_manager->all_enabled() : array();
102    }
103
104    /**
105    * Get phpBB config
106    *
107    * @return config
108    */
109    public function get_phpbb_config()
110    {
111        return $this->phpbb_config;
112    }
113
114    /**
115     * Get the phpBB root path
116     *
117     * @return string
118     */
119    public function get_phpbb_root_path()
120    {
121        return $this->phpbb_root_path;
122    }
123
124    /**
125    * Get the filesystem object
126    *
127    * @return filesystem
128    */
129    public function get_filesystem()
130    {
131        return $this->filesystem;
132    }
133
134    /**
135    * Get the web root path
136    *
137    * @return string
138    */
139    public function get_web_root_path()
140    {
141        return $this->web_root_path ?? $this->web_root_path = $this->phpbb_path_helper->get_web_root_path();
142    }
143
144    /**
145    * Get the phpbb path helper object
146    *
147    * @return path_helper
148    */
149    public function get_path_helper()
150    {
151        return $this->phpbb_path_helper;
152    }
153
154    /**
155     * Gets the assets bag
156     *
157     * @return assets_bag
158     */
159    public function get_assets_bag()
160    {
161        return $this->assets_bag;
162    }
163
164    /**
165     * Gets the event dispatcher instance
166     *
167     * @return dispatcher_interface
168     */
169    public function get_phpbb_dispatcher()
170    {
171        return $this->phpbb_dispatcher;
172    }
173
174    /**
175    * Get the namespace look up order
176    *
177    * @return array
178    */
179    public function getNamespaceLookUpOrder()
180    {
181        return $this->namespace_look_up_order;
182    }
183
184    /**
185    * Set the namespace look up order to load templates from
186    *
187    * @param array $namespace
188    * @return \Twig\Environment
189    */
190    public function setNamespaceLookUpOrder($namespace)
191    {
192        $this->namespace_look_up_order = $namespace;
193
194        return $this;
195    }
196
197    /**
198     * {@inheritdoc}
199     */
200    public function render($name, array $context = []) : string
201    {
202        return $this->display_with_assets($name, $context);
203    }
204
205    /**
206     * {@inheritdoc}
207     */
208    public function display($name, array $context = []) : void
209    {
210        echo $this->display_with_assets($name, $context);
211    }
212
213    /**
214     * Get template with assets
215     */
216    private function display_with_assets($name, array $context = [])
217    {
218        $placeholder_salt = unique_id();
219
220        if (array_key_exists('definition', $context))
221        {
222            $context['definition']->set('SCRIPTS', '__SCRIPTS_' . $placeholder_salt . '__');
223            $context['definition']->set('STYLESHEETS', '__STYLESHEETS_' . $placeholder_salt . '__');
224        }
225
226        /**
227        * Allow changing the template output stream before rendering
228        *
229        * @event core.twig_environment_render_template_before
230        * @var    array    context        Array with template variables
231        * @var    string  name        The template name
232        * @since 3.2.1-RC1
233        */
234        if ($this->phpbb_dispatcher)
235        {
236            $vars = array('context', 'name');
237            extract($this->phpbb_dispatcher->trigger_event('core.twig_environment_render_template_before', compact($vars)));
238        }
239
240        $output = parent::render($name, $context);
241
242        /**
243        * Allow changing the template output stream after rendering
244        *
245        * @event core.twig_environment_render_template_after
246        * @var    array    context        Array with template variables
247        * @var    string  name        The template name
248        * @var    string    output        Rendered template output stream
249        * @since 3.2.1-RC1
250        */
251        if ($this->phpbb_dispatcher)
252        {
253            $vars = array('context', 'name', 'output');
254            extract($this->phpbb_dispatcher->trigger_event('core.twig_environment_render_template_after', compact($vars)));
255        }
256
257        return $this->inject_assets($output, $placeholder_salt);
258    }
259
260    /**
261     * Injects the assets (from INCLUDECSS/JS) in the output.
262     *
263     * @param string $output
264     *
265     * @return string
266     */
267    private function inject_assets($output, $placeholder_salt)
268    {
269        $output = str_replace('__STYLESHEETS_' . $placeholder_salt . '__', $this->assets_bag->get_stylesheets_content(), $output);
270        $output = str_replace('__SCRIPTS_' . $placeholder_salt . '__', $this->assets_bag->get_scripts_content(), $output);
271
272        return $output;
273    }
274
275    /**
276    * Loads a template by name.
277    *
278    * @param string  $cls   The template class associated with the given template name
279    * @param string  $name  The template name
280    * @param integer|null $index The index if it is an embedded template
281    * @return \Twig\Template A template instance representing the given template name
282    * @throws \Twig\Error\LoaderError
283    */
284    public function loadTemplate(string $cls, string $name, int|null $index = null) : \Twig\Template
285    {
286        if (strpos($name, '@') === false)
287        {
288            foreach ($this->getNamespaceLookUpOrder() as $namespace)
289            {
290                try
291                {
292                    if ($namespace === '__main__')
293                    {
294                        return parent::loadTemplate($cls, $name, $index);
295                    }
296
297                    return parent::loadTemplate($this->getTemplateClass('@' . $namespace . '/' . $name), '@' . $namespace . '/' . $name, $index);
298                }
299                catch (\Twig\Error\LoaderError $e)
300                {
301                }
302            }
303
304            // We were unable to load any templates
305            throw $e;
306        }
307        else
308        {
309            return parent::loadTemplate($cls, $name, $index);
310        }
311    }
312
313    /**
314    * Finds a template by name.
315    *
316    * @param string  $name  The template name
317    * @return string
318    * @throws \Twig\Error\LoaderError
319    */
320    public function findTemplate($name)
321    {
322        if (strpos($name, '@') === false)
323        {
324            foreach ($this->getNamespaceLookUpOrder() as $namespace)
325            {
326                try
327                {
328                    if ($namespace === '__main__')
329                    {
330                        return parent::getLoader()->getCacheKey($name);
331                    }
332
333                    return parent::getLoader()->getCacheKey('@' . $namespace . '/' . $name);
334                }
335                catch (\Twig\Error\LoaderError $e)
336                {
337                }
338            }
339
340            // We were unable to load any templates
341            throw $e;
342        }
343        else
344        {
345            return parent::getLoader()->getCacheKey($name);
346        }
347    }
348}