diff --git a/README.md b/README.md index a59d3fd..ac130b0 100644 --- a/README.md +++ b/README.md @@ -48,11 +48,13 @@ Configuration options are described in official [Symfony documentation](https:// You can also use Filter/Helper equivalent. For example if you want to store result in variable: ```latte -{var img = ('my/awesome/image.png')|asset} -{var imgFoo = ('my/awesome/image.png', 'foo')|asset} +{var $filename = 'my/awesome/image.png'} -{var version = ('my/awesome/image.png')|asset_version} -{var versionFoo = ('my/awesome/image.png', 'foo')|asset_version} +{$filename|asset} +{$filename|asset: foo} + +{$filename|asset_version} +{$filename|asset_version: foo} ``` ## Contributing diff --git a/composer.json b/composer.json index 36bf2df..91a3fe8 100644 --- a/composer.json +++ b/composer.json @@ -10,11 +10,11 @@ } ], "require": { - "php": "^7.4 | ^8.0", - "latte/latte": "^2.5", + "php": "^7.4 || ^8.0", + "latte/latte": "^2.5 || ^3.0", "nette/di": "^3.0.10", "nette/utils": "^3.2.5", - "symfony/asset": "^4.2 | ^5.0 | ^6.0" + "symfony/asset": "^4.2 || ^5.0 || ^6.0" }, "require-dev": { "friendsofphp/php-cs-fixer": "^3.13", diff --git a/phpstan.neon b/phpstan.neon index 25bf1ec..3bb8297 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,3 +1,13 @@ includes: - vendor/phpstan/phpstan-nette/extension.neon - vendor/phpstan/phpstan-nette/rules.neon + +parameters: + ignoreErrors: + - + message: '~If condition is always false\.~' + path: src/DI/AssetExtension.php + + excludePaths: + analyse: + - src/Latte/AssetMacroSet.php diff --git a/src/DI/AssetExtension.php b/src/DI/AssetExtension.php index af31d34..36ec5ae 100644 --- a/src/DI/AssetExtension.php +++ b/src/DI/AssetExtension.php @@ -21,6 +21,7 @@ use Symfony\Component\Asset\VersionStrategy\StaticVersionStrategy; use Symfony\Component\Asset\VersionStrategy\VersionStrategyInterface; use Symfony\Component\Asset\VersionStrategy\JsonManifestVersionStrategy; +use SixtyEightPublishers\Asset\Latte\AssetExtension as AssetLatteExtension; use function assert; use function is_array; use function is_string; @@ -109,27 +110,33 @@ public function beforeCompile(): void assert($latteFactory instanceof FactoryDefinition); $resultDefinition = $latteFactory->getResultDefinition(); - # asset filters - $resultDefinition->addSetup('addFilter', [ - 'name' => 'asset', - 'callback' => [$this->prefix('@packages'), 'getUrl'], - ]); - - $resultDefinition->addSetup('addFilter', [ - 'name' => 'asset_version', - 'callback' => [$this->prefix('@packages'), 'getVersion'], - ]); - - # asset macros - $resultDefinition->addSetup('addProvider', [ - 'name' => 'symfonyPackages', - 'value' => $this->prefix('@packages'), - ]); - - $resultDefinition->addSetup('?->onCompile[] = function ($engine) { ?::install($engine->getCompiler()); }', [ - '@self', - new PhpLiteral(AssetMacroSet::class), - ]); + if (version_compare(Engine::VERSION, '3', '<')) { + # asset filters + $resultDefinition->addSetup('addFilter', [ + 'name' => 'asset', + 'callback' => [$this->prefix('@packages'), 'getUrl'], + ]); + + $resultDefinition->addSetup('addFilter', [ + 'name' => 'asset_version', + 'callback' => [$this->prefix('@packages'), 'getVersion'], + ]); + + # asset macros + $resultDefinition->addSetup('addProvider', [ + 'name' => 'symfonyPackages', + 'value' => $this->prefix('@packages'), + ]); + + $resultDefinition->addSetup('?->onCompile[] = function ($engine) { ?::install($engine->getCompiler()); }', [ + '@self', + new PhpLiteral(AssetMacroSet::class), + ]); + } else { + $resultDefinition->addSetup('addExtension', [ + new Statement(AssetLatteExtension::class), + ]); + } } private function createVersionStrategy(string $packageName, PackageConfig $config, ?ServiceDefinition $default = NULL): ServiceDefinition diff --git a/src/Latte/AssetExtension.php b/src/Latte/AssetExtension.php new file mode 100644 index 0000000..44fb4c3 --- /dev/null +++ b/src/Latte/AssetExtension.php @@ -0,0 +1,92 @@ +packages = $packages; + } + + /** + * @return array{asset: callable, asset_version: callable} + */ + public function getTags(): array + { + return [ + 'asset' => [$this, 'createAsset'], + 'asset_version' => [$this, 'createAssetVersion'], + ]; + } + + /** + * @return array{asset: callable, asset_version: callable} + */ + public function getFilters(): array + { + return [ + 'asset' => [$this->packages, 'getUrl'], + 'asset_version' => [$this->packages, 'getVersion'], + ]; + } + + /** + * @return array{symfonyPackages: Packages} + */ + public function getProviders(): array + { + return [ + 'symfonyPackages' => $this->packages, + ]; + } + + public function createAsset(Tag $tag): Node + { + $args = []; + $path = $tag->parser->parseUnquotedStringOrExpression(); + + if (!$tag->parser->isEnd()) { + $tag->parser->stream->tryConsume(','); + $args = [$tag->parser->parseExpression()]; + } + + return new AuxiliaryNode( + fn (PrintContext $context) => $context->format( + 'echo %escape($this->global->symfonyPackages->getUrl(%node, %args));', + $path, + $args + ) + ); + } + + public function createAssetVersion(Tag $tag): Node + { + $args = []; + $path = $tag->parser->parseUnquotedStringOrExpression(); + + if (!$tag->parser->isEnd()) { + $tag->parser->stream->tryConsume(','); + $args = [$tag->parser->parseExpression()]; + } + + return new AuxiliaryNode( + fn (PrintContext $context) => $context->format( + 'echo %escape($this->global->symfonyPackages->getVersion(%node, %args));', + $path, + $args + ) + ); + } +} diff --git a/tests/Latte/AssetMacroSetTest.phpt b/tests/Latte/AssetMacrosAndFiltersTest.phpt similarity index 57% rename from tests/Latte/AssetMacroSetTest.phpt rename to tests/Latte/AssetMacrosAndFiltersTest.phpt index 7006ccb..70aa51d 100644 --- a/tests/Latte/AssetMacroSetTest.phpt +++ b/tests/Latte/AssetMacrosAndFiltersTest.phpt @@ -14,7 +14,7 @@ use function assert; require __DIR__ . '/../bootstrap.php'; -final class AssetMacroSetTest extends TestCase +final class AssetMacrosAndFiltersTest extends TestCase { private Engine $engine; @@ -32,7 +32,7 @@ final class AssetMacroSetTest extends TestCase public function testAssetMacro(): void { - $this->assertMacros([ + $this->assertLatte([ ['{asset "my/file.json"}', 'https://cdn.example.com/my/file.json?version=2.1'], ['{asset "my/nested/file.json", "json_manifest_strategy"}', '/my/nested/file.abc123.json'], ]); @@ -40,13 +40,49 @@ final class AssetMacroSetTest extends TestCase public function testAssetVersionMacro(): void { - $this->assertMacros([ + $this->assertLatte([ ['{asset_version "my/file.json"}', '2.1'], ['{asset_version "my/nested/file.json", "json_manifest_strategy"}', '/my/nested/file.abc123.json'], ]); } - private function assertMacros(array $data): void + public function testAssetFilter(): void + { + $defaultPackage = <<< LATTE +{var \$file = "my/file.json"} +{\$file|asset} +LATTE; + + $nestedPackage = <<< LATTE +{var \$file = "my/nested/file.json"} +{\$file|asset: json_manifest_strategy} +LATTE; + + $this->assertLatte([ + [$defaultPackage, 'https://cdn.example.com/my/file.json?version=2.1'], + [$nestedPackage, '/my/nested/file.abc123.json'], + ]); + } + + public function testAssetVersionFilter(): void + { + $defaultPackage = <<< LATTE +{var \$file = "my/file.json"} +{\$file|asset_version} +LATTE; + + $nestedPackage = <<< LATTE +{var \$file = "my/nested/file.json"} +{\$file|asset_version: json_manifest_strategy} +LATTE; + + $this->assertLatte([ + [$defaultPackage, '2.1'], + [$nestedPackage, '/my/nested/file.abc123.json'], + ]); + } + + private function assertLatte(array $data): void { foreach ($data as [$latteCode, $expectedOutput]) { $output = $this->engine->renderToString($latteCode); @@ -56,4 +92,4 @@ final class AssetMacroSetTest extends TestCase } } -(new AssetMacroSetTest())->run(); +(new AssetMacrosAndFiltersTest())->run();