diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..e64345c --- /dev/null +++ b/.gitattributes @@ -0,0 +1,7 @@ +.github export-ignore +tests export-ignore +.gitattributes export-ignore +.gitignore export-ignore +.php_cs.dist export-ignore +.travis.yml export-ignore +phpunit.xml.dist export-ignore diff --git a/.php_cs.dist b/.php_cs.dist new file mode 100644 index 0000000..c219e98 --- /dev/null +++ b/.php_cs.dist @@ -0,0 +1,112 @@ +fixer = $fixer; + $this->pathRegex = $pathRegex; + } + + public function isCandidate(Tokens $tokens) : bool + { + return $this->fixer->isCandidate($tokens); + } + + public function isRisky() : bool + { + return $this->fixer->isRisky(); + } + + public function fix(\SplFileInfo $file, Tokens $tokens) : void + { + $this->fixer->fix($file, $tokens); + } + + public function getName() : string + { + return (new \ReflectionClass($this))->getShortName().'/'.$this->fixer->getName(); + } + + public function getPriority() : int + { + return $this->fixer->getPriority(); + } + + public function supports(\SplFileInfo $file) : bool + { + if (1 !== preg_match($this->pathRegex, $file->getRealPath())) { + return false; + } + + return $this->fixer->supports($file); + } + + public function configure(array $configuration = null) + { + if ($this->fixer instanceof ConfigurableFixerInterface) { + $this->fixer->configure($configuration); + } + } +}; + +$header = << + +For the full copyright and license information, please view the LICENSE +file that was distributed with this source code. +EOF; + +return Config::create() + ->setUsingCache(false) + ->setRiskyAllowed(true) + ->registerCustomFixers([ + new FilterableFixer(new NativeConstantInvocationFixer(), '/\bsrc\b/'), + new FilterableFixer(new NativeFunctionInvocationFixer(), '/\bsrc\b/'), + ]) + ->setRules([ + '@Symfony' => true, + '@Symfony:risky' => true, + 'array_syntax' => ['syntax' => 'short'], + 'binary_operator_spaces' => ['operators' => ['=' => null, '=>' => null]], + 'declare_strict_types' => true, + 'native_constant_invocation' => false, + 'native_function_invocation' => false, + 'FilterableFixer/native_constant_invocation' => true, + 'FilterableFixer/native_function_invocation' => true, + 'no_useless_else' => true, + 'no_useless_return' => true, + 'ordered_imports' => [ + 'sort_algorithm' => 'alpha', + 'imports_order' => ['class', 'function', 'const'], + ], + 'phpdoc_align' => false, + 'phpdoc_order' => true, + 'phpdoc_to_comment' => false, + 'phpdoc_separation' => false, // do not separate @param and @psalm-param + 'return_type_declaration' => ['space_before' => 'one'], + 'strict_comparison' => true, + 'header_comment' => [ + 'comment_type' => 'PHPDoc', + 'header' => $header, + 'location' => 'after_open', + 'separate' => 'both', + ], + ]) +; diff --git a/.travis.yml b/.travis.yml index 2d158b5..1d693fb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,10 +1,9 @@ language: php php: - - 7.0 - - 7.1 - 7.2 - 7.3 + - 7.4 install: - travis_retry composer install diff --git a/README.md b/README.md index 9f38924..76a9488 100644 --- a/README.md +++ b/README.md @@ -1,27 +1,27 @@ -Deferred Twig Extension +Twig Deferred Extension ======================= [![Build Status](https://travis-ci.org/rybakit/twig-deferred-extension.svg?branch=master)](https://travis-ci.org/rybakit/twig-deferred-extension) [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/rybakit/twig-deferred-extension/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/rybakit/twig-deferred-extension/?branch=master) [![Mentioned in Awesome Twig](https://awesome.re/mentioned-badge.svg)](https://github.com/JulienRAVIA/awesome-twig#extensions) -An extension for Twig that allows to defer block rendering. +An extension for [Twig](https://twig.symfony.com/) that allows to defer block rendering. ## Installation -The recommended way to install the extension is through [Composer](http://getcomposer.org): - -```sh -$ composer require phive/twig-extensions-deferred:^1.0 # for Twig 1.x -$ composer require phive/twig-extensions-deferred:^2.0 # for Twig 2.x +```bash +composer require rybakit/twig-deferred-extension ``` +> *Note that this extension requires Twig 3 or above. If you need support for older versions of Twig, +> please refer to the [legacy repository](https://github.com/rybakit/twig-extensions-deferred-legacy).* + ## Initialization ```php -use Phive\Twig\Extensions\Deferred\DeferredExtension; +use Twig\DeferredExtension\DeferredExtension; use Twig\Environment; ... @@ -53,7 +53,7 @@ use Twig\Environment; ... $twig = new Environment($loader); -$twig->addGlobal('assets', new ArrayObject()); +$twig->addGlobal('assets', new \ArrayObject()); ``` Then build the following set of templates: @@ -140,4 +140,4 @@ The resulting html will be the following: ## License -Deferred Twig Extension is released under the MIT License. See the bundled [LICENSE](LICENSE) file for details. +The library is released under the MIT License. See the bundled [LICENSE](LICENSE) file for details. diff --git a/composer.json b/composer.json index 382c9c5..e4cfc61 100644 --- a/composer.json +++ b/composer.json @@ -1,8 +1,8 @@ { - "name": "phive/twig-extensions-deferred", + "name": "rybakit/twig-deferred-extension", "description": "An extension for Twig that allows to defer block rendering", "keywords": ["twig", "extension", "defer", "lazy"], - "homepage": "https://github.com/rybakit/twig-extensions-deferred", + "homepage": "https://github.com/rybakit/twig-deferred-extension", "type": "library", "license": "MIT", "authors": [ @@ -12,25 +12,23 @@ } ], "require": { - "twig/twig": "^2.8" + "twig/twig": "^3.0" }, "require-dev": { - "phpunit/phpunit": "^6.5" + "friendsofphp/php-cs-fixer": "^2.16", + "phpunit/phpunit": "^6.1|^7.0|^8.0|^9.0" }, "autoload": { "psr-4": { - "Phive\\Twig\\Extensions\\Deferred\\": "src/" + "Twig\\DeferredExtension\\": "src/" } }, "autoload-dev" : { "psr-4": { - "Phive\\Twig\\Extensions\\Tests\\Deferred\\": "tests/" + "Twig\\DeferredExtension\\Tests\\": "tests/" } }, "config": { - "platform": { - "php": "7.0" - }, "preferred-install": { "*": "dist" }, diff --git a/src/DeferredBlockNode.php b/src/DeferredBlockNode.php index 2741008..f3aef76 100755 --- a/src/DeferredBlockNode.php +++ b/src/DeferredBlockNode.php @@ -1,13 +1,24 @@ + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Twig\DeferredExtension; use Twig\Compiler; use Twig\Node\BlockNode; -class DeferredBlockNode extends BlockNode +final class DeferredBlockNode extends BlockNode { - public function compile(Compiler $compiler) + public function compile(Compiler $compiler) : void { $name = $this->getAttribute('name'); diff --git a/src/DeferredExtension.php b/src/DeferredExtension.php index 86aa1fc..7ec9afb 100644 --- a/src/DeferredExtension.php +++ b/src/DeferredExtension.php @@ -1,40 +1,51 @@ + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Twig\DeferredExtension; use Twig\Extension\AbstractExtension; use Twig\Template; -class DeferredExtension extends AbstractExtension +final class DeferredExtension extends AbstractExtension { private $blocks = []; - public function getTokenParsers() + public function getTokenParsers() : array { return [new DeferredTokenParser()]; } - public function getNodeVisitors() + public function getNodeVisitors() : array { return [new DeferredNodeVisitor()]; } - public function defer(Template $template, $blockName) + public function defer(Template $template, string $blockName) : void { $templateName = $template->getTemplateName(); $this->blocks[$templateName][] = $blockName; - ob_start(); + \ob_start(); } - public function resolve(Template $template, array $context, array $blocks) + public function resolve(Template $template, array $context, array $blocks) : void { $templateName = $template->getTemplateName(); if (empty($this->blocks[$templateName])) { return; } - while ($blockName = array_pop($this->blocks[$templateName])) { - $buffer = ob_get_clean(); + while ($blockName = \array_pop($this->blocks[$templateName])) { + $buffer = \ob_get_clean(); $blocks[$blockName] = [$template, 'block_'.$blockName.'_deferred']; $template->displayBlock($blockName, $context, $blocks); diff --git a/src/DeferredNode.php b/src/DeferredNode.php index 419311a..11c33e4 100755 --- a/src/DeferredNode.php +++ b/src/DeferredNode.php @@ -1,13 +1,24 @@ + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Twig\DeferredExtension; use Twig\Compiler; use Twig\Node\Node; -class DeferredNode extends Node +final class DeferredNode extends Node { - public function compile(Compiler $compiler) + public function compile(Compiler $compiler) : void { $compiler ->write("\$this->env->getExtension('".DeferredExtension::class."')->resolve(\$this, \$context, \$blocks);\n") diff --git a/src/DeferredNodeVisitor.php b/src/DeferredNodeVisitor.php index d942c38..6843acc 100644 --- a/src/DeferredNodeVisitor.php +++ b/src/DeferredNodeVisitor.php @@ -1,20 +1,28 @@ + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Twig\DeferredExtension; use Twig\Environment; use Twig\Node\ModuleNode; use Twig\Node\Node; use Twig\NodeVisitor\NodeVisitorInterface; -class DeferredNodeVisitor implements NodeVisitorInterface +final class DeferredNodeVisitor implements NodeVisitorInterface { private $hasDeferred = false; - /** - * {@inheritdoc} - */ - public function enterNode(Node $node, Environment $env) + public function enterNode(Node $node, Environment $env) : Node { if (!$this->hasDeferred && $node instanceof DeferredBlockNode) { $this->hasDeferred = true; @@ -23,10 +31,7 @@ public function enterNode(Node $node, Environment $env) return $node; } - /** - * {@inheritdoc} - */ - public function leaveNode(Node $node, Environment $env) + public function leaveNode(Node $node, Environment $env) : ?Node { if ($this->hasDeferred && $node instanceof ModuleNode) { $node->setNode('display_end', new Node([new DeferredNode(), $node->getNode('display_end')])); @@ -36,10 +41,7 @@ public function leaveNode(Node $node, Environment $env) return $node; } - /** - * {@inheritdoc} - */ - public function getPriority() + public function getPriority() : int { return 0; } diff --git a/src/DeferredTokenParser.php b/src/DeferredTokenParser.php index 390cbb3..1870ae0 100644 --- a/src/DeferredTokenParser.php +++ b/src/DeferredTokenParser.php @@ -1,6 +1,17 @@ + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Twig\DeferredExtension; use Twig\Node\BlockNode; use Twig\Node\Node; @@ -9,11 +20,11 @@ use Twig\TokenParser\AbstractTokenParser; use Twig\TokenParser\BlockTokenParser; -class DeferredTokenParser extends AbstractTokenParser +final class DeferredTokenParser extends AbstractTokenParser { private $blockTokenParser; - public function setParser(Parser $parser) + public function setParser(Parser $parser) : void { parent::setParser($parser); @@ -21,7 +32,7 @@ public function setParser(Parser $parser) $this->blockTokenParser->setParser($parser); } - public function parse(Token $token) + public function parse(Token $token) : Node { $stream = $this->parser->getStream(); $nameToken = $stream->next(); @@ -37,18 +48,18 @@ public function parse(Token $token) return $node; } - public function getTag() + public function getTag() : string { return 'block'; } - private function replaceBlockNode($name) + private function replaceBlockNode(string $name) : void { - $block = $this->parser->getBlock($name)->getNode(0); + $block = $this->parser->getBlock($name)->getNode('0'); $this->parser->setBlock($name, $this->createDeferredBlockNode($block)); } - private function createDeferredBlockNode(BlockNode $block) + private function createDeferredBlockNode(BlockNode $block) : DeferredBlockNode { $name = $block->getAttribute('name'); $deferredBlock = new DeferredBlockNode($name, new Node([]), $block->getTemplateLine()); diff --git a/tests/IntegrationTest.php b/tests/IntegrationTest.php index 26765d5..4d98d05 100644 --- a/tests/IntegrationTest.php +++ b/tests/IntegrationTest.php @@ -1,14 +1,25 @@ + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ -use Phive\Twig\Extensions\Deferred\DeferredExtension; +declare(strict_types=1); + +namespace Twig\DeferredExtension\Tests; + +use Twig\DeferredExtension\DeferredExtension; use Twig\Extension\StringLoaderExtension; use Twig\Test\IntegrationTestCase; -class IntegrationTest extends IntegrationTestCase +final class IntegrationTest extends IntegrationTestCase { - public function getExtensions() + public function getExtensions() : array { return [ new DeferredExtension(), @@ -17,7 +28,7 @@ public function getExtensions() ]; } - public function getFixturesDir() + public function getFixturesDir() : string { return __DIR__.'/Fixtures'; } diff --git a/tests/TestExtension.php b/tests/TestExtension.php index c2b43de..f4b70c4 100644 --- a/tests/TestExtension.php +++ b/tests/TestExtension.php @@ -1,18 +1,29 @@ + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Twig\DeferredExtension\Tests; use Twig\Extension\AbstractExtension; use Twig\Extension\GlobalsInterface; -class TestExtension extends AbstractExtension implements GlobalsInterface +final class TestExtension extends AbstractExtension implements GlobalsInterface { - public function getGlobals() + public function getGlobals() : array { return ['data' => new \ArrayObject()]; } - public function getNodeVisitors() + public function getNodeVisitors() : array { return [new TestNodeVisitor()]; } diff --git a/tests/TestNode.php b/tests/TestNode.php index 83782e4..105bd2b 100644 --- a/tests/TestNode.php +++ b/tests/TestNode.php @@ -1,13 +1,24 @@ + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Twig\DeferredExtension\Tests; use Twig\Compiler; use Twig\Node\Node; -class TestNode extends Node +final class TestNode extends Node { - public function compile(Compiler $compiler) + public function compile(Compiler $compiler) : void { $compiler ->write("if (isset(\$context['body_extra'])) {\n") diff --git a/tests/TestNodeVisitor.php b/tests/TestNodeVisitor.php index 6710146..abc55ac 100644 --- a/tests/TestNodeVisitor.php +++ b/tests/TestNodeVisitor.php @@ -1,26 +1,31 @@ + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Twig\DeferredExtension\Tests; use Twig\Environment; use Twig\Node\ModuleNode; use Twig\Node\Node; use Twig\NodeVisitor\NodeVisitorInterface; -class TestNodeVisitor implements NodeVisitorInterface +final class TestNodeVisitor implements NodeVisitorInterface { - /** - * {@inheritdoc} - */ - public function enterNode(Node $node, Environment $env) + public function enterNode(Node $node, Environment $env) : Node { return $node; } - /** - * {@inheritdoc} - */ - public function leaveNode(Node $node, Environment $env) + public function leaveNode(Node $node, Environment $env) : ?Node { if ($node instanceof ModuleNode) { $node->setNode('display_end', new Node([new TestNode(), $node->getNode('display_end')])); @@ -29,10 +34,7 @@ public function leaveNode(Node $node, Environment $env) return $node; } - /** - * {@inheritdoc} - */ - public function getPriority() + public function getPriority() : int { return 0; }