diff --git a/UPGRADE.md b/UPGRADE.md
index 3930e5c9..72ce1ff0 100644
--- a/UPGRADE.md
+++ b/UPGRADE.md
@@ -1,3 +1,7 @@
+### UPGRADE FROM 0.20.0 TO 0.21.0
+
+1. `Sylius\InvoicingPlugin\Generator\InvoicePdfFileGenerator` takes `Sylius\InvoicingPlugin\Generator\PdfOptionsGeneratorInterface` as the third argument after `Knp\Snappy\GeneratorInterface`.
+
### UPGRADE FROM 0.19.0 TO 0.20.0
1. Since 0.20.0, the recommended Sylius version to use with InvoicingPlugin is `1.11.*`. If you would like to upgrade Sylius to v1.11.0,
diff --git a/spec/Generator/InvoicePdfFileGeneratorSpec.php b/spec/Generator/InvoicePdfFileGeneratorSpec.php
index 1da9e4a0..1018c9bf 100644
--- a/spec/Generator/InvoicePdfFileGeneratorSpec.php
+++ b/spec/Generator/InvoicePdfFileGeneratorSpec.php
@@ -19,6 +19,7 @@
use Sylius\InvoicingPlugin\Entity\InvoiceInterface;
use Sylius\InvoicingPlugin\Generator\InvoiceFileNameGeneratorInterface;
use Sylius\InvoicingPlugin\Generator\InvoicePdfFileGeneratorInterface;
+use Sylius\InvoicingPlugin\Generator\PdfOptionsGeneratorInterface;
use Sylius\InvoicingPlugin\Model\InvoicePdf;
use Symfony\Component\Config\FileLocatorInterface;
use Twig\Environment;
@@ -28,12 +29,14 @@ final class InvoicePdfFileGeneratorSpec extends ObjectBehavior
function let(
Environment $twig,
GeneratorInterface $pdfGenerator,
+ PdfOptionsGeneratorInterface $pdfOptionsGenerator,
FileLocatorInterface $fileLocator,
InvoiceFileNameGeneratorInterface $invoiceFileNameGenerator
): void {
$this->beConstructedWith(
$twig,
$pdfGenerator,
+ $pdfOptionsGenerator,
$fileLocator,
$invoiceFileNameGenerator,
'invoiceTemplate.html.twig',
@@ -50,6 +53,7 @@ function it_creates_invoice_pdf_with_generated_content_and_filename_basing_on_in
FileLocatorInterface $fileLocator,
Environment $twig,
GeneratorInterface $pdfGenerator,
+ PdfOptionsGeneratorInterface $pdfOptionsGenerator,
InvoiceFileNameGeneratorInterface $invoiceFileNameGenerator,
InvoiceInterface $invoice,
ChannelInterface $channel
@@ -64,8 +68,19 @@ function it_creates_invoice_pdf_with_generated_content_and_filename_basing_on_in
->willReturn('I am an invoice pdf file content')
;
- $pdfGenerator->getOutputFromHtml('I am an invoice pdf file content')->willReturn('PDF FILE');
+ $pdfOptionsGenerator
+ ->generate()
+ ->willReturn(['allow' => ['located-path/sylius-logo.png']])
+ ;
+
+ $pdfGenerator
+ ->getOutputFromHtml('I am an invoice pdf file content', ['allow' => ['located-path/sylius-logo.png']])
+ ->willReturn('PDF FILE')
+ ;
- $this->generate($invoice)->shouldBeLike(new InvoicePdf('2015_05_00004444.pdf', 'PDF FILE'));
+ $this
+ ->generate($invoice)
+ ->shouldBeLike(new InvoicePdf('2015_05_00004444.pdf', 'PDF FILE'))
+ ;
}
}
diff --git a/spec/Generator/PdfOptionsGeneratorSpec.php b/spec/Generator/PdfOptionsGeneratorSpec.php
new file mode 100644
index 00000000..27cec88d
--- /dev/null
+++ b/spec/Generator/PdfOptionsGeneratorSpec.php
@@ -0,0 +1,52 @@
+beConstructedWith(
+ $fileLocator,
+ ['allow' => 'allowed_file_in_knp_snappy_config.png'],
+ ['swans.png']
+ );
+ }
+
+ function it_is_pdf_options_generator_interface(): void
+ {
+ $this->shouldImplement(PdfOptionsGeneratorInterface::class);
+ }
+
+ function it_generates_pdf_options(FileLocatorInterface $fileLocator): void
+ {
+ $fileLocator
+ ->locate('swans.png')
+ ->willReturn('located-path/swans.png');
+
+ $this
+ ->generate()
+ ->shouldBeLike([
+ 'allow' => [
+ 'allowed_file_in_knp_snappy_config.png',
+ 'located-path/swans.png',
+ ],
+ ])
+ ;
+ }
+}
diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php
index 58e4f4fd..69274dfd 100644
--- a/src/DependencyInjection/Configuration.php
+++ b/src/DependencyInjection/Configuration.php
@@ -32,6 +32,7 @@
use Sylius\InvoicingPlugin\Factory\InvoiceShopBillingDataFactory;
use Sylius\InvoicingPlugin\Factory\LineItemFactory;
use Sylius\InvoicingPlugin\Factory\TaxItemFactory;
+use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\ConfigurationInterface;
@@ -42,7 +43,15 @@ public function getConfigTreeBuilder(): TreeBuilder
$treeBuilder = new TreeBuilder('sylius_invoicing_plugin');
$rootNode = $treeBuilder->getRootNode();
- $rootNode
+ $this->addResourcesSection($rootNode);
+ $this->addPdfGeneratorSection($rootNode);
+
+ return $treeBuilder;
+ }
+
+ private function addResourcesSection(ArrayNodeDefinition $node): void
+ {
+ $node
->children()
->arrayNode('resources')
->addDefaultsIfNotSet()
@@ -78,63 +87,63 @@ public function getConfigTreeBuilder(): TreeBuilder
->end()
->end()
->end()
- ->end()
- ->arrayNode('shop_billing_data')
- ->addDefaultsIfNotSet()
- ->children()
- ->variableNode('options')->end()
- ->arrayNode('classes')
- ->addDefaultsIfNotSet()
- ->children()
- ->scalarNode('model')->defaultValue(InvoiceShopBillingData::class)->cannotBeEmpty()->end()
- ->scalarNode('interface')->defaultValue(InvoiceShopBillingDataInterface::class)->cannotBeEmpty()->end()
- ->scalarNode('controller')->defaultValue(ResourceController::class)->cannotBeEmpty()->end()
- ->scalarNode('factory')->defaultValue(InvoiceShopBillingDataFactory::class)->cannotBeEmpty()->end()
- ->scalarNode('repository')->cannotBeEmpty()->end()
- ->end()
+ ->end()
+ ->arrayNode('shop_billing_data')
+ ->addDefaultsIfNotSet()
+ ->children()
+ ->variableNode('options')->end()
+ ->arrayNode('classes')
+ ->addDefaultsIfNotSet()
+ ->children()
+ ->scalarNode('model')->defaultValue(InvoiceShopBillingData::class)->cannotBeEmpty()->end()
+ ->scalarNode('interface')->defaultValue(InvoiceShopBillingDataInterface::class)->cannotBeEmpty()->end()
+ ->scalarNode('controller')->defaultValue(ResourceController::class)->cannotBeEmpty()->end()
+ ->scalarNode('factory')->defaultValue(InvoiceShopBillingDataFactory::class)->cannotBeEmpty()->end()
+ ->scalarNode('repository')->cannotBeEmpty()->end()
->end()
->end()
->end()
- ->arrayNode('line_item')
- ->addDefaultsIfNotSet()
- ->children()
- ->variableNode('options')->end()
- ->arrayNode('classes')
- ->addDefaultsIfNotSet()
- ->children()
- ->scalarNode('model')->defaultValue(LineItem::class)->cannotBeEmpty()->end()
- ->scalarNode('interface')->defaultValue(LineItemInterface::class)->cannotBeEmpty()->end()
- ->scalarNode('controller')->defaultValue(ResourceController::class)->cannotBeEmpty()->end()
- ->scalarNode('factory')->defaultValue(LineItemFactory::class)->cannotBeEmpty()->end()
- ->scalarNode('repository')->cannotBeEmpty()->end()
- ->end()
+ ->end()
+ ->arrayNode('line_item')
+ ->addDefaultsIfNotSet()
+ ->children()
+ ->variableNode('options')->end()
+ ->arrayNode('classes')
+ ->addDefaultsIfNotSet()
+ ->children()
+ ->scalarNode('model')->defaultValue(LineItem::class)->cannotBeEmpty()->end()
+ ->scalarNode('interface')->defaultValue(LineItemInterface::class)->cannotBeEmpty()->end()
+ ->scalarNode('controller')->defaultValue(ResourceController::class)->cannotBeEmpty()->end()
+ ->scalarNode('factory')->defaultValue(LineItemFactory::class)->cannotBeEmpty()->end()
+ ->scalarNode('repository')->cannotBeEmpty()->end()
->end()
->end()
->end()
- ->arrayNode('tax_item')
- ->addDefaultsIfNotSet()
- ->children()
- ->variableNode('options')->end()
- ->arrayNode('classes')
- ->addDefaultsIfNotSet()
- ->children()
- ->scalarNode('model')->defaultValue(TaxItem::class)->cannotBeEmpty()->end()
- ->scalarNode('interface')->defaultValue(TaxItemInterface::class)->cannotBeEmpty()->end()
- ->scalarNode('controller')->defaultValue(ResourceController::class)->cannotBeEmpty()->end()
- ->scalarNode('factory')->defaultValue(TaxItemFactory::class)->cannotBeEmpty()->end()
- ->scalarNode('repository')->cannotBeEmpty()->end()
- ->end()
+ ->end()
+ ->arrayNode('tax_item')
+ ->addDefaultsIfNotSet()
+ ->children()
+ ->variableNode('options')->end()
+ ->arrayNode('classes')
+ ->addDefaultsIfNotSet()
+ ->children()
+ ->scalarNode('model')->defaultValue(TaxItem::class)->cannotBeEmpty()->end()
+ ->scalarNode('interface')->defaultValue(TaxItemInterface::class)->cannotBeEmpty()->end()
+ ->scalarNode('controller')->defaultValue(ResourceController::class)->cannotBeEmpty()->end()
+ ->scalarNode('factory')->defaultValue(TaxItemFactory::class)->cannotBeEmpty()->end()
+ ->scalarNode('repository')->cannotBeEmpty()->end()
->end()
->end()
->end()
- ->arrayNode('invoice_sequence')
- ->addDefaultsIfNotSet()
- ->children()
- ->variableNode('options')->end()
- ->arrayNode('classes')
- ->addDefaultsIfNotSet()
- ->children()
- ->scalarNode('model')->defaultValue(InvoiceSequence::class)->cannotBeEmpty()->end()
+ ->end()
+ ->arrayNode('invoice_sequence')
+ ->addDefaultsIfNotSet()
+ ->children()
+ ->variableNode('options')->end()
+ ->arrayNode('classes')
+ ->addDefaultsIfNotSet()
+ ->children()
+ ->scalarNode('model')->defaultValue(InvoiceSequence::class)->cannotBeEmpty()->end()
->scalarNode('interface')->defaultValue(InvoiceSequenceInterface::class)->cannotBeEmpty()->end()
->scalarNode('controller')->defaultValue(ResourceController::class)->cannotBeEmpty()->end()
->scalarNode('factory')->defaultValue(Factory::class)->cannotBeEmpty()->end()
@@ -147,7 +156,22 @@ public function getConfigTreeBuilder(): TreeBuilder
->end()
->end()
;
+ }
- return $treeBuilder;
+ private function addPdfGeneratorSection(ArrayNodeDefinition $node): void
+ {
+ $node
+ ->children()
+ ->arrayNode('pdf_generator')
+ ->addDefaultsIfNotSet()
+ ->children()
+ ->arrayNode('allowed_files')
+ ->useAttributeAsKey('name')
+ ->variablePrototype()->end()
+ ->end()
+ ->end()
+ ->end()
+ ->end()
+ ;
}
}
diff --git a/src/DependencyInjection/SyliusInvoicingExtension.php b/src/DependencyInjection/SyliusInvoicingExtension.php
index 56dc6846..0f95e355 100644
--- a/src/DependencyInjection/SyliusInvoicingExtension.php
+++ b/src/DependencyInjection/SyliusInvoicingExtension.php
@@ -32,6 +32,8 @@ public function load(array $config, ContainerBuilder $container): void
$this->registerResources('sylius_invoicing_plugin', 'doctrine/orm', $config['resources'], $container);
$loader->load('services.xml');
+
+ $container->setParameter('sylius_invoicing.pdf_generator.allowed_files', $config['pdf_generator']['allowed_files']);
}
public function prepend(ContainerBuilder $container): void
diff --git a/src/Generator/InvoicePdfFileGenerator.php b/src/Generator/InvoicePdfFileGenerator.php
index a828e0ee..17fca564 100644
--- a/src/Generator/InvoicePdfFileGenerator.php
+++ b/src/Generator/InvoicePdfFileGenerator.php
@@ -21,32 +21,15 @@
final class InvoicePdfFileGenerator implements InvoicePdfFileGeneratorInterface
{
- private Environment $templatingEngine;
-
- private GeneratorInterface $pdfGenerator;
-
- private FileLocatorInterface $fileLocator;
-
- private InvoiceFileNameGeneratorInterface $invoiceFileNameGenerator;
-
- private string $template;
-
- private string $invoiceLogoPath;
-
public function __construct(
- Environment $templatingEngine,
- GeneratorInterface $pdfGenerator,
- FileLocatorInterface $fileLocator,
- InvoiceFileNameGeneratorInterface $invoiceFileNameGenerator,
- string $template,
- string $invoiceLogoPath
+ private Environment $templatingEngine,
+ private GeneratorInterface $pdfGenerator,
+ private PdfOptionsGeneratorInterface $pdfOptionsGenerator,
+ private FileLocatorInterface $fileLocator,
+ private InvoiceFileNameGeneratorInterface $invoiceFileNameGenerator,
+ private string $template,
+ private string $invoiceLogoPath
) {
- $this->templatingEngine = $templatingEngine;
- $this->pdfGenerator = $pdfGenerator;
- $this->fileLocator = $fileLocator;
- $this->invoiceFileNameGenerator = $invoiceFileNameGenerator;
- $this->template = $template;
- $this->invoiceLogoPath = $invoiceLogoPath;
}
public function generate(InvoiceInterface $invoice): InvoicePdf
@@ -58,7 +41,8 @@ public function generate(InvoiceInterface $invoice): InvoicePdf
'invoice' => $invoice,
'channel' => $invoice->channel(),
'invoiceLogoPath' => $this->fileLocator->locate($this->invoiceLogoPath),
- ])
+ ]),
+ $this->pdfOptionsGenerator->generate()
);
return new InvoicePdf($filename, $pdf);
diff --git a/src/Generator/PdfOptionsGenerator.php b/src/Generator/PdfOptionsGenerator.php
new file mode 100644
index 00000000..ed20ffc6
--- /dev/null
+++ b/src/Generator/PdfOptionsGenerator.php
@@ -0,0 +1,48 @@
+knpSnappyOptions;
+
+ if (empty($this->allowedFiles)) {
+ return $options;
+ }
+
+ if (!isset($options['allow'])) {
+ $options['allow'] = [];
+ } elseif (!is_array($options['allow'])) {
+ $options['allow'] = [$options['allow']];
+ }
+
+ $options['allow'] = array_merge(
+ $options['allow'],
+ array_map(fn ($file) => $this->fileLocator->locate($file), $this->allowedFiles)
+ );
+
+ return $options;
+ }
+}
diff --git a/src/Generator/PdfOptionsGeneratorInterface.php b/src/Generator/PdfOptionsGeneratorInterface.php
new file mode 100644
index 00000000..f88b494b
--- /dev/null
+++ b/src/Generator/PdfOptionsGeneratorInterface.php
@@ -0,0 +1,19 @@
+
+
@SyliusInvoicingPlugin/Invoice/Download/pdf.html.twig
@@ -50,5 +51,11 @@
+
+
+
+ %knp_snappy.pdf.options%
+ %sylius_invoicing.pdf_generator.allowed_files%
+
diff --git a/tests/Application/config/packages/knp_snappy.yaml b/tests/Application/config/packages/knp_snappy.yaml
index 3b277fcd..cb0b804a 100644
--- a/tests/Application/config/packages/knp_snappy.yaml
+++ b/tests/Application/config/packages/knp_snappy.yaml
@@ -2,5 +2,4 @@ knp_snappy:
pdf:
enabled: true
binary: '%env(resolve:WKHTMLTOPDF_PATH)%'
- options:
- enable-local-file-access: true
+ options: []
diff --git a/tests/Unit/DependencyInjection/SyliusInvoicingConfigurationTest.php b/tests/Unit/DependencyInjection/SyliusInvoicingConfigurationTest.php
new file mode 100644
index 00000000..5c48b473
--- /dev/null
+++ b/tests/Unit/DependencyInjection/SyliusInvoicingConfigurationTest.php
@@ -0,0 +1,48 @@
+assertProcessedConfigurationEquals(
+ [[]],
+ ['pdf_generator' => ['allowed_files' => []]],
+ 'pdf_generator'
+ );
+ }
+
+ /** @test */
+ public function it_allows_to_define_allowed_files(): void
+ {
+ $this->assertProcessedConfigurationEquals(
+ [['pdf_generator' => ['allowed_files' => ['swans.png', 'product.png']]]],
+ ['pdf_generator' => ['allowed_files' => ['swans.png', 'product.png']]],
+ 'pdf_generator'
+ );
+ }
+
+ protected function getConfiguration(): Configuration
+ {
+ return new Configuration();
+ }
+}