206 lines
7.3 KiB
PHP
206 lines
7.3 KiB
PHP
<?php
|
|
/**
|
|
* This file is part of Pico. It's copyrighted by the contributors recorded
|
|
* in the version control history of the file, available from the following
|
|
* original location:
|
|
*
|
|
* <https://github.com/picocms/pico-deprecated/blob/master/plugins/PicoThemeApi2CompatPlugin.php>
|
|
*
|
|
* This file was created by splitting up an original file into multiple files,
|
|
* which in turn was previously part of the project's main repository. The
|
|
* version control history of these files apply accordingly, available from
|
|
* the following original locations:
|
|
*
|
|
* <https://github.com/picocms/pico-deprecated/blob/90ea3d5a9767f1511f165e051dd7ffb8f1b3f92e/PicoDeprecated.php>
|
|
* <https://github.com/picocms/Pico/blob/82a342ba445122182b898a2c1800f03c8d16f18c/plugins/00-PicoDeprecated.php>
|
|
*
|
|
* SPDX-License-Identifier: MIT
|
|
* License-Filename: LICENSE
|
|
*/
|
|
|
|
/**
|
|
* Maintains backward compatibility with themes using API version 2, written
|
|
* for Pico 2.0
|
|
*
|
|
* @author Daniel Rudolf
|
|
* @link http://picocms.org
|
|
* @license http://opensource.org/licenses/MIT The MIT License
|
|
* @version 2.1
|
|
*/
|
|
class PicoThemeApi2CompatPlugin extends AbstractPicoCompatPlugin
|
|
{
|
|
/**
|
|
* Manually configured Twig escape strategy
|
|
*
|
|
* @var mixed|null
|
|
*/
|
|
protected $twigEscapeStrategy;
|
|
|
|
/**
|
|
* Directory paths of plugins
|
|
*
|
|
* @var string[]
|
|
*/
|
|
protected $pluginPaths = array();
|
|
|
|
/**
|
|
* Sets PicoThemeApi2CompatPlugin::$twigEscapeStrategy
|
|
*
|
|
* @see PicoThemeApi2CompatPlugin::$twigEscapeStrategy
|
|
*
|
|
* @param array &$config array of config variables
|
|
*/
|
|
public function onConfigLoaded(array &$config)
|
|
{
|
|
if (isset($config['twig_config']['autoescape'])) {
|
|
$this->twigEscapeStrategy = $config['twig_config']['autoescape'];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Re-introduces the Twig variables prev_page, base_dir and theme_dir
|
|
*
|
|
* @param string &$templateName file name of the template
|
|
* @param array &$twigVariables template variables
|
|
*/
|
|
public function onPageRendering(&$templateName, array &$twigVariables)
|
|
{
|
|
$twigVariables['prev_page'] = &$twigVariables['previous_page'];
|
|
$twigVariables['base_dir'] = rtrim($this->getPico()->getRootDir(), '/');
|
|
$twigVariables['theme_dir'] = $this->getPico()->getThemesDir() . $this->getPico()->getTheme();
|
|
}
|
|
|
|
/**
|
|
* Registers PicoPluginApi2CompatPlugin::twigEscapeStrategy() as Twig's
|
|
* default escape strategy
|
|
*
|
|
* @see PicoPluginApi2CompatPlugin::twigEscapeStrategy()
|
|
*
|
|
* @param Twig_Environment &$twig Twig instance
|
|
*/
|
|
public function onTwigRegistered(Twig_Environment &$twig)
|
|
{
|
|
if ($twig->hasExtension('Twig_Extension_Escaper')) {
|
|
/** @var Twig_Extension_Escaper $escaperExtension */
|
|
$escaperExtension = $twig->getExtension('Twig_Extension_Escaper');
|
|
$escaperExtension->setDefaultStrategy(array($this, 'twigEscapeStrategy'));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns Twig's default escaping strategy for the given template
|
|
*
|
|
* This escape strategy takes a template name and decides whether Twig's
|
|
* global default escape strategy should be used, or escaping should be
|
|
* disabled. Escaping is disabled for themes using API v2 and below as well
|
|
* as for templates of plugins using API v2 and below. If a escape strategy
|
|
* has been configured manually, this method always returns this explicitly
|
|
* configured escape strategy.
|
|
*
|
|
* @param string $templateName template name
|
|
*
|
|
* @return string|false escape strategy for this template
|
|
*/
|
|
public function twigEscapeStrategy($templateName)
|
|
{
|
|
$twigConfig = $this->getPico()->getConfig('twig_config');
|
|
$escapeStrategy = $twigConfig['autoescape'];
|
|
|
|
if (($this->twigEscapeStrategy !== null) && ($escapeStrategy === $this->twigEscapeStrategy)) {
|
|
return $escapeStrategy;
|
|
}
|
|
|
|
if (!is_string($escapeStrategy) && ($escapeStrategy !== false)) {
|
|
$escapeStrategy = call_user_func($escapeStrategy, $templateName);
|
|
}
|
|
|
|
if ($escapeStrategy === false) {
|
|
return false;
|
|
}
|
|
|
|
/** @var Twig_SourceContextLoaderInterface $twigLoader */
|
|
$twigLoader = $this->getPico()->getTwig()->getLoader();
|
|
if (!$twigLoader instanceof Twig_SourceContextLoaderInterface) {
|
|
throw new RuntimeException(
|
|
"PicoDeprecated compat plugin '" . __CLASS__ . "' requires a 'Twig_SourceContextLoaderInterface' "
|
|
. "Twig loader, '" . get_class($twigLoader) . "' given"
|
|
);
|
|
}
|
|
|
|
try {
|
|
$templatePath = $twigLoader->getSourceContext($templateName)->getPath();
|
|
} catch (\Twig\Error\LoaderError $e) {
|
|
$templatePath = '';
|
|
}
|
|
|
|
if ($templatePath) {
|
|
$themePath = realpath($this->getPico()->getThemesDir() . $this->getPico()->getTheme()) . '/';
|
|
if (substr($templatePath, 0, strlen($themePath)) === $themePath) {
|
|
$themeApiVersion = $this->getPico()->getThemeApiVersion();
|
|
return ($themeApiVersion >= PicoDeprecated::API_VERSION_3) ? $escapeStrategy : false;
|
|
}
|
|
|
|
$plugin = $this->getPluginFromPath($templatePath);
|
|
if ($plugin) {
|
|
$pluginApiVersion = $this->getPicoDeprecated()->getPluginApiVersion($plugin);
|
|
return ($pluginApiVersion >= PicoDeprecated::API_VERSION_3) ? $escapeStrategy : false;
|
|
}
|
|
}
|
|
|
|
// unknown template path
|
|
// to preserve BC we must assume that the template uses an old API version
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Returns the matching plugin instance when the given path is within a
|
|
* plugin's base directory
|
|
*
|
|
* @param string $path file path to search for
|
|
*
|
|
* @return object|null either the matching plugin instance or NULL
|
|
*/
|
|
protected function getPluginFromPath($path)
|
|
{
|
|
$plugins = $this->getPico()->getPlugins();
|
|
foreach ($this->pluginPaths as $pluginName => $pluginPath) {
|
|
if ($pluginPath && (substr($path, 0, strlen($pluginPath)) === $pluginPath)) {
|
|
return $plugins[$pluginName];
|
|
}
|
|
}
|
|
|
|
$rootDir = realpath($this->getPico()->getRootDir()) . '/';
|
|
$vendorDir = realpath($this->getPico()->getVendorDir()) . '/';
|
|
$pluginsDir = realpath($this->getPico()->getPluginsDir()) . '/';
|
|
$themesDir = realpath($this->getPico()->getThemesDir()) . '/';
|
|
foreach ($plugins as $pluginName => $plugin) {
|
|
if (isset($this->pluginPaths[$pluginName])) {
|
|
continue;
|
|
}
|
|
|
|
$pluginReflector = new ReflectionObject($plugin);
|
|
|
|
$pluginPath = dirname($pluginReflector->getFileName() ?: '') . '/';
|
|
if (in_array($pluginPath, array('/', $rootDir, $vendorDir, $pluginsDir, $themesDir), true)) {
|
|
$pluginPath = '';
|
|
}
|
|
|
|
$this->pluginPaths[$pluginName] = $pluginPath;
|
|
|
|
if ($pluginPath && (substr($path, 0, strlen($pluginPath)) === $pluginPath)) {
|
|
return $plugins[$pluginName];
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
public function getApiVersion()
|
|
{
|
|
return PicoDeprecated::API_VERSION_3;
|
|
}
|
|
}
|