Skip to content

Commit

Permalink
[UPDATE] Rework to enable custom builders via tag
Browse files Browse the repository at this point in the history
  • Loading branch information
Neirda24 committed Mar 22, 2024
1 parent 262d501 commit 2bcc4d2
Show file tree
Hide file tree
Showing 16 changed files with 300 additions and 164 deletions.
64 changes: 50 additions & 14 deletions config/services.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
<?php

use Sensiolabs\GotenbergBundle\Builder\HtmlPdfBuilder;
use Sensiolabs\GotenbergBundle\Builder\LibreOfficePdfBuilder;
use Sensiolabs\GotenbergBundle\Builder\MarkdownPdfBuilder;
use Sensiolabs\GotenbergBundle\Builder\UrlPdfBuilder;
use Sensiolabs\GotenbergBundle\Client\GotenbergClient;
use Sensiolabs\GotenbergBundle\Client\GotenbergClientInterface;
use Sensiolabs\GotenbergBundle\Formatter\AssetBaseDirFormatter;
Expand All @@ -16,25 +20,11 @@
return function (ContainerConfigurator $container): void {
$services = $container->services();

$services->set('sensiolabs_gotenberg', Gotenberg::class)
->args([
service('sensiolabs_gotenberg.client'),
abstract_arg('html configuration options'),
abstract_arg('url configuration options'),
abstract_arg('markdown configuration options'),
abstract_arg('office configuration options'),
service('sensiolabs_gotenberg.asset.base_dir_formatter'),
service('twig')->nullOnInvalid(),
])
->public()
->alias(GotenbergInterface::class, 'sensiolabs_gotenberg');

$services->set('sensiolabs_gotenberg.client', GotenbergClient::class)
->args([
abstract_arg('base_uri to gotenberg API'),
service(HttpClientInterface::class),
])
->public()
->alias(GotenbergClientInterface::class, 'sensiolabs_gotenberg.client');

$services->set('sensiolabs_gotenberg.asset.base_dir_formatter', AssetBaseDirFormatter::class)
Expand All @@ -49,4 +39,50 @@
$services->set('sensiolabs_gotenberg.twig.asset_extension', GotenbergAssetExtension::class)
->tag('twig.extension')
;

$services->set('.sensiolabs_gotenberg.builder.html', HtmlPdfBuilder::class)
->share(false)
->args([
service('sensiolabs_gotenberg.client'),
service('sensiolabs_gotenberg.asset.base_dir_formatter'),
service('twig')->nullOnInvalid(),
])
->tag('sensiolabs_gotenberg.builder')
;

$services->set('.sensiolabs_gotenberg.builder.url', UrlPdfBuilder::class)
->share(false)
->args([
service('sensiolabs_gotenberg.client'),
service('sensiolabs_gotenberg.asset.base_dir_formatter'),
service('twig')->nullOnInvalid(),
])
->tag('sensiolabs_gotenberg.builder')
;

$services->set('.sensiolabs_gotenberg.builder.markdown', MarkdownPdfBuilder::class)
->share(false)
->args([
service('sensiolabs_gotenberg.client'),
service('sensiolabs_gotenberg.asset.base_dir_formatter'),
service('twig')->nullOnInvalid(),
])
->tag('sensiolabs_gotenberg.builder')
;

$services->set('.sensiolabs_gotenberg.builder.office', LibreOfficePdfBuilder::class)
->share(false)
->args([
service('sensiolabs_gotenberg.client'),
service('sensiolabs_gotenberg.asset.base_dir_formatter'),
])
->tag('sensiolabs_gotenberg.builder')
;

$services->set('sensiolabs_gotenberg', Gotenberg::class)
->args([
abstract_arg('All builders indexed by class FQCN')
])
->alias(GotenbergInterface::class, 'sensiolabs_gotenberg')
;
};
6 changes: 6 additions & 0 deletions phpstan.neon
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
parameters:
level: 8
paths:
- 'config'
- 'src'
- 'tests'
ignoreErrors:
-
message: "#^Method Sensiolabs\\\\GotenbergBundle\\\\Tests\\\\Kernel\\:\\:configureContainer\\(\\) is unused\\.$#"
count: 1
path: tests/Kernel.php
4 changes: 4 additions & 0 deletions phpunit.xml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@
beStrictAboutOutputDuringTests="true"
failOnRisky="true"
failOnWarning="true">
<php>
<env name="KERNEL_CLASS" value="Sensiolabs\GotenbergBundle\Tests\Kernel"/>
</php>

<testsuites>
<testsuite name="default">
<directory>tests</directory>
Expand Down
28 changes: 24 additions & 4 deletions src/Builder/AbstractPdfBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@

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\HttpFoundation\HeaderUtils;

