Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Automatically add assets #18

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 17 additions & 1 deletion config/services.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@

use Sensiolabs\GotenbergBundle\Client\GotenbergClient;
use Sensiolabs\GotenbergBundle\Client\GotenbergClientInterface;
use Sensiolabs\GotenbergBundle\Formatter\AssetBaseDirFormatter;
use Sensiolabs\GotenbergBundle\Pdf\Gotenberg;
use Sensiolabs\GotenbergBundle\Pdf\GotenbergInterface;
use Sensiolabs\GotenbergBundle\Twig\GotenbergAssetExtension;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Contracts\HttpClient\HttpClientInterface;
use function Symfony\Component\DependencyInjection\Loader\Configurator\abstract_arg;
use function Symfony\Component\DependencyInjection\Loader\Configurator\param;
Expand All @@ -17,7 +20,7 @@
->args([
service('sensiolabs_gotenberg.client'),
abstract_arg('user configuration options'),
param('kernel.project_dir'),
service('sensiolabs_gotenberg.asset.base_dir_formatter'),
service('twig')->nullOnInvalid(),
])
->public()
Expand All @@ -30,4 +33,17 @@
])
->public()
->alias(GotenbergClientInterface::class, 'sensiolabs_gotenberg.client');

$services->set('sensiolabs_gotenberg.asset.base_dir_formatter', AssetBaseDirFormatter::class)
->args([
service(Filesystem::class),
param('kernel.project_dir'),
abstract_arg('base_directory to assets'),
])
->alias(AssetBaseDirFormatter::class, 'sensiolabs_gotenberg.asset.base_dir_formatter')
;

$services->set('sensiolabs_gotenberg.twig.asset_extension', GotenbergAssetExtension::class)
->tag('twig.extension')
;
};
1 change: 1 addition & 0 deletions docs/configuration.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ The default configuration for the bundle looks like :
sensiolabs_gotenberg:
base_uri: 'http://localhost:3000'
base_directory: '%kernel.project_dir%'
options:
paper_width: null # 8.5
paper_height: null # 11
Expand Down
22 changes: 9 additions & 13 deletions docs/customization.rst
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,13 @@ already set in your ``sensiolabs_gotenberg.yml``.
Additional Assets
-----------------

You can reference any file (like images, fonts, stylesheets, and so on...)
from within a template.
If a template needs to link to a static asset (e.g. an image), this bundle provides an gotenberg_asset()
Twig function to help generate that path.

.. warning::
The only requirement is that their paths in the template file are on the root level.
This function work as `asset() Twig function`_ and fetch your assets in the public folder of your application
If your files are in another folder, you can override the default value of ``base_directory`` in your
configuration file ``config/sensiolabs_gotenberg.yml``.
The path provided can be relative as well as absolute.

.. code-block:: html

Expand All @@ -32,28 +34,21 @@ from within a template.
<title>PDF body</title>
</head>
<body>
<img src="ceo.jpeg" />
<img src="admin.jpeg" />
<img src="{{ gotenberg_asset('public/img/ceo.jpeg') }}" alt="CEO"/>
<img src="{{ gotenberg_asset('public/img/admin.jpeg') }}" alt="Admin"/>
<main>
<h1>Hello world!</h1>
</main>
</body>
</html>

When building the PDF, you just have to use the ``assets`` method to add any
asset referenced in the template to the request.

.. code-block:: php
use Sensiolabs\GotenbergBundle\Pdf\Gotenberg;
$twigPdfBuilder = $gotenberg->twig();
$twigPdfBuilder
->content('path/to/template.html.twig')
->assets(
'assets/images/profiles/ceo.jpeg',
'assets/images/profiles/admin.jpeg',
)
->generate()
.. tip::
Expand Down Expand Up @@ -339,6 +334,7 @@ Enable PDF for Universal Access for optimal accessibility.

For more information about `pdf formats`_.

