diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..050fab29 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,5 @@ +# CHANGELOG + +## 0.3.0 + +* [BC BREAK] Rename `sensiolabs_gotenberg.twig.asset_extension` to `sensiolabs_gotenberg.twig.gotenberg_asset_extension` diff --git a/composer.json b/composer.json index edf4080f..19792f71 100644 --- a/composer.json +++ b/composer.json @@ -39,6 +39,7 @@ "phpstan/phpstan-symfony": "^1.3", "phpunit/phpunit": "^10.4", "shipmonk/composer-dependency-analyser": "^1.7", + "symfony/asset": "^6.4 || ^7.0", "symfony/framework-bundle": "^6.4 || ^7.0", "symfony/http-client": "^6.4 || ^7.0", "symfony/monolog-bundle": "^3.10", diff --git a/config/asset.php b/config/asset.php new file mode 100644 index 00000000..8e42a981 --- /dev/null +++ b/config/asset.php @@ -0,0 +1,19 @@ +services(); + + $services->set('sensiolabs_gotenberg.twig.asset_extension', AssetExtension::class) + ->decorate('twig.extension.assets') + ->args([ + service('.inner'), + service('assets.packages'), + param('kernel.project_dir'), + ]) + ; +}; diff --git a/config/services.php b/config/services.php index 422b6e73..9648652f 100644 --- a/config/services.php +++ b/config/services.php @@ -39,7 +39,7 @@ ->alias(AssetBaseDirFormatter::class, 'sensiolabs_gotenberg.asset.base_dir_formatter') ; - $services->set('sensiolabs_gotenberg.twig.asset_extension', GotenbergAssetExtension::class) + $services->set('sensiolabs_gotenberg.twig.gotenberg_asset_extension', GotenbergAssetExtension::class) ->tag('twig.extension') ; diff --git a/docs/assets.md b/docs/assets.md index f4798fd4..8552f68c 100644 --- a/docs/assets.md +++ b/docs/assets.md @@ -8,9 +8,22 @@ You can add assets in several ways, and it's available for most builders. | Screenshot | :white_check_mark: | :white_check_mark: | :white_check_mark: | N/A | > [!WARNING] -> As a reminder, we can only load assets in the content. And not in Header or Footer. +> As a reminder, we can only load assets in the content, not in Header or Footer. +> However, you can load images using a base64 encoded source. > For more information about [Header and Footer restriction](https://gotenberg.dev/docs/routes#header-footer-chromium) -> + +## Using public assets with the Symfony Asset component + +Public assets loaded using the [Symfony Asset component](https://symfony.com/doc/current/components/asset.html) can be +used when generating your PDF. + +> [!WARNING] +> Since the Asset component handle assets from the public folder, prefer the Gotenberg bundle to display private assets. +> See below. + +## Using private assets with the Gotenberg bundle + +> [!WARNING] > By default, the assets are fetch in the `assets` folder of your application. > If your assets files are in another folder, you can override the > default value of `assets_directory` in your configuration file @@ -47,7 +60,7 @@ You can add assets in several ways, and it's available for most builders. > ``` > -## Twig file +### Twig file `{{ gotenberg_asset() }}` Twig function will help you to generate an asset path. This function work as [asset() Twig function](https://symfony.com/doc/current/templates.html#linking-to-css-javascript-and-image-assets). @@ -104,7 +117,7 @@ class YourController } ``` -## HTML file +### HTML file If your file is an HTML file and not a Twig template, you can also add some assets as below. diff --git a/src/Builder/Pdf/AbstractChromiumPdfBuilder.php b/src/Builder/Pdf/AbstractChromiumPdfBuilder.php index c734cccf..0b0334b5 100644 --- a/src/Builder/Pdf/AbstractChromiumPdfBuilder.php +++ b/src/Builder/Pdf/AbstractChromiumPdfBuilder.php @@ -343,13 +343,13 @@ public function assets(string ...$paths): static /** * Adds a file, like an image, font, stylesheet, and so on. */ - public function addAsset(string $path): static + public function addAsset(string $path, string|null $name = null): static { $resolvedPath = $this->asset->resolve($path); - $dataPart = new DataPart(new DataPartFile($resolvedPath)); + $dataPart = new DataPart(new DataPartFile($resolvedPath, $name)); - $this->formFields['assets'][$resolvedPath] = $dataPart; + $this->formFields['assets'][$name ?? $resolvedPath] = $dataPart; return $this; } diff --git a/src/Builder/Screenshot/AbstractChromiumScreenshotBuilder.php b/src/Builder/Screenshot/AbstractChromiumScreenshotBuilder.php index 7ffb756a..56252ee0 100644 --- a/src/Builder/Screenshot/AbstractChromiumScreenshotBuilder.php +++ b/src/Builder/Screenshot/AbstractChromiumScreenshotBuilder.php @@ -351,13 +351,13 @@ public function assets(string ...$paths): static /** * Adds a file, like an image, font, stylesheet, and so on. */ - public function addAsset(string $path): static + public function addAsset(string $path, string|null $name = null): static { $resolvedPath = $this->asset->resolve($path); - $dataPart = new DataPart(new DataPartFile($resolvedPath)); + $dataPart = new DataPart(new DataPartFile($resolvedPath, $name)); - $this->formFields['assets'][$resolvedPath] = $dataPart; + $this->formFields['assets'][$name ?? $resolvedPath] = $dataPart; return $this; } diff --git a/src/DependencyInjection/SensiolabsGotenbergExtension.php b/src/DependencyInjection/SensiolabsGotenbergExtension.php index b9c490fa..34715b01 100644 --- a/src/DependencyInjection/SensiolabsGotenbergExtension.php +++ b/src/DependencyInjection/SensiolabsGotenbergExtension.php @@ -4,6 +4,7 @@ use Sensiolabs\GotenbergBundle\Builder\Pdf\PdfBuilderInterface; use Sensiolabs\GotenbergBundle\Builder\Screenshot\ScreenshotBuilderInterface; +use Symfony\Bridge\Twig\Extension\AssetExtension; use Symfony\Component\Config\FileLocator; use Symfony\Component\DependencyInjection\Alias; use Symfony\Component\DependencyInjection\ContainerBuilder; @@ -57,6 +58,10 @@ public function load(array $configs, ContainerBuilder $container): void $loader->load('builder_screenshot.php'); $loader->load('services.php'); + if ($container::willBeAvailable('symfony/asset', AssetExtension::class, ['symfony/framework-bundle'])) { + $loader->load('asset.php'); + } + if (false === $config['controller_listener']) { $container->removeDefinition('sensiolabs_gotenberg.http_kernel.stream_builder'); } diff --git a/src/Exception/ClientException.php b/src/Exception/ClientException.php index e8eb548e..5fa64ae5 100644 --- a/src/Exception/ClientException.php +++ b/src/Exception/ClientException.php @@ -2,6 +2,6 @@ namespace Sensiolabs\GotenbergBundle\Exception; -class ClientException extends \RuntimeException implements ExceptionInterface +class ClientException extends RuntimeException { } diff --git a/src/Exception/InvalidBuilderConfiguration.php b/src/Exception/InvalidBuilderConfiguration.php index dd11d04b..b0bd0c65 100644 --- a/src/Exception/InvalidBuilderConfiguration.php +++ b/src/Exception/InvalidBuilderConfiguration.php @@ -2,6 +2,6 @@ namespace Sensiolabs\GotenbergBundle\Exception; -final class InvalidBuilderConfiguration extends \RuntimeException implements ExceptionInterface +final class InvalidBuilderConfiguration extends RuntimeException { } diff --git a/src/Exception/MissingRequiredFieldException.php b/src/Exception/MissingRequiredFieldException.php index 783b6c9a..b2664c15 100644 --- a/src/Exception/MissingRequiredFieldException.php +++ b/src/Exception/MissingRequiredFieldException.php @@ -2,6 +2,6 @@ namespace Sensiolabs\GotenbergBundle\Exception; -final class MissingRequiredFieldException extends \RuntimeException implements ExceptionInterface +final class MissingRequiredFieldException extends RuntimeException { } diff --git a/src/Exception/PdfPartRenderingException.php b/src/Exception/PdfPartRenderingException.php index 827b3841..14bbe7ae 100644 --- a/src/Exception/PdfPartRenderingException.php +++ b/src/Exception/PdfPartRenderingException.php @@ -2,6 +2,6 @@ namespace Sensiolabs\GotenbergBundle\Exception; -final class PdfPartRenderingException extends \RuntimeException implements ExceptionInterface +final class PdfPartRenderingException extends RuntimeException { } diff --git a/src/Exception/ProcessorException.php b/src/Exception/ProcessorException.php index b0e79c31..3a272a24 100644 --- a/src/Exception/ProcessorException.php +++ b/src/Exception/ProcessorException.php @@ -2,6 +2,6 @@ namespace Sensiolabs\GotenbergBundle\Exception; -class ProcessorException extends \RuntimeException implements ExceptionInterface +class ProcessorException extends RuntimeException { } diff --git a/src/Exception/RenderingException.php b/src/Exception/RenderingException.php new file mode 100644 index 00000000..b4ba7d75 --- /dev/null +++ b/src/Exception/RenderingException.php @@ -0,0 +1,7 @@ +inner->getFunctions() as $function) { + if ('asset' === $function->getName()) { + $function = new TwigFunction('asset', $this->getAsset(...), ['needs_context' => true]); + } + $functions[$function->getName()] = $function; + } + + return $functions; + } + + /** + * @param array $context + */ + public function getAsset(array $context, string $path, string|null $packageName = null): string + { + $builder = $context['_builder'] ?? null; + + if (!$builder) { + return $this->inner->getAssetUrl($path, $packageName); + } + + $package = $this->packages->getPackage($packageName); + if (!$package instanceof PathPackage) { + return $this->inner->getAssetUrl($path, $packageName); + } + + if (!$builder instanceof AbstractChromiumPdfBuilder && !$builder instanceof AbstractChromiumScreenshotBuilder) { + throw new RenderingException('The gotenberg_asset function must be used with a class extending AbstractChromiumPdfBuilder or AbstractChromiumScreenshotBuilder.'); + } + + $name = uniqid(); + + $builder->addAsset($this->projectDir.'/public'.$package->getBasePath().$path, $name); + + return $name; + } +} diff --git a/src/Twig/GotenbergAssetExtension.php b/src/Twig/GotenbergAssetExtension.php index 343e3937..7c352d48 100644 --- a/src/Twig/GotenbergAssetExtension.php +++ b/src/Twig/GotenbergAssetExtension.php @@ -21,7 +21,7 @@ public function getFunctions(): array */ public function getAssetUrl(array $context, string $path): string { - $builder = $context['_builder']; + $builder = $context['_builder'] ?? null; if (!$builder instanceof AbstractChromiumPdfBuilder && !$builder instanceof AbstractChromiumScreenshotBuilder) { throw new \LogicException('You need to extend from AbstractChromiumPdfBuilder to use gotenberg_asset function.');