Skip to content

Commit

Permalink
Add assets formatter
Browse files Browse the repository at this point in the history
  • Loading branch information
StevenRenaux committed Feb 24, 2024
1 parent 6946b8a commit 23473a3
Show file tree
Hide file tree
Showing 18 changed files with 110 additions and 51 deletions.
20 changes: 20 additions & 0 deletions 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 @@ -18,6 +21,7 @@
service('sensiolabs_gotenberg.client'),
abstract_arg('user configuration options'),
param('kernel.project_dir'),
service(Filesystem::class),
service('twig')->nullOnInvalid(),
])
->public()
Expand All @@ -30,4 +34,20 @@
])
->public()
->alias(GotenbergClientInterface::class, 'sensiolabs_gotenberg.client');

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

$services->set('sensiolabs_gotenberg.twig.asset_extension', GotenbergAssetExtension::class)
->args([
service(AssetBaseDirFormatter::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'
asset_base_dir: '%kernel.project_dir%/public/'
options:
paper_width: null # 8.5
paper_height: null # 11
Expand Down
7 changes: 5 additions & 2 deletions docs/customization.rst
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,12 @@ Additional Assets
-----------------

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 URL.
Twig function to help generate that path.

This function work as `asset() Twig function`_.
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 ``asset_base_dir`` in your
configuration file ``config/sensiolabs_gotenberg.yml``.
The path provided can be relative as well as absolute.

.. code-block:: html

Expand Down
15 changes: 0 additions & 15 deletions src/Asset/GotenbergPackage.php

This file was deleted.

6 changes: 4 additions & 2 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 Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\Mime\Part\DataPart;
use Symfony\Component\Mime\Part\File as DataPartFile;
use Twig\Environment;
Expand All @@ -15,9 +16,10 @@ abstract class AbstractChromiumPdfBuilder extends AbstractPdfBuilder
public function __construct(
GotenbergClientInterface $gotenbergClient,
string $projectDir,
Filesystem $filesystem,
private readonly ?Environment $twig = null,
) {
parent::__construct($gotenbergClient, $projectDir);
parent::__construct($gotenbergClient, $projectDir, $filesystem);
}

/**
Expand Down Expand Up @@ -432,7 +434,7 @@ 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);
}
Expand Down
8 changes: 7 additions & 1 deletion 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 Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\HttpFoundation\File\File;
use Symfony\Component\String\UnicodeString;

Expand All @@ -18,6 +19,7 @@ abstract class AbstractPdfBuilder implements PdfBuilderInterface
public function __construct(
protected readonly GotenbergClientInterface $gotenbergClient,
protected readonly string $projectDir,
protected readonly Filesystem $filesystem,
) {
}

Expand Down Expand Up @@ -74,6 +76,10 @@ protected function assertFileExtension(string $path, array $validExtensions): vo

protected function resolveFilePath(string $path): string
{
return str_starts_with($path, '/') ? $path : $this->projectDir.'/'.$path;
if ($this->filesystem->isAbsolutePath($path)) {
return $path;
}

return "{$this->projectDir}/{$path}";
}
}
8 changes: 0 additions & 8 deletions src/Builder/AssetAwareBuilderInterface.php

This file was deleted.

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('asset_base_dir')
->info('Base DIR where assets are located')
->defaultValue('%kernel.project_dir%/public/')
->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, asset_base_dir: 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['asset_base_dir']);
}

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

namespace Sensiolabs\GotenbergBundle\Formatter;

use Symfony\Component\Filesystem\Filesystem;

final readonly class AssetBaseDirFormatter implements \Stringable
{
public function __construct(private string $baseDir, private Filesystem $filesystem, private string $projectDir)
{
}

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

return "{$this->projectDir}/{$this->baseDir}";
}
}
10 changes: 6 additions & 4 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 Symfony\Component\Filesystem\Filesystem;
use Twig\Environment;

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

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

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

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

public function office(): LibreOfficePdfBuilder
{
return (new LibreOfficePdfBuilder($this->gotenbergClient, $this->projectDir))
return (new LibreOfficePdfBuilder($this->gotenbergClient, $this->projectDir, $this->filesystem))
->setConfigurations($this->userConfigurations)
;
}
Expand Down
14 changes: 5 additions & 9 deletions src/Twig/GotenbergAssetExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,15 @@

namespace Sensiolabs\GotenbergBundle\Twig;

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

final class GotenbergAssetExtension extends AbstractExtension
{
private GotenbergPackage $packages;

public function __construct(GotenbergPackage $packages)
public function __construct(private readonly string $formattedAssetBaseDir)
{
$this->packages = $packages;
}

public function getFunctions(): array
Expand All @@ -31,11 +27,11 @@ public function getAssetUrl(array $context, string $path): string
{
$builder = $context['_builder'];

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

$builder->assets($this->packages->getUrl($path));
$builder->assets($this->formattedAssetBaseDir.$path);

return (new File($path))->getFilename();
}
Expand Down
19 changes: 13 additions & 6 deletions tests/Builder/HtmlPdfBuilderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use Sensiolabs\GotenbergBundle\Client\GotenbergClientInterface;
use Sensiolabs\GotenbergBundle\Exception\ExtraHttpHeadersJsonEncodingException;
use Sensiolabs\GotenbergBundle\Exception\PdfPartRenderingException;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\Mime\Part\DataPart;

#[CoversClass(HtmlPdfBuilder::class)]
Expand All @@ -15,7 +16,8 @@ final class HtmlPdfBuilderTest extends AbstractBuilderTestCase
public function testWithConfigurations(): void
{
$client = $this->createMock(GotenbergClientInterface::class);
$builder = new HtmlPdfBuilder($client, self::FIXTURE_DIR);
$filesystem = $this->createMock(Filesystem::class);
$builder = new HtmlPdfBuilder($client, self::FIXTURE_DIR, $filesystem);
$builder->contentFile('content.html');
$builder->setConfigurations(self::getUserConfig());

Expand Down Expand Up @@ -54,7 +56,8 @@ public function testWithConfigurations(): void
public function testWithTemplate(): void
{
$client = $this->createMock(GotenbergClientInterface::class);
$builder = new HtmlPdfBuilder($client, self::FIXTURE_DIR, self::$twig);
$filesystem = $this->createMock(Filesystem::class);
$builder = new HtmlPdfBuilder($client, self::FIXTURE_DIR, $filesystem, self::$twig);
$builder->content('content.html.twig');

$multipartFormData = $builder->getMultipartFormData();
Expand All @@ -70,7 +73,8 @@ public function testWithTemplate(): void
public function testWithAssets(): void
{
$client = $this->createMock(GotenbergClientInterface::class);
$builder = new HtmlPdfBuilder($client, self::FIXTURE_DIR);
$filesystem = $this->createMock(Filesystem::class);
$builder = new HtmlPdfBuilder($client, self::FIXTURE_DIR, $filesystem);
$builder->contentFile('content.html');
$builder->assets('assets/logo.png');

Expand All @@ -88,7 +92,8 @@ public function testWithAssets(): void
public function testWithHeader(): void
{
$client = $this->createMock(GotenbergClientInterface::class);
$builder = new HtmlPdfBuilder($client, self::FIXTURE_DIR);
$filesystem = $this->createMock(Filesystem::class);
$builder = new HtmlPdfBuilder($client, self::FIXTURE_DIR, $filesystem);
$builder->headerFile('header.html');
$builder->contentFile('content.html');

Expand All @@ -109,7 +114,8 @@ public function testInvalidTwigTemplate(): void
$this->expectExceptionMessage('Could not render template "invalid.html.twig" into PDF part "index.html".');

$client = $this->createMock(GotenbergClientInterface::class);
$builder = new HtmlPdfBuilder($client, self::FIXTURE_DIR, self::$twig);
$filesystem = $this->createMock(Filesystem::class);
$builder = new HtmlPdfBuilder($client, self::FIXTURE_DIR, $filesystem, self::$twig);

$builder->content('invalid.html.twig');
}
Expand All @@ -120,7 +126,8 @@ public function testInvalidExtraHttpHeaders(): void
$this->expectExceptionMessage('Could not encode extra HTTP headers into JSON');

$client = $this->createMock(GotenbergClientInterface::class);
$builder = new HtmlPdfBuilder($client, self::FIXTURE_DIR);
$filesystem = $this->createMock(Filesystem::class);
$builder = new HtmlPdfBuilder($client, self::FIXTURE_DIR, $filesystem);
$builder->contentFile('content.html');
// @phpstan-ignore-next-line
$builder->extraHttpHeaders([
Expand Down
4 changes: 3 additions & 1 deletion tests/Builder/LibreOfficePdfBuilderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use PHPUnit\Framework\Attributes\DataProvider;
use Sensiolabs\GotenbergBundle\Builder\LibreOfficePdfBuilder;
use Sensiolabs\GotenbergBundle\Client\GotenbergClientInterface;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\Mime\Part\DataPart;

#[CoversClass(LibreOfficePdfBuilder::class)]
Expand All @@ -29,7 +30,8 @@ public static function provideValidOfficeFiles(): iterable
public function testOfficeFiles(string $filePath, string $contentType): void
{
$client = $this->createMock(GotenbergClientInterface::class);
$builder = new LibreOfficePdfBuilder($client, self::FIXTURE_DIR);
$filesystem = $this->createMock(Filesystem::class);
$builder = new LibreOfficePdfBuilder($client, self::FIXTURE_DIR, $filesystem);
$builder->files($filePath);

$multipartFormData = $builder->getMultipartFormData();
Expand Down
4 changes: 3 additions & 1 deletion tests/Builder/MarkdownPdfBuilderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use PHPUnit\Framework\Attributes\CoversClass;
use Sensiolabs\GotenbergBundle\Builder\MarkdownPdfBuilder;
use Sensiolabs\GotenbergBundle\Client\GotenbergClientInterface;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\Mime\Part\DataPart;

#[CoversClass(MarkdownPdfBuilder::class)]
Expand All @@ -13,7 +14,8 @@ final class MarkdownPdfBuilderTest extends AbstractBuilderTestCase
public function testMarkdownFile(): void
{
$client = $this->createMock(GotenbergClientInterface::class);
$builder = new MarkdownPdfBuilder($client, self::FIXTURE_DIR);
$filesystem = $this->createMock(Filesystem::class);
$builder = new MarkdownPdfBuilder($client, self::FIXTURE_DIR, $filesystem);
$builder
->wrapperFile('template.html')
->files('assets/file.md')
Expand Down
Loading

0 comments on commit 23473a3

Please sign in to comment.