abstract class AbstractPdfBuilder implements PdfBuilderInterface
{
Expand All @@ -15,6 +15,8 @@ abstract class AbstractPdfBuilder implements PdfBuilderInterface
*/
protected array $formFields = [];

private string|null $fileName;

public function __construct(
protected readonly GotenbergClientInterface $gotenbergClient,
protected readonly AssetBaseDirFormatter $asset,
Expand All @@ -25,8 +27,6 @@ public function __construct(
* Compiles the form values into a multipart form data array to send to the HTTP client.
*
* @return array<int, array<string, string>>
*
* @throws MissingRequiredFieldException
*/
abstract public function getMultipartFormData(): array;

Expand All @@ -40,9 +40,29 @@ abstract protected function getEndpoint(): string;
*/
abstract public function setConfigurations(array $configurations): self;

public function withFileName(string $fileName): static
{
$this->fileName = $fileName;

return $this;
}

public function generate(): PdfResponse
{
return $this->gotenbergClient->call($this->getEndpoint(), $this->getMultipartFormData());
$pdfResponse = $this->gotenbergClient->call($this->getEndpoint(), $this->getMultipartFormData());

if (null !== $this->fileName) {
$disposition = HeaderUtils::makeDisposition(
HeaderUtils::DISPOSITION_INLINE, # TODO : make dynamic
$this->fileName
);

$pdfResponse
->headers->set('Content-Disposition', $disposition)
;
}

return $pdfResponse;
}

/**
Expand Down
29 changes: 29 additions & 0 deletions src/DependencyInjection/CompilerPass/ProcessBuildersPass.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

declare(strict_types=1);

namespace Sensiolabs\GotenbergBundle\DependencyInjection\CompilerPass;

use Sensiolabs\GotenbergBundle\Builder\PdfBuilderInterface;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\Compiler\ServiceLocatorTagPass;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;

final class ProcessBuildersPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container): void
{
/** @var array<class-string<PdfBuilderInterface>, Reference> $builders */
$builders = [];
foreach ($container->findTaggedServiceIds('sensiolabs_gotenberg.builder') as $serviceId => $tags) {
$definition = $container->getDefinition($serviceId);

$builders[$definition->getClass()] = new Reference($serviceId);
}

$gotenberg = $container->findDefinition('sensiolabs_gotenberg');

$gotenberg->setArgument('$container', ServiceLocatorTagPass::register($container, $builders));
}
}
8 changes: 0 additions & 8 deletions src/DependencyInjection/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,10 @@ public function getConfigTreeBuilder(): TreeBuilder
->scalarNode('base_uri')
->info('Host of your local Gotenberg API')
->defaultValue('http://localhost:3000')
->cannotBeEmpty()
->validate()
->ifTrue(static function ($option): bool {
return preg_match('/^(http|https):\/\//', $option) !== 1;
})
->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()
Expand Down
21 changes: 16 additions & 5 deletions src/DependencyInjection/SensiolabsGotenbergExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Sensiolabs\GotenbergBundle\DependencyInjection;

use Sensiolabs\GotenbergBundle\Builder\PdfBuilderInterface;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Loader\PhpFileLoader;
Expand All @@ -19,14 +20,24 @@ public function load(array $configs, ContainerBuilder $container): void
/** @var array{base_uri: string, base_directory: string, default_options: array{html: array<string, mixed>, url: array<string, mixed>, markdown: array<string, mixed>, office: array<string, mixed>}} $config */
$config = $this->processConfiguration($configuration, $configs);

$container->registerForAutoconfiguration(PdfBuilderInterface::class)
->addTag('sensiolabs_gotenberg.builder')
;

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

$definition = $container->getDefinition('sensiolabs_gotenberg');
$definition->replaceArgument(1, $this->cleanUserOptions($config['default_options']['html']));
$definition->replaceArgument(2, $this->cleanUserOptions($config['default_options']['url']));
$definition->replaceArgument(3, $this->cleanUserOptions($config['default_options']['markdown']));
$definition->replaceArgument(4, $this->cleanUserOptions($config['default_options']['office']));
$definition = $container->getDefinition('.sensiolabs_gotenberg.builder.html');
$definition->addMethodCall('setConfigurations', [$this->cleanUserOptions($config['default_options']['html'])]);

$definition = $container->getDefinition('.sensiolabs_gotenberg.builder.url');
$definition->addMethodCall('setConfigurations', [$this->cleanUserOptions($config['default_options']['url'])]);

$definition = $container->getDefinition('.sensiolabs_gotenberg.builder.markdown');
$definition->addMethodCall('setConfigurations', [$this->cleanUserOptions($config['default_options']['markdown'])]);

$definition = $container->getDefinition('.sensiolabs_gotenberg.builder.office');
$definition->addMethodCall('setConfigurations', [$this->cleanUserOptions($config['default_options']['office'])]);

$definition = $container->getDefinition('sensiolabs_gotenberg.asset.base_dir_formatter');
$definition->replaceArgument(2, $config['base_directory']);
Expand Down
44 changes: 14 additions & 30 deletions src/Pdf/Gotenberg.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,58 +2,42 @@

namespace Sensiolabs\GotenbergBundle\Pdf;

use Psr\Container\ContainerInterface;
use Sensiolabs\GotenbergBundle\Builder\HtmlPdfBuilder;
use Sensiolabs\GotenbergBundle\Builder\LibreOfficePdfBuilder;
use Sensiolabs\GotenbergBundle\Builder\MarkdownPdfBuilder;
use Sensiolabs\GotenbergBundle\Builder\PdfBuilderInterface;
use Sensiolabs\GotenbergBundle\Builder\UrlPdfBuilder;
use Sensiolabs\GotenbergBundle\Client\GotenbergClientInterface;
use Sensiolabs\GotenbergBundle\Formatter\AssetBaseDirFormatter;
use Twig\Environment;

final readonly class Gotenberg implements GotenbergInterface
{
/**
* @param array<string, mixed> $htmlConfiguration
* @param array<string, mixed> $urlConfiguration
* @param array<string, mixed> $markdownConfiguration
* @param array<string, mixed> $officeConfiguration
*/
public function __construct(
private GotenbergClientInterface $gotenbergClient,
private array $htmlConfiguration,
private array $urlConfiguration,
private array $markdownConfiguration,
private array $officeConfiguration,
private AssetBaseDirFormatter $asset,
private ?Environment $twig = null,
private ContainerInterface $container,
) {
}

public function get(string $builder): PdfBuilderInterface
{
return $this->container->get($builder);
}

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

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

public function markdown(): MarkdownPdfBuilder
public function office(): LibreOfficePdfBuilder
{
return (new MarkdownPdfBuilder($this->gotenbergClient, $this->asset, $this->twig))
->setConfigurations($this->markdownConfiguration)
;
return $this->get(LibreOfficePdfBuilder::class);
}

public function office(): LibreOfficePdfBuilder
public function markdown(): MarkdownPdfBuilder
{
return (new LibreOfficePdfBuilder($this->gotenbergClient, $this->asset))
->setConfigurations($this->officeConfiguration)
;
return $this->get(MarkdownPdfBuilder::class);
}
}
22 changes: 16 additions & 6 deletions src/Pdf/GotenbergInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,25 @@

namespace Sensiolabs\GotenbergBundle\Pdf;

use Sensiolabs\GotenbergBundle\Builder\HtmlPdfBuilder;
use Sensiolabs\GotenbergBundle\Builder\LibreOfficePdfBuilder;
use Sensiolabs\GotenbergBundle\Builder\MarkdownPdfBuilder;
use Sensiolabs\GotenbergBundle\Builder\PdfBuilderInterface;
use Sensiolabs\GotenbergBundle\Builder\UrlPdfBuilder;

interface GotenbergInterface
{
public function html(): PdfBuilderInterface;
/**
* @template T of PdfBuilderInterface
*
* @param class-string<T> $builder
*
* @return T
*/
public function get(string $builder): PdfBuilderInterface;

public function url(): PdfBuilderInterface;

public function markdown(): PdfBuilderInterface;

public function office(): PdfBuilderInterface;
public function html(): HtmlPdfBuilder;
public function url(): UrlPdfBuilder;
public function office(): LibreOfficePdfBuilder;
public function markdown(): MarkdownPdfBuilder;
}
6 changes: 6 additions & 0 deletions src/SensiolabsGotenbergBundle.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,14 @@

namespace Sensiolabs\GotenbergBundle;

use Sensiolabs\GotenbergBundle\DependencyInjection\CompilerPass\ProcessBuildersPass;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Bundle\Bundle;

class SensiolabsGotenbergBundle extends Bundle
{
public function build(ContainerBuilder $container)
{
$container->addCompilerPass(new ProcessBuildersPass());
}
}
10 changes: 0 additions & 10 deletions tests/DependencyInjection/ConfigurationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,16 +53,6 @@ public function testDefaultConfig(): void
self::assertEquals(self::getBundleDefaultConfig(), $config);
}

public function testInvalidHost(): void
{
$this->expectException(InvalidConfigurationException::class);
$processor = new Processor();
$processor->processConfiguration(
new Configuration(),
[['base_uri' => 'localhost:3000']],
);
}

#[DataProvider('provideInvalidRange')]
public function testInvalidRange(mixed $range): void
{
Expand Down
Loading

0 comments on commit 2bcc4d2

Please sign in to comment.