Merge pull request #5762 from gijsmartens/ticket/16243

[ticket/16243] Update template paths
This commit is contained in:
Marc Alexander 2021-08-24 13:17:03 +02:00 committed by GitHub
commit 44e3e4964b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 218 additions and 77 deletions

View file

@ -21,71 +21,59 @@ use phpbb\template\exception\user_object_not_available;
class twig extends \phpbb\template\base
{
/**
* Path of the cache directory for the template
*
* Cannot be changed during runtime.
*
* @var string
*/
* Path of the cache directory for the template
* Cannot be changed during runtime.
*
* @var string
*/
private $cachepath = '';
/**
* phpBB path helper
* @var \phpbb\path_helper
*/
/** @var \phpbb\path_helper */
protected $path_helper;
/**
* phpBB root path
* @var string
*/
/** @var string phpBB root path */
protected $phpbb_root_path;
/**
* PHP file extension
* @var string
*/
/** @var string php File extension */
protected $php_ext;
/**
* phpBB config instance
* @var \phpbb\config\config
*/
/** @var \phpbb\config\config */
protected $config;
/**
* Current user
* @var \phpbb\user
*/
/** @var \phpbb\user */
protected $user;
/**
* Extension manager.
*
* @var \phpbb\extension\manager
*/
/** @var \phpbb\extension\manager */
protected $extension_manager;
/**
* Twig Environment
*
* @var \Twig\Environment
*/
/** @var environment */
protected $twig;
/** @var loader */
protected $loader;
/**
* Constructor.
*
* @param \phpbb\path_helper $path_helper
* @param \phpbb\config\config $config
* @param \phpbb\template\context $context template context
* @param \phpbb\template\twig\environment $twig_environment
* @param string $cache_path
* @param \phpbb\user|null $user
* @param array|\ArrayAccess $extensions
* @param \phpbb\extension\manager $extension_manager extension manager, if null then template events will not be invoked
* @param \phpbb\path_helper $path_helper Path helper object
* @param \phpbb\config\config $config Config object
* @param \phpbb\template\context $context Template context
* @param environment $twig_environment Twig environment
* @param string $cache_path Template's cache directory path
* @param null|\phpbb\user $user User object
* @param array|\ArrayAccess $extensions Template extensions
* @param null|\phpbb\extension\manager $extension_manager If null then template events will not be invoked
*/
public function __construct(\phpbb\path_helper $path_helper, $config, \phpbb\template\context $context, \phpbb\template\twig\environment $twig_environment, $cache_path, \phpbb\user $user = null, $extensions = array(), \phpbb\extension\manager $extension_manager = null)
public function __construct(
\phpbb\path_helper $path_helper,
\phpbb\config\config $config,
\phpbb\template\context $context,
environment $twig_environment,
$cache_path,
\phpbb\user $user = null,
$extensions = [],
\phpbb\extension\manager $extension_manager = null
)
{
$this->path_helper = $path_helper;
$this->phpbb_root_path = $path_helper->get_phpbb_root_path();
@ -96,6 +84,7 @@ class twig extends \phpbb\template\base
$this->extension_manager = $extension_manager;
$this->cachepath = $cache_path;
$this->twig = $twig_environment;
$this->loader = $twig_environment->getLoader();
foreach ($extensions as $extension)
{
@ -105,7 +94,7 @@ class twig extends \phpbb\template\base
// Add admin namespace
if ($this->path_helper->get_adm_relative_path() !== null && is_dir($this->phpbb_root_path . $this->path_helper->get_adm_relative_path() . 'style/'))
{
$this->twig->getLoader()->setPaths($this->phpbb_root_path . $this->path_helper->get_adm_relative_path() . 'style/', 'admin');
$this->loader->setPaths($this->phpbb_root_path . $this->path_helper->get_adm_relative_path() . 'style/', 'admin');
}
}
@ -138,9 +127,9 @@ class twig extends \phpbb\template\base
throw new user_object_not_available();
}
$style_list = array(
$style_list = [
$this->user->style['style_path'],
);
];
if ($this->user->style['style_parent_id'])
{
@ -158,55 +147,61 @@ class twig extends \phpbb\template\base
* Default: array('styles') (phpBB's style directory)
* @return \phpbb\template\template $this
*/
public function set_style($style_directories = array('styles'))
public function set_style($style_directories = ['styles'])
{
if ($style_directories !== array('styles') && $this->twig->getLoader()->getPaths('core') === array())
if ($style_directories !== ['styles'] && $this->loader->getPaths('core') === [])
{
// We should set up the core styles path since not already setup
$this->set_style();
}
$names = $this->get_user_style();
$paths = [];
// Add 'all' folder to $names array
// It allows extensions to load a template file from 'all' folder,
// if a style doesn't include it.
$names = $this->get_user_style();
$names[] = 'all';
$paths = array();
foreach ($style_directories as $directory)
{
foreach ($names as $name)
{
$path = $this->phpbb_root_path . trim($directory, '/') . "/{$name}/";
$template_path = $path . 'template/';
$theme_path = $path . 'theme/';
$path = $this->phpbb_root_path . trim($directory, '/') . "/{$name}/";
$handle = @opendir($path);
$valid = false;
$is_valid_dir = false;
if (is_dir($template_path))
if ($handle)
{
$is_valid_dir = true;
$paths[] = $template_path;
}
if (is_dir($theme_path))
{
$is_valid_dir = true;
$paths[] = $theme_path;
while (($file = readdir($handle)) !== false)
{
$dir = $path . $file;
if ($file[0] !== '.' && is_dir($dir))
{
$paths[] = $dir;
$valid = true;
}
}
closedir($handle);
}
if ($is_valid_dir)
if ($valid)
{
// Add the base style directory as a safe directory
$this->twig->getLoader()->addSafeDirectory($path);
$this->loader->addSafeDirectory($path);
}
}
}
// If we're setting up the main phpBB styles directory and the core
// namespace isn't setup yet, we will set it up now
if ($style_directories === array('styles') && $this->twig->getLoader()->getPaths('core') === array())
if ($style_directories === ['styles'] && $this->loader->getPaths('core') === [])
{
// Set up the core style paths namespace
$this->twig->getLoader()->setPaths($paths, 'core');
$this->loader->setPaths($paths, 'core');
}
$this->set_custom_style($names, $paths);
@ -229,11 +224,11 @@ class twig extends \phpbb\template\base
*/
public function set_custom_style($names, $paths)
{
$paths = (is_string($paths)) ? array($paths) : $paths;
$names = (is_string($names)) ? array($names) : $names;
$paths = (is_string($paths)) ? [$paths] : $paths;
$names = (is_string($names)) ? [$names] : $names;
// Set as __main__ namespace
$this->twig->getLoader()->setPaths($paths);
$this->loader->setPaths($paths);
// Add all namespaces for all extensions
if ($this->extension_manager instanceof \phpbb\extension\manager)
@ -244,7 +239,7 @@ class twig extends \phpbb\template\base
{
// namespaces cannot contain /
$namespace = str_replace('/', '_', $ext_namespace);
$paths = array();
$paths = [];
foreach ($names as $template_dir)
{
@ -285,11 +280,11 @@ class twig extends \phpbb\template\base
if ($is_valid_dir)
{
// Add the base style directory as a safe directory
$this->twig->getLoader()->addSafeDirectory($ext_style_path);
$this->loader->addSafeDirectory($ext_style_path);
}
}
$this->twig->getLoader()->setPaths($paths, $namespace);
$this->loader->setPaths($paths, $namespace);
}
}
@ -345,10 +340,10 @@ class twig extends \phpbb\template\base
$vars = array_merge(
$context_vars['.'][0], // To get normal vars
array(
[
'definition' => new \phpbb\template\twig\definition(),
'loops' => $context_vars, // To get loops
)
]
);
if ($this->user instanceof \phpbb\user)
@ -373,6 +368,6 @@ class twig extends \phpbb\template\base
*/
public function get_source_file_for_handle($handle)
{
return $this->twig->getLoader()->getCacheKey($this->get_filename_from_handle($handle));
return $this->loader->getCacheKey($this->get_filename_from_handle($handle));
}
}

View file

@ -0,0 +1,146 @@
<?php
/**
*
* This file is part of the phpBB Forum Software package.
*
* @copyright (c) phpBB Limited <https://www.phpbb.com>
* @license GNU General Public License, version 2 (GPL-2.0)
*
* For full copyright and license information, please see
* the docs/CREDITS.txt file.
*
*/
namespace phpbb\tests\template;
use phpbb\filesystem\helper as filesystem_helper;
use phpbb\template\twig\twig;
class twig_test extends \phpbb_test_case
{
/** @var twig */
public $twig;
/**
* @var string
*/
private $template_path;
/**
* @var twig
*/
private $template;
/**
* @var \phpbb\user
*/
private $user;
/**
* @var \phpbb\language\language
*/
private $lang;
protected function setUp(): void
{
global $phpbb_root_path, $phpEx;
$config = new \phpbb\config\config([]);
$lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx);
$this->lang = $lang = new \phpbb\language\language($lang_loader);
$user = new \phpbb\user($lang, '\phpbb\datetime');
$this->user = $user;
$filesystem = new \phpbb\filesystem\filesystem();
$path_helper = new \phpbb\path_helper(
new \phpbb\symfony_request(
new \phpbb_mock_request()
),
$this->createMock('\phpbb\request\request'),
$phpbb_root_path,
$phpEx
);
$this->template_path = 'tests/template/templates';
$cache_path = $phpbb_root_path . 'cache/twig';
$context = new \phpbb\template\context();
$loader = new \phpbb\template\twig\loader('');
$twig = new \phpbb\template\twig\environment(
$config,
$filesystem,
$path_helper,
$cache_path,
null,
$loader,
new \phpbb\event\dispatcher(),
[
'cache' => false,
'debug' => false,
'auto_reload' => true,
'autoescape' => false,
]
);
$this->template = new \phpbb\template\twig\twig($path_helper, $config, $context, $twig, $cache_path, $this->user, array(new \phpbb\template\twig\extension($context, $twig, $this->user)));
$twig->setLexer(new \phpbb\template\twig\lexer($twig));
}
public function test_get_user_style_invalid_user()
{
// Add closure to override user method
$set_user_closure = function ($user) {
$this->user = $user;
};
$run_set_user_closure = $set_user_closure->bindTo($this->template, get_class($this->template));
$run_set_user_closure(null);
$this->expectException('\phpbb\template\exception\user_object_not_available');
$this->template->get_user_style();
$run_set_user_closure($this->user);
}
public function data_get_user_style(): array
{
return [
[['style_path' => 'prosilver', 'style_parent_id' => 0], ['prosilver']],
[['style_path' => 'prosilver_se', 'style_parent_id' => 5, 'style_parent_tree' => 'prosilver'], ['prosilver_se', 'prosilver']],
];
}
/**
* @dataProvider data_get_user_style
*/
public function test_get_user_style($user_style, $expected)
{
$this->user->style = $user_style;
$this->assertEquals($expected, $this->template->get_user_style());
}
public function test_set_style()
{
global $phpbb_root_path;
// User style is left empty on purpose to see template as valid directory
$tests_template_relative_path = '../tests/template';
$test_template_absolute_path = filesystem_helper::realpath($phpbb_root_path . trim($tests_template_relative_path, '/'));
// Get loader instance
$template_reflection = new \ReflectionObject($this->template);
$loader_reflection = $template_reflection->getProperty('loader');
$loader_reflection->setAccessible(true);
/** @var \phpbb\template\twig\loader $loader */
$loader = $loader_reflection->getValue($this->template);
// set_style() not called yet
$this->assertEmpty($loader->getSafeDirectories());
// set_style() to add default elements
$this->user->style = ['style_path' => '', 'style_parent_id' => 0];
$this->template->set_style();
$safe_directories = $loader->getSafeDirectories();
$this->assertFalse(in_array($test_template_absolute_path, $safe_directories));
$this->assertFalse(empty($safe_directories));
// set_style() with tests template folder
$this->template->set_style([$tests_template_relative_path]);
$this->assertTrue(in_array($test_template_absolute_path, $loader->getSafeDirectories()));
}
}