.. _asset() Twig function: https://symfony.com/doc/current/templates.html#linking-to-css-javascript-and-image-assets
.. _assets: https://gotenberg.dev/docs/routes#html-file-into-pdf-route
.. _defaults properties: https://gotenberg.dev/docs/routes#page-properties-chromium
.. _Header and footer: https://gotenberg.dev/docs/routes#header--footer
Expand Down
17 changes: 10 additions & 7 deletions src/Builder/AbstractChromiumPdfBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use Sensiolabs\GotenbergBundle\Enum\PdfPart;
use Sensiolabs\GotenbergBundle\Exception\ExtraHttpHeadersJsonEncodingException;
use Sensiolabs\GotenbergBundle\Exception\PdfPartRenderingException;
use Sensiolabs\GotenbergBundle\Formatter\AssetBaseDirFormatter;
use Symfony\Component\Mime\Part\DataPart;
use Symfony\Component\Mime\Part\File as DataPartFile;
use Twig\Environment;
Expand All @@ -14,10 +15,10 @@ abstract class AbstractChromiumPdfBuilder extends AbstractPdfBuilder
{
public function __construct(
GotenbergClientInterface $gotenbergClient,
string $projectDir,
AssetBaseDirFormatter $asset,
private readonly ?Environment $twig = null,
) {
parent::__construct($gotenbergClient, $projectDir);
parent::__construct($gotenbergClient, $asset);
}

/**
Expand Down Expand Up @@ -232,9 +233,11 @@ public function assets(string ...$paths): static
*/
public function addAsset(string $path): static
{
$dataPart = new DataPart(new DataPartFile($this->resolveFilePath($path)));
$resolvedPath = $this->asset->resolve($path);

$this->formFields['assets'][$path] = $dataPart;
$dataPart = new DataPart(new DataPartFile($resolvedPath));

$this->formFields['assets'][$resolvedPath] = $dataPart;

return $this;
}
Expand Down Expand Up @@ -411,7 +414,7 @@ public function getMultipartFormData(): array
protected function withPdfPartFile(PdfPart $pdfPart, string $path): static
{
$dataPart = new DataPart(
new DataPartFile($this->resolveFilePath($path)),
new DataPartFile($this->asset->resolve($path)),
$pdfPart->value,
);

Expand All @@ -432,9 +435,9 @@ protected function withRenderedPart(PdfPart $pdfPart, string $template, array $c
}

try {
$html = $this->twig->render($template, $context);
$html = $this->twig->render($template, array_merge($context, ['_builder' => $this]));
} catch (\Throwable $error) {
throw new PdfPartRenderingException(sprintf('Could not render template "%s" into PDF part "%s".', $template, $pdfPart->value), previous: $error);
throw new PdfPartRenderingException(sprintf('Could not render template "%s" into PDF part "%s". %s', $template, $pdfPart->value, $error->getMessage()), previous: $error);
}

$this->formFields[$pdfPart->value] = new DataPart($html, $pdfPart->value, 'text/html');
Expand Down
10 changes: 3 additions & 7 deletions src/Builder/AbstractPdfBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use Sensiolabs\GotenbergBundle\Client\GotenbergClientInterface;
use Sensiolabs\GotenbergBundle\Client\PdfResponse;
use Sensiolabs\GotenbergBundle\Exception\MissingRequiredFieldException;
use Sensiolabs\GotenbergBundle\Formatter\AssetBaseDirFormatter;
use Symfony\Component\HttpFoundation\File\File;
use Symfony\Component\String\UnicodeString;

Expand All @@ -17,7 +18,7 @@ abstract class AbstractPdfBuilder implements PdfBuilderInterface

public function __construct(
protected readonly GotenbergClientInterface $gotenbergClient,
protected readonly string $projectDir,
protected readonly AssetBaseDirFormatter $asset,
) {
}

Expand Down Expand Up @@ -64,16 +65,11 @@ public function setConfigurations(array $configurations): static
*/
protected function assertFileExtension(string $path, array $validExtensions): void
{
$file = new File($this->resolveFilePath($path));
$file = new File($this->asset->resolve($path));
$extension = $file->getExtension();

if (!\in_array($extension, $validExtensions, true)) {
throw new \InvalidArgumentException(sprintf('The file extension "%s" is not available in Gotenberg.', $extension));
}
}

protected function resolveFilePath(string $path): string
{
return str_starts_with($path, '/') ? $path : $this->projectDir.'/'.$path;
}
}
2 changes: 1 addition & 1 deletion src/Builder/LibreOfficePdfBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ public function files(string ...$paths): self
foreach ($paths as $path) {
$this->assertFileExtension($path, self::AVAILABLE_EXTENSIONS);

$dataPart = new DataPart(new DataPartFile($this->resolveFilePath($path)));
$dataPart = new DataPart(new DataPartFile($this->asset->resolve($path)));

$this->formFields['files'][$path] = $dataPart;
}
Expand Down
2 changes: 1 addition & 1 deletion src/Builder/MarkdownPdfBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public function files(string ...$paths): self
foreach ($paths as $path) {
$this->assertFileExtension($path, ['md']);

$dataPart = new DataPart(new DataPartFile($this->resolveFilePath($path)));
$dataPart = new DataPart(new DataPartFile($this->asset->resolve($path)));

$this->formFields['files'][$path] = $dataPart;
}
Expand Down
5 changes: 5 additions & 0 deletions src/DependencyInjection/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ public function getConfigTreeBuilder(): TreeBuilder
->thenInvalid('Invalid API Gotenberg host.')
->end()
->end()
->scalarNode('base_directory')
->info('Base directory will be used for assets, files, markdown')
->defaultValue('%kernel.project_dir%')
->cannotBeEmpty()
->end()
->arrayNode('default_options')
->addDefaultsIfNotSet()
->children()
Expand Down
5 changes: 4 additions & 1 deletion src/DependencyInjection/SensiolabsGotenbergExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,17 @@ public function load(array $configs, ContainerBuilder $container): void

$configuration = new Configuration();

/** @var array{base_uri: string, default_options: array<string, mixed>} $config */
/** @var array{base_uri: string, base_directory: string, default_options: array<string, mixed>} $config */
$config = $this->processConfiguration($configuration, $configs);

$definition = $container->getDefinition('sensiolabs_gotenberg.client');
$definition->replaceArgument(0, $config['base_uri']);

$definition = $container->getDefinition('sensiolabs_gotenberg');
$definition->replaceArgument(1, $this->cleanDefaultOptions($config['default_options']));

$definition = $container->getDefinition('sensiolabs_gotenberg.asset.base_dir_formatter');
$definition->replaceArgument(0, $config['base_directory']);
}

