From 4090c88e7299b2f65373f870e182bd75d20a7202 Mon Sep 17 00:00:00 2001 From: Corey Taylor Date: Fri, 27 Mar 2020 09:06:40 -0500 Subject: [PATCH] Replaced configuration events with methods in TwigView. Added Extension to extension class names. --- phpstan.neon | 4 +- psalm-baseline.xml | 11 +- src/Event/ConstructEvent.php | 57 ----- src/Event/EnvironmentConfigEvent.php | 63 ----- src/Event/ExtensionsListener.php | 132 ---------- src/Event/LoaderEvent.php | 62 ----- src/Event/ProfileEvent.php | 44 ---- src/Event/ProfilerListener.php | 60 ----- src/Event/TokenParsersListener.php | 58 ----- src/Plugin.php | 5 - .../{Arrays.php => ArraysExtension.php} | 6 +- .../{Basic.php => BasicExtension.php} | 6 +- ...alDangerous.php => ConfigureExtension.php} | 19 +- .../Extension/{I18n.php => I18nExtension.php} | 6 +- .../{Inflector.php => InflectorExtension.php} | 6 +- .../{Number.php => NumberExtension.php} | 6 +- .../{Profiler.php => ProfilerExtension.php} | 6 +- .../{Strings.php => StringsExtension.php} | 6 +- .../Extension/{Time.php => TimeExtension.php} | 6 +- .../{Utils.php => UtilsExtension.php} | 6 +- src/Twig/Extension/View.php | 78 ------ .../TokenParser/{Cell.php => CellParser.php} | 4 +- .../{Element.php => ElementParser.php} | 4 +- src/View/TwigView.php | 235 +++++++++++------- tests/TestCase/ConstructEventTest.php | 37 --- tests/TestCase/EnvironmentConfigEventTest.php | 60 ----- tests/TestCase/ExtensionsListenerTest.php | 106 -------- tests/TestCase/LoaderEventTest.php | 54 ---- tests/TestCase/ProfilerListenerTest.php | 48 ---- tests/TestCase/TokenParsersListenerTest.php | 49 ---- .../{BasicTest.php => BasicExtensionTest.php} | 6 +- ...ousTest.php => ConfigureExtensionTest.php} | 6 +- ...ringsTest.php => StringsExtensionTest.php} | 6 +- tests/TestCase/View/TwigViewTest.php | 102 +------- tests/test_app/templates/cakephp.php | 1 - 35 files changed, 203 insertions(+), 1162 deletions(-) delete mode 100644 src/Event/ConstructEvent.php delete mode 100644 src/Event/EnvironmentConfigEvent.php delete mode 100644 src/Event/ExtensionsListener.php delete mode 100644 src/Event/LoaderEvent.php delete mode 100644 src/Event/ProfileEvent.php delete mode 100644 src/Event/ProfilerListener.php delete mode 100644 src/Event/TokenParsersListener.php rename src/Twig/Extension/{Arrays.php => ArraysExtension.php} (93%) rename src/Twig/Extension/{Basic.php => BasicExtension.php} (93%) rename src/Twig/Extension/{PotentialDangerous.php => ConfigureExtension.php} (77%) rename src/Twig/Extension/{I18n.php => I18nExtension.php} (92%) rename src/Twig/Extension/{Inflector.php => InflectorExtension.php} (93%) rename src/Twig/Extension/{Number.php => NumberExtension.php} (94%) rename src/Twig/Extension/{Profiler.php => ProfilerExtension.php} (90%) rename src/Twig/Extension/{Strings.php => StringsExtension.php} (95%) rename src/Twig/Extension/{Time.php => TimeExtension.php} (92%) rename src/Twig/Extension/{Utils.php => UtilsExtension.php} (93%) delete mode 100644 src/Twig/Extension/View.php rename src/Twig/TokenParser/{Cell.php => CellParser.php} (96%) rename src/Twig/TokenParser/{Element.php => ElementParser.php} (95%) delete mode 100644 tests/TestCase/ConstructEventTest.php delete mode 100644 tests/TestCase/EnvironmentConfigEventTest.php delete mode 100644 tests/TestCase/ExtensionsListenerTest.php delete mode 100644 tests/TestCase/LoaderEventTest.php delete mode 100644 tests/TestCase/ProfilerListenerTest.php delete mode 100644 tests/TestCase/TokenParsersListenerTest.php rename tests/TestCase/Twig/Extension/{BasicTest.php => BasicExtensionTest.php} (91%) rename tests/TestCase/Twig/Extension/{PotentialDangerousTest.php => ConfigureExtensionTest.php} (86%) rename tests/TestCase/Twig/Extension/{StringsTest.php => StringsExtensionTest.php} (97%) delete mode 100644 tests/test_app/templates/cakephp.php diff --git a/phpstan.neon b/phpstan.neon index f0a216c..887191a 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -8,12 +8,12 @@ parameters: - message: "#^Parameter \\#2 \\$callable of class Twig\\\\TwigFilter constructor expects \\(callable\\(\\)\\: mixed\\)\\|null, 'debug' given\\.$#" count: 1 - path: src/Twig/Extension/Basic.php + path: src/Twig/Extension/BasicExtension.php - message: "#^Constant ROOT not found\\.$#" count: 2 - path: src/Twig/Extension/Profiler.php + path: src/Twig/Extension/ProfilerExtension.php - message: "#^Constant CACHE not found\\.$#" diff --git a/psalm-baseline.xml b/psalm-baseline.xml index 44732ac..cd1e9a2 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -1,20 +1,13 @@ - - - Shell - parent::__construct($io, $locator) - parent::getOptionParser() - - - + parseExpression parseExpression parseExpression - + parseExpression parseExpression diff --git a/src/Event/ConstructEvent.php b/src/Event/ConstructEvent.php deleted file mode 100644 index 202882b..0000000 --- a/src/Event/ConstructEvent.php +++ /dev/null @@ -1,57 +0,0 @@ - $twigView, - 'twig' => $twig, - ]); - } - - /** - * @return \Cake\TwigView\View\TwigView - */ - public function getTwigView(): TwigView - { - return $this->getData()['twigView']; - } - - /** - * @return \Twig\Environment - */ - public function getTwig(): Environment - { - return $this->getData()['twig']; - } -} diff --git a/src/Event/EnvironmentConfigEvent.php b/src/Event/EnvironmentConfigEvent.php deleted file mode 100644 index 7b33723..0000000 --- a/src/Event/EnvironmentConfigEvent.php +++ /dev/null @@ -1,63 +0,0 @@ -setConfig($config); - - return $event; - } - - /** - * @return array - */ - public function getConfig(): array - { - return $this->config; - } - - /** - * @param array $config Config array - * @return $this - */ - public function setConfig(array $config) - { - /** @psalm-suppress PossiblyNullPropertyAssignmentValue */ - $this->config = array_replace_recursive($this->config, $config); - - return $this; - } -} diff --git a/src/Event/ExtensionsListener.php b/src/Event/ExtensionsListener.php deleted file mode 100644 index b8d8608..0000000 --- a/src/Event/ExtensionsListener.php +++ /dev/null @@ -1,132 +0,0 @@ - 'construct', - ]; - } - - /** - * Event handler. - * - * @param \Cake\TwigView\Event\ConstructEvent $event Event. - * @return void - */ - public function construct(ConstructEvent $event): void - { - if ($event->getTwig()->hasExtension(StringLoaderExtension::class)) { - return; - } - - // Twig core extensions - $event->getTwig()->addExtension(new StringLoaderExtension()); - $event->getTwig()->addExtension(new DebugExtension()); - - // CakePHP bridging extensions - $event->getTwig()->addExtension(new Extension\I18n()); - $event->getTwig()->addExtension(new Extension\Time()); - $event->getTwig()->addExtension(new Extension\Basic()); - $event->getTwig()->addExtension(new Extension\Number()); - $event->getTwig()->addExtension(new Extension\Utils()); - $event->getTwig()->addExtension(new Extension\Arrays()); - $event->getTwig()->addExtension(new Extension\Strings()); - $event->getTwig()->addExtension(new Extension\Inflector()); - - if ( - !Configure::check('TwigView.flags.potentialDangerous') || - ( - Configure::check('TwigView.flags.potentialDangerous') && - Configure::read('TwigView.flags.potentialDangerous') === true - ) - ) { - $event->getTwig()->addExtension(new Extension\PotentialDangerous()); - } - - // Markdown extension - if ( - Configure::check('TwigView.markdown.engine') && - Configure::read('TwigView.markdown.engine') instanceof MarkdownInterface - ) { - $engine = Configure::read('TwigView.markdown.engine'); - $event->getTwig()->addExtension(new MarkdownExtension()); - - $event->getTwig()->addRuntimeLoader(new class ($engine) implements RuntimeLoaderInterface { - /** - * @var \Twig\Extra\Markdown\MarkdownInterface - */ - private $engine; - - /** - * @param \Twig\Extra\Markdown\MarkdownInterface $engine MarkdownInterface instance - */ - public function __construct(MarkdownInterface $engine) - { - $this->engine = $engine; - } - - /** - * @param string $class FQCN - * @return object|null - */ - public function load($class) - { - if ($class === MarkdownRuntime::class) { - return new MarkdownRuntime($this->engine); - } - - return null; - } - }); - } - - // jasny/twig-extensions - $event->getTwig()->addExtension(new DateExtension()); - $event->getTwig()->addExtension(new PcreExtension()); - $event->getTwig()->addExtension(new TextExtension()); - $event->getTwig()->addExtension(new ArrayExtension()); - // @codingStandardsIgnoreEnd - } -} diff --git a/src/Event/LoaderEvent.php b/src/Event/LoaderEvent.php deleted file mode 100644 index 7953981..0000000 --- a/src/Event/LoaderEvent.php +++ /dev/null @@ -1,62 +0,0 @@ - $loader, - ]); - } - - /** - * @return \Twig\Loader\LoaderInterface - */ - public function getLoader(): LoaderInterface - { - return $this->getSubject(); - } - - /** - * @return \Twig\Loader\LoaderInterface - */ - public function getResultLoader(): LoaderInterface - { - if ($this->result instanceof LoaderInterface) { - return $this->result; - } - - if (is_array($this->result) && $this->result['loader'] instanceof LoaderInterface) { - return $this->result['loader']; - } - - return $this->getLoader(); - } -} diff --git a/src/Event/ProfileEvent.php b/src/Event/ProfileEvent.php deleted file mode 100644 index 99143f1..0000000 --- a/src/Event/ProfileEvent.php +++ /dev/null @@ -1,44 +0,0 @@ -getSubject(); - } -} diff --git a/src/Event/ProfilerListener.php b/src/Event/ProfilerListener.php deleted file mode 100644 index 85886b7..0000000 --- a/src/Event/ProfilerListener.php +++ /dev/null @@ -1,60 +0,0 @@ - 'construct', - ]; - } - - /** - * Event handler. - * - * @param \Cake\TwigView\Event\ConstructEvent $event Event. - * @return void - */ - public function construct(ConstructEvent $event): void - { - if ($event->getTwig()->hasExtension(Extension\Profiler::class)) { - return; - } - - $profile = new Profile(); - $event->getTwig()->addExtension(new Extension\Profiler($profile)); - - EventManager::instance()->dispatch(ProfileEvent::create($profile)); - } -} diff --git a/src/Event/TokenParsersListener.php b/src/Event/TokenParsersListener.php deleted file mode 100644 index 599c089..0000000 --- a/src/Event/TokenParsersListener.php +++ /dev/null @@ -1,58 +0,0 @@ - 'construct', - ]; - } - - /** - * Event handler. - * - * @param \Cake\TwigView\Event\ConstructEvent $event Event. - * @return void - */ - public function construct(ConstructEvent $event): void - { - // CakePHP specific tags - try { - $event->getTwig()->addTokenParser(new TokenParser\Cell()); - $event->getTwig()->addTokenParser(new TokenParser\Element()); - } catch (LogicException $d) { - // Nothing to do as token parser already added. - } - } -} diff --git a/src/Plugin.php b/src/Plugin.php index 76cb12f..f39113b 100644 --- a/src/Plugin.php +++ b/src/Plugin.php @@ -23,7 +23,6 @@ use Cake\Core\Configure; use Cake\Core\Plugin as CorePlugin; use Cake\Core\PluginApplicationInterface; -use Cake\Event\EventManager; use Cake\TwigView\Command\CompileCommand; /** @@ -43,9 +42,6 @@ class Plugin extends BasePlugin */ public function bootstrap(PluginApplicationInterface $app): void { - EventManager::instance()->on(new Event\ExtensionsListener()); - EventManager::instance()->on(new Event\TokenParsersListener()); - if (Configure::read('debug') && CorePlugin::isLoaded('DebugKit')) { Configure::write('DebugKit.panels', array_merge( (array)Configure::read('DebugKit.panels'), @@ -53,7 +49,6 @@ public function bootstrap(PluginApplicationInterface $app): void 'Cake/TwigView.Twig', ] )); - EventManager::instance()->on(new Event\ProfilerListener()); } } diff --git a/src/Twig/Extension/Arrays.php b/src/Twig/Extension/ArraysExtension.php similarity index 93% rename from src/Twig/Extension/Arrays.php rename to src/Twig/Extension/ArraysExtension.php index 83eea05..29d2de4 100644 --- a/src/Twig/Extension/Arrays.php +++ b/src/Twig/Extension/ArraysExtension.php @@ -22,11 +22,11 @@ use Twig\TwigFunction; /** - * Class Arrays. + * Class ArraysExtension. * * @internal */ -final class Arrays extends AbstractExtension +final class ArraysExtension extends AbstractExtension { /** * Get declared functions. @@ -55,6 +55,6 @@ public function getFunctions(): array */ public function getName(): string { - return 'array'; + return 'twigview-array'; } } diff --git a/src/Twig/Extension/Basic.php b/src/Twig/Extension/BasicExtension.php similarity index 93% rename from src/Twig/Extension/Basic.php rename to src/Twig/Extension/BasicExtension.php index d188d89..5ac6172 100644 --- a/src/Twig/Extension/Basic.php +++ b/src/Twig/Extension/BasicExtension.php @@ -22,11 +22,11 @@ use Twig\TwigFilter; /** - * Class Basic. + * Class BasicExtension. * * @internal */ -final class Basic extends AbstractExtension +final class BasicExtension extends AbstractExtension { /** * Get declared filters. @@ -56,6 +56,6 @@ public function getFilters(): array */ public function getName(): string { - return 'basic'; + return 'twigview-basic'; } } diff --git a/src/Twig/Extension/PotentialDangerous.php b/src/Twig/Extension/ConfigureExtension.php similarity index 77% rename from src/Twig/Extension/PotentialDangerous.php rename to src/Twig/Extension/ConfigureExtension.php index 8904a61..75e8da9 100644 --- a/src/Twig/Extension/PotentialDangerous.php +++ b/src/Twig/Extension/ConfigureExtension.php @@ -19,28 +19,15 @@ namespace Cake\TwigView\Twig\Extension; use Twig\Extension\AbstractExtension; -use Twig\TwigFilter; use Twig\TwigFunction; /** - * Class Basic. + * Class ConfigureExtension. * * @internal */ -class PotentialDangerous extends AbstractExtension +class ConfigureExtension extends AbstractExtension { - /** - * Get declared filters. - * - * @return \Twig\TwigFilter[] - */ - public function getFilters() - { - return [ - new TwigFilter('env', 'env'), - ]; - } - /** * Get declared functions. * @@ -60,6 +47,6 @@ public function getFunctions() */ public function getName() { - return 'potential_dangerous'; + return 'twigview-configure'; } } diff --git a/src/Twig/Extension/I18n.php b/src/Twig/Extension/I18nExtension.php similarity index 92% rename from src/Twig/Extension/I18n.php rename to src/Twig/Extension/I18nExtension.php index a32b3d9..997207c 100644 --- a/src/Twig/Extension/I18n.php +++ b/src/Twig/Extension/I18nExtension.php @@ -22,11 +22,11 @@ use Twig\TwigFunction; /** - * Class I18n. + * Class I18nExtension. * * @internal */ -final class I18n extends AbstractExtension +final class I18nExtension extends AbstractExtension { /** * Get declared functions. @@ -51,6 +51,6 @@ public function getFunctions(): array */ public function getName(): string { - return 'i18n'; + return 'twigview-i18n'; } } diff --git a/src/Twig/Extension/Inflector.php b/src/Twig/Extension/InflectorExtension.php similarity index 93% rename from src/Twig/Extension/Inflector.php rename to src/Twig/Extension/InflectorExtension.php index a405a1e..308c0d2 100644 --- a/src/Twig/Extension/Inflector.php +++ b/src/Twig/Extension/InflectorExtension.php @@ -22,11 +22,11 @@ use Twig\TwigFilter; /** - * Class Inflector. + * Class InflectorExtension. * * @internal */ -final class Inflector extends AbstractExtension +final class InflectorExtension extends AbstractExtension { /** * Get filters for this extension. @@ -56,6 +56,6 @@ public function getFilters(): array */ public function getName(): string { - return 'inflector'; + return 'twigview-inflector'; } } diff --git a/src/Twig/Extension/Number.php b/src/Twig/Extension/NumberExtension.php similarity index 94% rename from src/Twig/Extension/Number.php rename to src/Twig/Extension/NumberExtension.php index 3286807..1e2a3a1 100644 --- a/src/Twig/Extension/Number.php +++ b/src/Twig/Extension/NumberExtension.php @@ -23,11 +23,11 @@ use Twig\TwigFunction; /** - * Class Number. + * Class NumberExtension. * * @internal */ -final class Number extends AbstractExtension +final class NumberExtension extends AbstractExtension { /** * Get declared functions. @@ -66,6 +66,6 @@ public function getFunctions(): array */ public function getName(): string { - return 'number'; + return 'twigview-number'; } } diff --git a/src/Twig/Extension/Profiler.php b/src/Twig/Extension/ProfilerExtension.php similarity index 90% rename from src/Twig/Extension/Profiler.php rename to src/Twig/Extension/ProfilerExtension.php index b612e62..df85785 100644 --- a/src/Twig/Extension/Profiler.php +++ b/src/Twig/Extension/ProfilerExtension.php @@ -19,15 +19,15 @@ namespace Cake\TwigView\Twig\Extension; use DebugKit\DebugTimer; -use Twig\Extension\ProfilerExtension; +use Twig\Extension\ProfilerExtension as TwigProfilerExtension; use Twig\Profiler\Profile; /** - * Class Basic. + * Class ProfilerExtension. * * @internal */ -final class Profiler extends ProfilerExtension +final class ProfilerExtension extends TwigProfilerExtension { /** * Enter $profile. diff --git a/src/Twig/Extension/Strings.php b/src/Twig/Extension/StringsExtension.php similarity index 95% rename from src/Twig/Extension/Strings.php rename to src/Twig/Extension/StringsExtension.php index f10afe5..a5b3e6e 100644 --- a/src/Twig/Extension/Strings.php +++ b/src/Twig/Extension/StringsExtension.php @@ -23,11 +23,11 @@ use Twig\TwigFunction; /** - * Class Strings. + * Class StringsExtension. * * @internal */ -final class Strings extends AbstractExtension +final class StringsExtension extends AbstractExtension { /** * Get declared filters. @@ -79,6 +79,6 @@ public function getFunctions(): array */ public function getName(): string { - return 'string'; + return 'twigview-string'; } } diff --git a/src/Twig/Extension/Time.php b/src/Twig/Extension/TimeExtension.php similarity index 92% rename from src/Twig/Extension/Time.php rename to src/Twig/Extension/TimeExtension.php index bc7ee79..71b450b 100644 --- a/src/Twig/Extension/Time.php +++ b/src/Twig/Extension/TimeExtension.php @@ -23,11 +23,11 @@ use Twig\TwigFunction; /** - * Class Time. + * Class TimeExtension. * * @internal */ -final class Time extends AbstractExtension +final class TimeExtension extends AbstractExtension { /** * Get declared functions. @@ -51,6 +51,6 @@ public function getFunctions(): array */ public function getName(): string { - return 'time'; + return 'twigview-time'; } } diff --git a/src/Twig/Extension/Utils.php b/src/Twig/Extension/UtilsExtension.php similarity index 93% rename from src/Twig/Extension/Utils.php rename to src/Twig/Extension/UtilsExtension.php index 6a59e15..1cce520 100644 --- a/src/Twig/Extension/Utils.php +++ b/src/Twig/Extension/UtilsExtension.php @@ -22,11 +22,11 @@ use Twig\TwigFilter; /** - * Class Utils. + * Class UtilsExtension. * * @internal */ -final class Utils extends AbstractExtension +final class UtilsExtension extends AbstractExtension { /** * Get declared filters. @@ -55,6 +55,6 @@ public function getFilters(): array */ public function getName(): string { - return 'utils'; + return 'twigview-utils'; } } diff --git a/src/Twig/Extension/View.php b/src/Twig/Extension/View.php deleted file mode 100644 index b4a110f..0000000 --- a/src/Twig/Extension/View.php +++ /dev/null @@ -1,78 +0,0 @@ -view = $view; - } - - /** - * Get declared functions. - * - * @return \Twig\TwigFunction[] - */ - public function getFunctions(): array - { - return [ - new TwigFunction('elementExists', function ($name) { - return $this->view->elementExists($name); - }), - new TwigFunction('getVars', function () { - return $this->view->getVars(); - }), - new TwigFunction('get', function ($var, $default = null) { - return $this->view->get($var, $default); - }), - ]; - } - - /** - * Get extension name. - * - * @return string - */ - public function getName(): string - { - return 'view'; - } -} diff --git a/src/Twig/TokenParser/Cell.php b/src/Twig/TokenParser/CellParser.php similarity index 96% rename from src/Twig/TokenParser/Cell.php rename to src/Twig/TokenParser/CellParser.php index 5c17c44..a69ed03 100644 --- a/src/Twig/TokenParser/Cell.php +++ b/src/Twig/TokenParser/CellParser.php @@ -24,11 +24,11 @@ use Twig\TokenParser\IncludeTokenParser; /** - * Class Element. + * Class CellParser. * * @internal */ -final class Cell extends IncludeTokenParser +final class CellParser extends IncludeTokenParser { /** * Parse token. diff --git a/src/Twig/TokenParser/Element.php b/src/Twig/TokenParser/ElementParser.php similarity index 95% rename from src/Twig/TokenParser/Element.php rename to src/Twig/TokenParser/ElementParser.php index 4be04b1..287900f 100644 --- a/src/Twig/TokenParser/Element.php +++ b/src/Twig/TokenParser/ElementParser.php @@ -24,11 +24,11 @@ use Twig\TokenParser\IncludeTokenParser; /** - * Class Element. + * Class ElementParser. * * @internal */ -final class Element extends IncludeTokenParser +final class ElementParser extends IncludeTokenParser { /** * Parse token. diff --git a/src/View/TwigView.php b/src/View/TwigView.php index 178594b..47f59cb 100644 --- a/src/View/TwigView.php +++ b/src/View/TwigView.php @@ -19,14 +19,36 @@ namespace Cake\TwigView\View; use Cake\Core\Configure; -use Cake\TwigView\Event\ConstructEvent; -use Cake\TwigView\Event\EnvironmentConfigEvent; -use Cake\TwigView\Event\LoaderEvent; +use Cake\Core\Plugin; +use Cake\TwigView\Twig\Extension\ArraysExtension; +use Cake\TwigView\Twig\Extension\BasicExtension; +use Cake\TwigView\Twig\Extension\ConfigureExtension; +use Cake\TwigView\Twig\Extension\I18nExtension; +use Cake\TwigView\Twig\Extension\InflectorExtension; +use Cake\TwigView\Twig\Extension\NumberExtension; +use Cake\TwigView\Twig\Extension\ProfilerExtension; +use Cake\TwigView\Twig\Extension\StringsExtension; +use Cake\TwigView\Twig\Extension\TimeExtension; +use Cake\TwigView\Twig\Extension\UtilsExtension; use Cake\TwigView\Twig\Loader; +use Cake\TwigView\Twig\TokenParser\CellParser; +use Cake\TwigView\Twig\TokenParser\ElementParser; +use Cake\View\Exception\MissingLayoutException; +use Cake\View\Exception\MissingTemplateException; use Cake\View\View; -use Exception; +use Jasny\Twig\ArrayExtension as JasnyArraysExtension; +use Jasny\Twig\DateExtension; +use Jasny\Twig\PcreExtension; +use Jasny\Twig\TextExtension; use Twig\Environment; +use Twig\Extension\DebugExtension; +use Twig\Extension\StringLoaderExtension; +use Twig\Extra\Markdown\MarkdownExtension; +use Twig\Extra\Markdown\MarkdownInterface; +use Twig\Extra\Markdown\MarkdownRuntime; use Twig\Loader\LoaderInterface; +use Twig\Profiler\Profile; +use Twig\RuntimeLoader\RuntimeLoaderInterface; /** * Class TwigView. @@ -38,27 +60,29 @@ class TwigView extends View public const ENV_CONFIG = 'TwigView.environment'; /** - * Extension to use. - * - * @var string + * @inheritDoc */ - protected $_ext = self::EXT; + protected $_ext = '.twig'; /** + * List of extensions searched when loading templates. + * * @var string[] */ protected $extensions = [ - self::EXT, - '.php', + '.twig', ]; /** - * Twig instance. - * * @var \Twig\Environment */ protected $twig; + /** + * @var \Twig\Profiler\Profile + */ + protected $profile; + /** * Return empty string when View instance is cast to string. * @@ -76,38 +100,49 @@ public function __toString(): string */ public function initialize(): void { - $this->twig = new Environment($this->getLoader(), $this->resolveConfig()); - - $this->getEventManager()->dispatch(ConstructEvent::create($this, $this->twig)); + parent::initialize(); - $this->_ext = self::EXT; + $this->twig = new Environment($this->createLoader(), $this->createEnvironmentConfig()); + $this->initializeTokenParser(); + $this->initializeExtensions(); + } - parent::initialize(); + /** + * Get Twig Environment instance. + * + * @return \Twig\Environment + */ + public function getTwig(): Environment + { + return $this->twig; } /** - * @param string $extension Extension. - * @return void + * Gets Twig Profile if profiler enabled. + * + * @return \Twig\Profiler\Profile */ - public function unshiftExtension(string $extension): void + public function getProfile(): Profile { - array_unshift($this->extensions, $extension); + return $this->profile; } /** - * Get twig environment instance. + * Creates the Twig LoaderInterface instance. * - * @return \Twig\Environment + * @return \Twig\Loader\LoaderInterface */ - public function getTwig(): Environment + protected function createLoader(): LoaderInterface { - return $this->twig; + return new Loader(); } /** + * Creates the Twig Environment configuration. + * * @return array */ - protected function resolveConfig(): array + protected function createEnvironmentConfig(): array { $debug = Configure::read('debug', false); @@ -122,110 +157,144 @@ protected function resolveConfig(): array $config['cache'] = CACHE . 'twigView' . DS; } - $configEvent = EnvironmentConfigEvent::create($config); - $this->getEventManager()->dispatch($configEvent); - - return $configEvent->getConfig(); + return $config; } /** - * Create the template loader. + * Adds custom Twig token parsers. * - * @return \Twig\Loader\LoaderInterface + * @return void */ - protected function getLoader(): LoaderInterface + protected function initializeTokenParser(): void { - $event = LoaderEvent::create(new Loader()); - $this->getEventManager()->dispatch($event); - - return $event->getResultLoader(); + $this->twig->addTokenParser(new CellParser()); + $this->twig->addTokenParser(new ElementParser()); } + // phpcs:disable CakePHP.Commenting.FunctionComment.InvalidReturnVoid + /** - * Render the template. + * Adds Twig extensions. * - * @param string $viewFile Template file. - * @param array $data Data that can be used by the template. - * @throws \Exception - * @return string + * @return void */ - protected function _render(string $viewFile, array $data = []): string + protected function initializeExtensions(): void { - if (empty($data)) { - $data = $this->viewVars; + // Twig core extensions + $this->twig->addExtension(new StringLoaderExtension()); + $this->twig->addExtension(new DebugExtension()); + + // CakePHP bridging extensions + $this->twig->addExtension(new ArraysExtension()); + $this->twig->addExtension(new BasicExtension()); + $this->twig->addExtension(new ConfigureExtension()); + $this->twig->addExtension(new I18nExtension()); + $this->twig->addExtension(new InflectorExtension()); + $this->twig->addExtension(new NumberExtension()); + $this->twig->addExtension(new StringsExtension()); + $this->twig->addExtension(new TimeExtension()); + $this->twig->addExtension(new UtilsExtension()); + + if (Configure::read('debug') && Plugin::isLoaded('DebugKit')) { + $this->profile = new Profile(); + $this->twig->addExtension(new ProfilerExtension($this->profile)); } - if (substr($viewFile, -3) === 'php') { - $out = parent::_render($viewFile, $data); - } else { - $data = array_merge( - $data, - iterator_to_array($this->helpers()->getIterator()), - [ - '_view' => $this, - ] - ); + // Markdown extension + if (Configure::read('TwigView.markdown.engine') instanceof MarkdownInterface) { + $engine = Configure::read('TwigView.markdown.engine'); + $this->twig->addExtension(new MarkdownExtension()); + + $this->twig->addRuntimeLoader(new class ($engine) implements RuntimeLoaderInterface { + /** + * @var \Twig\Extra\Markdown\MarkdownInterface + */ + private $engine; + + /** + * @param \Twig\Extra\Markdown\MarkdownInterface $engine MarkdownInterface instance + */ + public function __construct(MarkdownInterface $engine) + { + $this->engine = $engine; + } - try { - $out = $this->getTwig()->load($viewFile)->render($data); - } catch (Exception $e) { - $previous = $e->getPrevious(); - - if ($previous !== null && $previous instanceof Exception) { - throw $previous; - } else { - throw $e; + /** + * @param string $class FQCN + * @return object|null + */ + public function load($class) + { + if ($class === MarkdownRuntime::class) { + return new MarkdownRuntime($this->engine); + } + + return null; } - } + }); } - return $out; + // jasny/twig-extensions + $this->twig->addExtension(new DateExtension()); + $this->twig->addExtension(new JasnyArraysExtension()); + $this->twig->addExtension(new PcreExtension()); + $this->twig->addExtension(new TextExtension()); } + // phpcs:enable + /** - * @param string|null $name Template name. - * @throws \Exception - * @return string + * @inheritDoc + */ + protected function _render(string $templateFile, array $data = []): string + { + $data = array_merge( + empty($data) ? $this->viewVars : $data, + iterator_to_array($this->helpers()->getIterator()), + [ + '_view' => $this, + ] + ); + + return $this->getTwig()->load($templateFile)->render($data); + } + + /** + * @inheritDoc */ protected function _getTemplateFileName(?string $name = null): string { - $rethrow = new Exception('You\'re not supposed to get here'); foreach ($this->extensions as $extension) { $this->_ext = $extension; try { return parent::_getTemplateFileName($name); - } catch (Exception $exception) { - $rethrow = $exception; + } catch (MissingTemplateException $exception) { + $missingException = $exception; } } - throw $rethrow; + throw $missingException ?? new MissingTemplateException($name ?? $this->getTemplate()); } /** - * @param string|null $name Layout name. - * @throws \Exception - * @return string + * @inheritDoc */ protected function _getLayoutFileName(?string $name = null): string { - $rethrow = new Exception('You\'re not supposed to get here'); foreach ($this->extensions as $extension) { $this->_ext = $extension; try { return parent::_getLayoutFileName($name); - } catch (Exception $exception) { - $rethrow = $exception; + } catch (MissingLayoutException $exception) { + $missingException = $exception; } } - throw $rethrow; + throw $missingException ?? new MissingLayoutException($name ?? $this->getLayout()); } /** - * @param string $name Element name. - * @param bool $pluginCheck Whether to check within plugin. - * @return string|false + * @inheritDoc */ protected function _getElementFileName(string $name, bool $pluginCheck = true) { diff --git a/tests/TestCase/ConstructEventTest.php b/tests/TestCase/ConstructEventTest.php deleted file mode 100644 index 082e620..0000000 --- a/tests/TestCase/ConstructEventTest.php +++ /dev/null @@ -1,37 +0,0 @@ -prophesize(TwigView::class)->reveal(); - $twigEnvironment = $this->prophesize(Environment::class)->reveal(); - $event = ConstructEvent::create($twigView, $twigEnvironment); - - $this->assertEquals($twigView, $event->getTwigView()); - $this->assertEquals($twigEnvironment, $event->getTwig()); - } -} diff --git a/tests/TestCase/EnvironmentConfigEventTest.php b/tests/TestCase/EnvironmentConfigEventTest.php deleted file mode 100644 index 2e911aa..0000000 --- a/tests/TestCase/EnvironmentConfigEventTest.php +++ /dev/null @@ -1,60 +0,0 @@ - 'bar', - ]; - $event = EnvironmentConfigEvent::create($config); - $this->assertEquals($config, $event->getConfig()); - } - - public function testSetConfig() - { - $event = EnvironmentConfigEvent::create([ - 'foo' => 'bar', - 'beer' => 'crate', - 'baz' => [ - 'oof' => 'rab', - 'foo' => 'bar', - ], - ]); - $event->setConfig([ - 'foo' => 'rab', - 'baz' => [ - 'oof' => 'beer', - ], - ]); - $this->assertEquals([ - 'foo' => 'rab', - 'beer' => 'crate', - 'baz' => [ - 'oof' => 'beer', - 'foo' => 'bar', - ], - ], $event->getConfig()); - } -} diff --git a/tests/TestCase/ExtensionsListenerTest.php b/tests/TestCase/ExtensionsListenerTest.php deleted file mode 100644 index 2387c6c..0000000 --- a/tests/TestCase/ExtensionsListenerTest.php +++ /dev/null @@ -1,106 +0,0 @@ -implementedEvents(); - $this->assertIsArray($eventsList); - $this->assertSame(1, count($eventsList)); - } - - public function testConstruct() - { - $twig = $this->prophesize(Environment::class); - $twig->hasExtension(StringLoaderExtension::class)->shouldBeCalled(); - $twig->addExtension(Argument::type(AbstractExtension::class))->shouldBeCalled(); - - $twigView = new TwigView(); - (new ExtensionsListener())->construct(ConstructEvent::create($twigView, $twig->reveal())); - } - - public function testConstructMarkdownEngine() - { - Configure::write( - 'TwigView.markdown.engine', - $this->prophesize(MarkdownInterface::class)->reveal() - ); - - $twig = $this->prophesize(Environment::class); - $twig->hasExtension(StringLoaderExtension::class)->shouldBeCalled(); - $twig->addExtension(Argument::type(AbstractExtension::class))->shouldBeCalled(); - $twig->addExtension(Argument::type(MarkdownExtension::class))->shouldBeCalled(); - $twig->addRuntimeLoader(Argument::type('object'))->shouldBeCalled(); - - $twigView = new TwigView(); - (new ExtensionsListener())->construct(ConstructEvent::create($twigView, $twig->reveal())); - } - - public function testConstructNoMarkdownEngine() - { - $twig = $this->prophesize(Environment::class); - $twig->hasExtension(StringLoaderExtension::class)->shouldBeCalled(); - $twig->addExtension(Argument::type(AbstractExtension::class))->shouldBeCalled(); - $twig->addExtension(Argument::type(MarkdownExtension::class))->shouldNotBeCalled(); - - $twigView = new TwigView(); - (new ExtensionsListener())->construct(ConstructEvent::create($twigView, $twig->reveal())); - } - - public function testConstructDebug() - { - Configure::write('debug', true); - - $twig = $this->prophesize(Environment::class); - $twig->hasExtension(StringLoaderExtension::class)->shouldBeCalled(); - $twig->addExtension(Argument::type(AbstractExtension::class))->shouldBeCalled(); - - $twigView = new TwigView(); - (new ExtensionsListener())->construct(ConstructEvent::create($twigView, $twig->reveal())); - } - - public function testConstructDebugFalse() - { - Configure::write('debug', false); - - $twig = $this->prophesize(Environment::class); - $twig->hasExtension(StringLoaderExtension::class)->shouldBeCalled(); - $twig->addExtension(Argument::type(AbstractExtension::class))->shouldBeCalled(); - - $twigView = new TwigView(); - (new ExtensionsListener())->construct(ConstructEvent::create($twigView, $twig->reveal())); - } -} diff --git a/tests/TestCase/LoaderEventTest.php b/tests/TestCase/LoaderEventTest.php deleted file mode 100644 index 34dfcf6..0000000 --- a/tests/TestCase/LoaderEventTest.php +++ /dev/null @@ -1,54 +0,0 @@ -prophesize(LoaderInterface::class)->reveal(); - $event = LoaderEvent::create($loader); - $event->setResult([ - 'loader' => $loader2, - ]); - $this->assertEquals($loader2, $event->getResultLoader()); - } - - public function testResultLoader() - { - $loader = new Loader(); - $loader2 = $this->prophesize(LoaderInterface::class)->reveal(); - $event = LoaderEvent::create($loader); - $event->setResult($loader2); - $this->assertEquals($loader2, $event->getResultLoader()); - } - - public function testLoader() - { - $loader = new Loader(); - $event = LoaderEvent::create($loader); - $this->assertEquals($loader, $event->getResultLoader()); - } -} diff --git a/tests/TestCase/ProfilerListenerTest.php b/tests/TestCase/ProfilerListenerTest.php deleted file mode 100644 index 8fe2dbc..0000000 --- a/tests/TestCase/ProfilerListenerTest.php +++ /dev/null @@ -1,48 +0,0 @@ -implementedEvents(); - $this->assertIsArray($eventsList); - $this->assertSame(1, count($eventsList)); - } - - public function testConstruct() - { - $twig = $this->prophesize(Environment::class); - $twig->hasExtension(Profiler::class)->shouldBeCalled()->willReturn(true); - - $twigView = new TwigView(); - (new ProfilerListener())->construct(ConstructEvent::create($twigView, $twig->reveal())); - } -} diff --git a/tests/TestCase/TokenParsersListenerTest.php b/tests/TestCase/TokenParsersListenerTest.php deleted file mode 100644 index c9008e9..0000000 --- a/tests/TestCase/TokenParsersListenerTest.php +++ /dev/null @@ -1,49 +0,0 @@ -implementedEvents(); - $this->assertIsArray($eventsList); - $this->assertSame(1, count($eventsList)); - } - - public function testConstruct() - { - $twig = $this->prophesize(Environment::class); - $twig->addTokenParser(Argument::type(IncludeTokenParser::class))->shouldBeCalled(); - - $twigView = new TwigView(); - (new TokenParsersListener())->construct(ConstructEvent::create($twigView, $twig->reveal())); - } -} diff --git a/tests/TestCase/Twig/Extension/BasicTest.php b/tests/TestCase/Twig/Extension/BasicExtensionTest.php similarity index 91% rename from tests/TestCase/Twig/Extension/BasicTest.php rename to tests/TestCase/Twig/Extension/BasicExtensionTest.php index cc70a35..bd870fe 100644 --- a/tests/TestCase/Twig/Extension/BasicTest.php +++ b/tests/TestCase/Twig/Extension/BasicExtensionTest.php @@ -18,13 +18,13 @@ namespace Cake\TwigView\Test\TestCase\Twig\Extension; -use Cake\TwigView\Twig\Extension\Basic; +use Cake\TwigView\Twig\Extension\BasicExtension; -final class BasicTest extends AbstractExtensionTest +final class BasicExtensionTest extends AbstractExtensionTest { public function setUp(): void { - $this->extension = new Basic(); + $this->extension = new BasicExtension(); parent::setUp(); } diff --git a/tests/TestCase/Twig/Extension/PotentialDangerousTest.php b/tests/TestCase/Twig/Extension/ConfigureExtensionTest.php similarity index 86% rename from tests/TestCase/Twig/Extension/PotentialDangerousTest.php rename to tests/TestCase/Twig/Extension/ConfigureExtensionTest.php index aa6783b..f605e2e 100644 --- a/tests/TestCase/Twig/Extension/PotentialDangerousTest.php +++ b/tests/TestCase/Twig/Extension/ConfigureExtensionTest.php @@ -18,13 +18,13 @@ namespace Cake\TwigView\Test\TestCase\Twig\Extension; -use Cake\TwigView\Twig\Extension\PotentialDangerous; +use Cake\TwigView\Twig\Extension\ConfigureExtension; -final class PotentialDangerousTest extends AbstractExtensionTest +final class ConfigureExtensionTest extends AbstractExtensionTest { public function setUp(): void { - $this->extension = new PotentialDangerous(); + $this->extension = new ConfigureExtension(); parent::setUp(); } diff --git a/tests/TestCase/Twig/Extension/StringsTest.php b/tests/TestCase/Twig/Extension/StringsExtensionTest.php similarity index 97% rename from tests/TestCase/Twig/Extension/StringsTest.php rename to tests/TestCase/Twig/Extension/StringsExtensionTest.php index 5c74051..2d62cbc 100644 --- a/tests/TestCase/Twig/Extension/StringsTest.php +++ b/tests/TestCase/Twig/Extension/StringsExtensionTest.php @@ -18,13 +18,13 @@ namespace Cake\TwigView\Test\TestCase\Twig\Extension; -use Cake\TwigView\Twig\Extension\Strings; +use Cake\TwigView\Twig\Extension\StringsExtension; -final class StringsTest extends AbstractExtensionTest +final class StringsExtensionTest extends AbstractExtensionTest { public function setUp(): void { - $this->extension = new Strings(); + $this->extension = new StringsExtension(); parent::setUp(); } diff --git a/tests/TestCase/View/TwigViewTest.php b/tests/TestCase/View/TwigViewTest.php index 4dd0fc5..408935a 100644 --- a/tests/TestCase/View/TwigViewTest.php +++ b/tests/TestCase/View/TwigViewTest.php @@ -18,15 +18,9 @@ namespace Cake\TwigView\Test\TestCase; -use Cake\Core\Configure; -use Cake\Event\EventManager; use Cake\TestSuite\TestCase; -use Cake\TwigView\Event\ConstructEvent; -use Cake\TwigView\Event\EnvironmentConfigEvent; -use Cake\TwigView\View\TwigView; -use TestApp\Exception\MissingSomethingException; use TestApp\View\AppView; -use Twig\Environment; +use Twig\Error\RuntimeError; use Twig\Error\SyntaxError; /** @@ -34,73 +28,13 @@ */ class TwigViewTest extends TestCase { - public function testInheritance() - { - $this->assertInstanceOf('Cake\View\View', new TwigView()); - } - - public function testConstruct() - { - $this->_hibernateListeners(ConstructEvent::EVENT); - - $callbackFired = false; - $eventCallback = function ($event) use (&$callbackFired) { - self::assertInstanceof(Environment::class, $event->getSubject()->getTwig()); - $callbackFired = true; - }; - EventManager::instance()->on(ConstructEvent::EVENT, $eventCallback); - - new TwigView(); - - EventManager::instance()->off(ConstructEvent::EVENT, $eventCallback); - $this->_wakeupListeners(ConstructEvent::EVENT); - - $this->assertTrue($callbackFired); - } - - public function testConstructConfig() - { - Configure::write(TwigView::ENV_CONFIG, [ - 'true' => true, - ]); - - $this->_hibernateListeners(EnvironmentConfigEvent::EVENT); - - $callbackFired = false; - $that = $this; - $eventCallback = function ($event) use ($that, &$callbackFired) { - $that->assertIsArray($event->getConfig()); - $that->assertTrue($event->getConfig()['true']); - - $callbackFired = true; - }; - EventManager::instance()->on(EnvironmentConfigEvent::EVENT, $eventCallback); - - new TwigView(); - - EventManager::instance()->off(EnvironmentConfigEvent::EVENT, $eventCallback); - $this->_wakeupListeners(EnvironmentConfigEvent::EVENT); - - $this->assertTrue($callbackFired); - } - - public function test_renderPhp() - { - $output = 'foo:bar with a beer'; - $filename = 'cakephp'; - - $view = new TwigView(); - $renderedView = $view->render($filename); - - self::assertSame($output, $renderedView); - } - /** - * Tests that a twig file that throws a custom exception correctly renders the thrown exception and not a Twig one. + * Tests a twig file that throws internal exception throw a Twig exception with message. */ public function test_renderTwigCustomException() { - $this->expectException(MissingSomethingException::class); + $this->expectException(RuntimeError::class); + $this->expectExceptionMessage('Something is missing'); $view = new AppView(); $view->render('exception', false); @@ -143,32 +77,4 @@ protected static function getProperty($name) return $property; } - - protected function _hibernateListeners($eventKey) - { - $this->__preservedEventListeners[$eventKey] = EventManager::instance()->listeners($eventKey); - - foreach ($this->__preservedEventListeners[$eventKey] as $eventListener) { - EventManager::instance()->off($eventListener['callable'], $eventKey); - } - } - - protected function _wakeupListeners($eventKey) - { - if (isset($this->__preservedEventListeners[$eventKey])) { - return; - } - - foreach ($this->__preservedEventListeners[$eventKey] as $eventListener) { - EventManager::instance()->on( - $eventListener['callable'], - $eventKey, - [ - 'passParams' => $eventListener['passParams'], - ] - ); - } - - $this->__preservedEventListeners = []; - } } diff --git a/tests/test_app/templates/cakephp.php b/tests/test_app/templates/cakephp.php deleted file mode 100644 index def1132..0000000 --- a/tests/test_app/templates/cakephp.php +++ /dev/null @@ -1 +0,0 @@ -foo:bar with a beer \ No newline at end of file