Update to Symfony YAML 5.0 and Twig 3.0

Pico now requires PHP 7.2.5+
This commit is contained in:
Daniel Rudolf 2020-04-10 23:11:53 +02:00
parent b1a58b9300
commit 85d7573020
No known key found for this signature in database
GPG key ID: A061F02CD8DE4538
6 changed files with 47 additions and 35 deletions

View file

@ -31,9 +31,9 @@
"source": "https://github.com/picocms/Pico" "source": "https://github.com/picocms/Pico"
}, },
"require": { "require": {
"php": ">=7.0.8", "php": ">=7.2.5",
"twig/twig": "^2.12", "twig/twig": "^3.0",
"symfony/yaml" : "^3.4", "symfony/yaml" : "^5.0",
"erusev/parsedown": "1.7.4", "erusev/parsedown": "1.7.4",
"erusev/parsedown-extra": "0.8.1" "erusev/parsedown-extra": "0.8.1"
}, },

View file

@ -27,7 +27,7 @@ twig_config: # Twig template engine config
## ##
# Content # Content
# #
date_format: %D %T # Pico's default date format; date_format: "%D %T" # Pico's default date format;
# See https://php.net/manual/en/function.strftime.php for more info # See https://php.net/manual/en/function.strftime.php for more info
pages_order_by_meta: author # Sort pages by meta value "author" (set "pages_order_by" to "meta") pages_order_by_meta: author # Sort pages by meta value "author" (set "pages_order_by" to "meta")
pages_order_by: alpha # Change how Pico sorts pages ("alpha" for alphabetical order, "date", or "meta") pages_order_by: alpha # Change how Pico sorts pages ("alpha" for alphabetical order, "date", or "meta")

View file

@ -1,5 +1,5 @@
--- ---
Logo: %theme_url%/img/pico-white.svg Logo: "%theme_url%/img/pico-white.svg"
Tagline: Making the web easy. Tagline: Making the web easy.
Social: Social:
- title: Visit us on GitHub - title: Visit us on GitHub

View file