/**
Expand Down
28 changes: 28 additions & 0 deletions src/Formatter/AssetBaseDirFormatter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

namespace Sensiolabs\GotenbergBundle\Formatter;

use Symfony\Component\Filesystem\Filesystem;

final readonly class AssetBaseDirFormatter
{
private string $baseDir;

public function __construct(private Filesystem $filesystem, private string $projectDir, string $baseDir)
{
$this->baseDir = rtrim($baseDir, '/');
}

public function resolve(string $path): string
{
if ($this->filesystem->isAbsolutePath($path)) {
return $path;
}

if ($this->filesystem->isAbsolutePath($this->baseDir)) {
return "{$this->baseDir}/{$path}";
}

return "{$this->projectDir}/{$this->baseDir}/{$path}";
}
}
11 changes: 6 additions & 5 deletions src/Pdf/Gotenberg.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use Sensiolabs\GotenbergBundle\Builder\MarkdownPdfBuilder;
use Sensiolabs\GotenbergBundle\Builder\UrlPdfBuilder;
use Sensiolabs\GotenbergBundle\Client\GotenbergClientInterface;
use Sensiolabs\GotenbergBundle\Formatter\AssetBaseDirFormatter;
use Twig\Environment;

final readonly class Gotenberg implements GotenbergInterface
Expand All @@ -17,35 +18,35 @@
public function __construct(
private GotenbergClientInterface $gotenbergClient,
private array $userConfigurations,
private string $projectDir,
private AssetBaseDirFormatter $asset,
private ?Environment $twig = null,
) {
}

public function html(): HtmlPdfBuilder
{
return (new HtmlPdfBuilder($this->gotenbergClient, $this->projectDir, $this->twig))
return (new HtmlPdfBuilder($this->gotenbergClient, $this->asset, $this->twig))
->setConfigurations($this->userConfigurations)
;
}

public function url(): UrlPdfBuilder
{
return (new UrlPdfBuilder($this->gotenbergClient, $this->projectDir, $this->twig))
return (new UrlPdfBuilder($this->gotenbergClient, $this->asset, $this->twig))
->setConfigurations($this->userConfigurations)
;
}

public function markdown(): MarkdownPdfBuilder
{
return (new MarkdownPdfBuilder($this->gotenbergClient, $this->projectDir, $this->twig))
return (new MarkdownPdfBuilder($this->gotenbergClient, $this->asset, $this->twig))
->setConfigurations($this->userConfigurations)
;
}

public function office(): LibreOfficePdfBuilder
{
return (new LibreOfficePdfBuilder($this->gotenbergClient, $this->projectDir))
return (new LibreOfficePdfBuilder($this->gotenbergClient, $this->asset))
->setConfigurations($this->userConfigurations)
;
}
Expand Down
34 changes: 34 additions & 0 deletions src/Twig/GotenbergAssetExtension.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

namespace Sensiolabs\GotenbergBundle\Twig;

use Sensiolabs\GotenbergBundle\Builder\AbstractChromiumPdfBuilder;
use Symfony\Component\Mime\Part\File;
use Twig\Extension\AbstractExtension;
use Twig\TwigFunction;

final class GotenbergAssetExtension extends AbstractExtension
{
public function getFunctions(): array
{
return [
new TwigFunction('gotenberg_asset', $this->getAssetUrl(...), ['needs_context' => true]),
StevenRenaux marked this conversation as resolved.
Show resolved Hide resolved
];
}

/**
* @param array<string, mixed> $context
*/
public function getAssetUrl(array $context, string $path): string
{
$builder = $context['_builder'];

if (!$builder instanceof AbstractChromiumPdfBuilder) {
throw new \LogicException('You need to extend from AbstractChromiumPdfBuilder to use gotenberg_asset function.');
}

$builder->addAsset($path);

return (new File($path))->getFilename();
Neirda24 marked this conversation as resolved.
Show resolved Hide resolved
}
}
Loading