@ -11,8 +11,8 @@
*/ */
// check PHP platform requirements // check PHP platform requirements
if (PHP_VERSION_ID < 70008) { if (PHP_VERSION_ID < 70205) {
die('Pico requires PHP 7.0.8 or above to run'); die('Pico requires PHP 7.2.5 or above to run');
} }
if (!extension_loaded('dom')) { if (!extension_loaded('dom')) {
die("Pico requires the PHP extension 'dom' to run"); die("Pico requires the PHP extension 'dom' to run");

View file

@ -18,6 +18,13 @@
namespace picocms\Pico; namespace picocms\Pico;
use Symfony\Component\Yaml\Parser as YamlParser;
use Twig\Environment as TwigEnvironment;
use Twig\Extension\DebugExtension as TwigDebugExtension;
use Twig\Loader\FilesystemLoader as TwigFilesystemLoader;
use Twig\Markup as TwigMarkup;
use Twig\TwigFilter;
/** /**
* Pico * Pico
* *
@ -229,7 +236,7 @@ class Pico
* Symfony YAML instance used for meta header parsing * Symfony YAML instance used for meta header parsing
* *
* @see Pico::getYamlParser() * @see Pico::getYamlParser()
* @var \Symfony\Component\Yaml\Parser|null * @var YamlParser|null
*/ */
protected $yamlParser; protected $yamlParser;
@ -309,7 +316,7 @@ class Pico
* Twig instance used for template parsing * Twig instance used for template parsing
* *
* @see Pico::getTwig() * @see Pico::getTwig()
* @var \Twig_Environment|null * @var TwigEnvironment|null
*/ */
protected $twig; protected $twig;
@ -1438,12 +1445,12 @@ class Pico
* This method triggers the `onYamlParserRegistered` event when the Symfony * This method triggers the `onYamlParserRegistered` event when the Symfony
* YAML parser wasn't initiated yet. * YAML parser wasn't initiated yet.
* *
* @return \Symfony\Component\Yaml\Parser Symfony YAML parser * @return YamlParser Symfony YAML parser
*/ */
public function getYamlParser() public function getYamlParser()
{ {
if ($this->yamlParser === null) { if ($this->yamlParser === null) {
$this->yamlParser = new \Symfony\Component\Yaml\Parser(); $this->yamlParser = new YamlParser();
$this->triggerEvent('onYamlParserRegistered', [ &$this->yamlParser ]); $this->triggerEvent('onYamlParserRegistered', [ &$this->yamlParser ]);
} }
@ -2080,19 +2087,19 @@ class Pico
* @see http://twig.sensiolabs.org/ Twig website * @see http://twig.sensiolabs.org/ Twig website
* @see https://github.com/twigphp/Twig Twig on GitHub * @see https://github.com/twigphp/Twig Twig on GitHub
* *
* @return \Twig_Environment|null Twig template engine * @return TwigEnvironment|null Twig template engine
*/ */
public function getTwig() public function getTwig()
{ {
if ($this->twig === null) { if ($this->twig === null) {
$twigConfig = $this->getConfig('twig_config'); $twigConfig = $this->getConfig('twig_config');
$twigLoader = new \Twig_Loader_Filesystem($this->getThemesDir() . $this->getTheme()); $twigLoader = new TwigFilesystemLoader($this->getThemesDir() . $this->getTheme());
$this->twig = new \Twig_Environment($twigLoader, $twigConfig); $this->twig = new TwigEnvironment($twigLoader, $twigConfig);
$this->twig->addExtension(new TwigExtension($this)); $this->twig->addExtension(new TwigExtension($this));
if (!empty($twigConfig['debug'])) { if (!empty($twigConfig['debug'])) {
$this->twig->addExtension(new \Twig_Extension_Debug()); $this->twig->addExtension(new TwigDebugExtension());
} }
// register content filter // register content filter
@ -2100,7 +2107,7 @@ class Pico
// this is the reason why we can't register this filter as part of PicoTwigExtension // this is the reason why we can't register this filter as part of PicoTwigExtension
$pico = $this; $pico = $this;
$pages = &$this->pages; $pages = &$this->pages;
$this->twig->addFilter(new \Twig_SimpleFilter( $this->twig->addFilter(new TwigFilter(
'content', 'content',
function ($page) use ($pico, &$pages) { function ($page) use ($pico, &$pages) {
if (isset($pages[$page])) { if (isset($pages[$page])) {
@ -2141,7 +2148,7 @@ class Pico
'theme_url' => $this->getConfig('themes_url') . $this->getTheme(), 'theme_url' => $this->getConfig('themes_url') . $this->getTheme(),
'site_title' => $this->getConfig('site_title'), 'site_title' => $this->getConfig('site_title'),
'meta' => $this->meta, 'meta' => $this->meta,
'content' => new \Twig_Markup($this->content, 'UTF-8'), 'content' => new TwigMarkup($this->content, 'UTF-8'),
'pages' => $this->pages, 'pages' => $this->pages,
'previous_page' => $this->previousPage, 'previous_page' => $this->previousPage,
'current_page' => $this->currentPage, 'current_page' => $this->currentPage,

View file

@ -12,6 +12,11 @@
namespace picocms\Pico; namespace picocms\Pico;
use Twig\Error\RuntimeError as TwigRuntimeError;
use Twig\Extension\AbstractExtension as AbstractTwigExtension;
use Twig\TwigFilter;
use Twig\TwigFunction;
/** /**
* Pico's Twig extension to implement additional filters * Pico's Twig extension to implement additional filters
* *
@ -20,7 +25,7 @@ namespace picocms\Pico;
* @license http://opensource.org/licenses/MIT The MIT License * @license http://opensource.org/licenses/MIT The MIT License
* @version 3.0 * @version 3.0
*/ */
class TwigExtension extends \Twig_Extension class TwigExtension extends AbstractTwigExtension
{ {
/** /**
* Current instance of Pico * Current instance of Pico
@ -69,20 +74,20 @@ class TwigExtension extends \Twig_Extension
* *
* @see Twig_ExtensionInterface::getFilters() * @see Twig_ExtensionInterface::getFilters()
* *
* @return \Twig_SimpleFilter[] array of Pico's Twig filters * @return TwigFilter[] array of Pico's Twig filters
*/ */
public function getFilters() public function getFilters()
{ {
return [ return [
'markdown' => new \Twig_SimpleFilter( 'markdown' => new TwigFilter(
'markdown', 'markdown',
[ $this, 'markdownFilter' ], [ $this, 'markdownFilter' ],
[ 'is_safe' => [ 'html' ] ] [ 'is_safe' => [ 'html' ] ]
), ),
'map' => new \Twig_SimpleFilter('map', [ $this, 'mapFilter' ]), 'map' => new TwigFilter('map', [ $this, 'mapFilter' ]),
'sort_by' => new \Twig_SimpleFilter('sort_by', [ $this, 'sortByFilter' ]), 'sort_by' => new TwigFilter('sort_by', [ $this, 'sortByFilter' ]),
'link' => new \Twig_SimpleFilter('link', [ $this->pico, 'getPageUrl' ]), 'link' => new TwigFilter('link', [ $this->pico, 'getPageUrl' ]),
'url' => new \Twig_SimpleFilter('url', [ $this->pico, 'substituteUrl' ]), 'url' => new TwigFilter('url', [ $this->pico, 'substituteUrl' ]),
]; ];
} }
@ -91,14 +96,14 @@ class TwigExtension extends \Twig_Extension
* *
* @see Twig_ExtensionInterface::getFunctions() * @see Twig_ExtensionInterface::getFunctions()
* *
* @return \Twig_SimpleFunction[] array of Pico's Twig functions * @return TwigFunction[] array of Pico's Twig functions
*/ */
public function getFunctions() public function getFunctions()
{ {
return [ return [
'url_param' => new \Twig_SimpleFunction('url_param', [ $this, 'urlParamFunction' ]), 'url_param' => new TwigFunction('url_param', [ $this, 'urlParamFunction' ]),
'form_param' => new \Twig_SimpleFunction('form_param', [ $this, 'formParamFunction' ]), 'form_param' => new TwigFunction('form_param', [ $this, 'formParamFunction' ]),
'pages' => new \Twig_SimpleFunction('pages', [ $this, 'pagesFunction' ]), 'pages' => new TwigFunction('pages', [ $this, 'pagesFunction' ]),
]; ];
} }
@ -138,12 +143,12 @@ class TwigExtension extends \Twig_Extension
* *
* @return array mapped values * @return array mapped values
* *
* @throws \Twig_Error_Runtime * @throws TwigRuntimeError
*/ */
public function mapFilter($var, $mapKeyPath) public function mapFilter($var, $mapKeyPath)
{ {
if (!is_array($var) && (!is_object($var) || !($var instanceof \Traversable))) { if (!is_array($var) && (!is_object($var) || !($var instanceof \Traversable))) {
throw new \Twig_Error_Runtime(sprintf( throw new TwigRuntimeError(sprintf(
'The map filter only works with arrays or "Traversable", got "%s"', 'The map filter only works with arrays or "Traversable", got "%s"',
is_object($var) ? get_class($var) : gettype($var) is_object($var) ? get_class($var) : gettype($var)
)); ));
@ -180,20 +185,20 @@ class TwigExtension extends \Twig_Extension
* *
* @return array sorted array * @return array sorted array
* *
* @throws \Twig_Error_Runtime * @throws TwigRuntimeError
*/ */
public function sortByFilter($var, $sortKeyPath, $fallback = 'bottom') public function sortByFilter($var, $sortKeyPath, $fallback = 'bottom')
{ {
if (is_object($var) && ($var instanceof \Traversable)) { if (is_object($var) && ($var instanceof \Traversable)) {
$var = iterator_to_array($var, true); $var = iterator_to_array($var, true);
} elseif (!is_array($var)) { } elseif (!is_array($var)) {
throw new \Twig_Error_Runtime(sprintf( throw new TwigRuntimeError(sprintf(
'The sort_by filter only works with arrays or "Traversable", got "%s"', 'The sort_by filter only works with arrays or "Traversable", got "%s"',
is_object($var) ? get_class($var) : gettype($var) is_object($var) ? get_class($var) : gettype($var)
)); ));
} }
if (($fallback !== 'top') && ($fallback !== 'bottom') && ($fallback !== 'keep') && ($fallback !== "remove")) { if (($fallback !== 'top') && ($fallback !== 'bottom') && ($fallback !== 'keep') && ($fallback !== "remove")) {
throw new \Twig_Error_Runtime( throw new TwigRuntimeError(
'The sort_by filter only supports the "top", "bottom", "keep" and "remove" fallbacks' 'The sort_by filter only supports the "top", "bottom", "keep" and "remove" fallbacks'
); );
} }
@ -423,7 +428,7 @@ class TwigExtension extends \Twig_Extension
* *
* @return array[] the data of the matched pages * @return array[] the data of the matched pages
* *
* @throws \Twig_Error_Runtime * @throws TwigRuntimeError
*/ */
public function pagesFunction($start = '', $depth = 0, $depthOffset = 0, $offset = 1) public function pagesFunction($start = '', $depth = 0, $depthOffset = 0, $offset = 1)
{ {
@ -445,7 +450,7 @@ class TwigExtension extends \Twig_Extension
$depthOffset = $depthOffset + $offset; $depthOffset = $depthOffset + $offset;
if (($depth !== null) && ($depth < 0)) { if (($depth !== null) && ($depth < 0)) {
throw new \Twig_Error_Runtime('The pages function doesn\'t support negative depths'); throw new TwigRuntimeError('The pages function doesn\'t support negative depths');
} }
$pageTree = $this->getPico()->getPageTree(); $pageTree = $this->getPico()->getPageTree();