diff --git a/README.md b/README.md index a115ae25..a3bb7b81 100644 --- a/README.md +++ b/README.md @@ -242,7 +242,8 @@ class YourController `xltx`, `xlw`, `xml`, `xpm`, `zabw` 6. [Merge Builder](./docs/pdf/merge-builder.md) 7. [Convert Builder](./docs/pdf/convert-builder.md) -8. [PDF customization](./docs/pdf/customization.md) (available for every builder except LibreOffice and Merge) +8. [Split Builder](./docs/pdf/split-builder.md) +9. [PDF customization](./docs/pdf/customization.md) (available for every builder except LibreOffice, Merge and Split) #### Screenshot diff --git a/config/builder_pdf.php b/config/builder_pdf.php index 349c960d..33bcd231 100644 --- a/config/builder_pdf.php +++ b/config/builder_pdf.php @@ -5,6 +5,7 @@ use Sensiolabs\GotenbergBundle\Builder\Pdf\LibreOfficePdfBuilder; use Sensiolabs\GotenbergBundle\Builder\Pdf\MarkdownPdfBuilder; use Sensiolabs\GotenbergBundle\Builder\Pdf\MergePdfBuilder; +use Sensiolabs\GotenbergBundle\Builder\Pdf\SplitPdfBuilder; use Sensiolabs\GotenbergBundle\Builder\Pdf\UrlPdfBuilder; use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator; use function Symfony\Component\DependencyInjection\Loader\Configurator\service; @@ -89,4 +90,15 @@ ->call('setLogger', [service('logger')->nullOnInvalid()]) ->tag('sensiolabs_gotenberg.pdf_builder') ; + + $services->set('.sensiolabs_gotenberg.pdf_builder.split', SplitPdfBuilder::class) + ->share(false) + ->args([ + service('sensiolabs_gotenberg.client'), + service('sensiolabs_gotenberg.asset.base_dir_formatter'), + service('.sensiolabs_gotenberg.webhook_configuration_registry'), + ]) + ->call('setLogger', [service('logger')->nullOnInvalid()]) + ->tag('sensiolabs_gotenberg.pdf_builder') + ; }; diff --git a/docs/builders_api.md b/docs/builders_api.md index 30f6e0da..1099d2f2 100644 --- a/docs/builders_api.md +++ b/docs/builders_api.md @@ -8,6 +8,7 @@ * [LibreOfficePdfBuilder](./pdf/builders_api/LibreOfficePdfBuilder.md) * [MergePdfBuilder](./pdf/builders_api/MergePdfBuilder.md) * [ConvertPdfBuilder](./pdf/builders_api/ConvertPdfBuilder.md) +* [SplitPdfBuilder](./pdf/builders_api/SplitPdfBuilder.md) ## Screenshot diff --git a/docs/configuration.md b/docs/configuration.md index 5fc78fda..4bd34c02 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -231,6 +231,15 @@ sensiolabs_gotenberg: # Enable PDF for Universal Access for optimal accessibility - default false. pdf_universal_access: null + # Either intervals or pages. - default None. https://gotenberg.dev/docs/routes#split-chromium + split_mode: null + + # Either the intervals or the page ranges to extract, depending on the selected mode. - default None. https://gotenberg.dev/docs/routes#split-chromium + split_span: null + + # Specify whether to put extracted pages into a single file or as many files as there are page ranges. Only works with pages mode. - default false. https://gotenberg.dev/docs/routes#split-chromium + split_unify: null + # Webhook configuration name or definition. webhook: @@ -419,6 +428,15 @@ sensiolabs_gotenberg: # Enable PDF for Universal Access for optimal accessibility - default false. pdf_universal_access: null + # Either intervals or pages. - default None. https://gotenberg.dev/docs/routes#split-chromium + split_mode: null + + # Either the intervals or the page ranges to extract, depending on the selected mode. - default None. https://gotenberg.dev/docs/routes#split-chromium + split_span: null + + # Specify whether to put extracted pages into a single file or as many files as there are page ranges. Only works with pages mode. - default false. https://gotenberg.dev/docs/routes#split-chromium + split_unify: null + # Webhook configuration name or definition. webhook: @@ -607,6 +625,15 @@ sensiolabs_gotenberg: # Enable PDF for Universal Access for optimal accessibility - default false. pdf_universal_access: null + # Either intervals or pages. - default None. https://gotenberg.dev/docs/routes#split-chromium + split_mode: null + + # Either the intervals or the page ranges to extract, depending on the selected mode. - default None. https://gotenberg.dev/docs/routes#split-chromium + split_span: null + + # Specify whether to put extracted pages into a single file or as many files as there are page ranges. Only works with pages mode. - default false. https://gotenberg.dev/docs/routes#split-chromium + split_unify: null + # Webhook configuration name or definition. webhook: @@ -755,6 +782,15 @@ sensiolabs_gotenberg: # Enable PDF for Universal Access for optimal accessibility - default false. pdf_universal_access: null + + # Either intervals or pages. - default None. https://gotenberg.dev/docs/routes#split-libreoffice + split_mode: null + + # Either the intervals or the page ranges to extract, depending on the selected mode. - default None. https://gotenberg.dev/docs/routes#split-libreoffice + split_span: null + + # Specify whether to put extracted pages into a single file or as many files as there are page ranges. Only works with pages mode. - default false. https://gotenberg.dev/docs/routes#split-libreoffice + split_unify: null merge: # Convert PDF into the given PDF/A format - default None. @@ -810,6 +846,15 @@ sensiolabs_gotenberg: name: name: ~ value: ~ + split: + # Either intervals or pages. - default None. https://gotenberg.dev/docs/routes#split-libreoffice + split_mode: null + + # Either the intervals or the page ranges to extract, depending on the selected mode. - default None. https://gotenberg.dev/docs/routes#split-libreoffice + split_span: null + + # Specify whether to put extracted pages into a single file or as many files as there are page ranges. Only works with pages mode. - default false. https://gotenberg.dev/docs/routes#split-libreoffice + split_unify: null screenshot: html: diff --git a/docs/generate.php b/docs/generate.php index 3e1075e1..030e3ee4 100755 --- a/docs/generate.php +++ b/docs/generate.php @@ -6,6 +6,7 @@ use Sensiolabs\GotenbergBundle\Builder\Pdf\LibreOfficePdfBuilder; use Sensiolabs\GotenbergBundle\Builder\Pdf\MarkdownPdfBuilder; use Sensiolabs\GotenbergBundle\Builder\Pdf\MergePdfBuilder; +use Sensiolabs\GotenbergBundle\Builder\Pdf\SplitPdfBuilder; use Sensiolabs\GotenbergBundle\Builder\Pdf\UrlPdfBuilder; use Sensiolabs\GotenbergBundle\Builder\Screenshot\HtmlScreenshotBuilder; use Sensiolabs\GotenbergBundle\Builder\Screenshot\MarkdownScreenshotBuilder; @@ -27,6 +28,7 @@ LibreOfficePdfBuilder::class, MergePdfBuilder::class, ConvertPdfBuilder::class, + SplitPdfBuilder::class, ], 'screenshot' => [ HtmlScreenshotBuilder::class, diff --git a/docs/pdf/builders_api/HtmlPdfBuilder.md b/docs/pdf/builders_api/HtmlPdfBuilder.md index 541c68c6..5161d58d 100644 --- a/docs/pdf/builders_api/HtmlPdfBuilder.md +++ b/docs/pdf/builders_api/HtmlPdfBuilder.md @@ -138,6 +138,15 @@ Resets the metadata. * `addMetadata(string $key, string $value)`: The metadata to write. +* `splitMode(?Sensiolabs\GotenbergBundle\Enumeration\SplitMode $splitMode)`: +Either intervals or pages. (default None). + +* `splitSpan(string $splitSpan)`: +Either the intervals or the page ranges to extract, depending on the selected mode. (default None). + +* `splitUnify(bool $bool)`: +Specify whether to put extracted pages into a single file or as many files as there are page ranges. Only works with pages mode. (default false). + * `downloadFrom(array $downloadFrom)`: * `webhookConfiguration(string $name)`: diff --git a/docs/pdf/builders_api/LibreOfficePdfBuilder.md b/docs/pdf/builders_api/LibreOfficePdfBuilder.md index d4570045..244296a9 100644 --- a/docs/pdf/builders_api/LibreOfficePdfBuilder.md +++ b/docs/pdf/builders_api/LibreOfficePdfBuilder.md @@ -85,6 +85,15 @@ Specify if the resolution of each image is reduced to the resolution specified b * `maxImageResolution(Sensiolabs\GotenbergBundle\Enumeration\ImageResolutionDPI $resolution)`: If the form field reduceImageResolution is set to true, tell if all images will be reduced to the given value in DPI. Possible values are: 75, 150, 300, 600 and 1200. +* `splitMode(?Sensiolabs\GotenbergBundle\Enumeration\SplitMode $splitMode)`: +Either intervals or pages. (default None). + +* `splitSpan(string $splitSpan)`: +Either the intervals or the page ranges to extract, depending on the selected mode. (default None). + +* `splitUnify(bool $bool)`: +Specify whether to put extracted pages into a single file or as many files as there are page ranges. Only works with pages mode. (default false). + * `downloadFrom(array $downloadFrom)`: * `webhookConfiguration(string $name)`: diff --git a/docs/pdf/builders_api/MarkdownPdfBuilder.md b/docs/pdf/builders_api/MarkdownPdfBuilder.md index 4f07a4c5..7af5eba4 100644 --- a/docs/pdf/builders_api/MarkdownPdfBuilder.md +++ b/docs/pdf/builders_api/MarkdownPdfBuilder.md @@ -141,6 +141,15 @@ Resets the metadata. * `addMetadata(string $key, string $value)`: The metadata to write. +* `splitMode(?Sensiolabs\GotenbergBundle\Enumeration\SplitMode $splitMode)`: +Either intervals or pages. (default None). + +* `splitSpan(string $splitSpan)`: +Either the intervals or the page ranges to extract, depending on the selected mode. (default None). + +* `splitUnify(bool $bool)`: +Specify whether to put extracted pages into a single file or as many files as there are page ranges. Only works with pages mode. (default false). + * `downloadFrom(array $downloadFrom)`: * `webhookConfiguration(string $name)`: diff --git a/docs/pdf/builders_api/SplitPdfBuilder.md b/docs/pdf/builders_api/SplitPdfBuilder.md new file mode 100644 index 00000000..8a5e3b4d --- /dev/null +++ b/docs/pdf/builders_api/SplitPdfBuilder.md @@ -0,0 +1,31 @@ +# SplitPdfBuilder + +Split `n` pdf files. + +* `splitMode(?Sensiolabs\GotenbergBundle\Enumeration\SplitMode $splitMode)`: +Either intervals or pages. (default None). + +* `splitSpan(string $splitSpan)`: +Either the intervals or the page ranges to extract, depending on the selected mode. (default None). + +* `splitUnify(bool $bool)`: +Specify whether to put extracted pages into a single file or as many files as there are page ranges. Only works with pages mode. (default false). + +* `files(string $paths)`: + +* `downloadFrom(array $downloadFrom)`: + +* `webhookConfiguration(string $name)`: +Providing an existing $name from the configuration file, it will correctly set both success and error webhook URLs as well as extra_http_headers if defined. + +* `webhookUrl(string $url, ?string $method)`: +Sets the webhook for cases of success. +Optionaly sets a custom HTTP method for such endpoint among : POST, PUT or PATCH. + +* `errorWebhookUrl(?string $url, ?string $method)`: +Sets the webhook for cases of error. +Optionaly sets a custom HTTP method for such endpoint among : POST, PUT or PATCH. + +* `webhookExtraHeaders(array $extraHeaders)`: +Extra headers that will be provided to the webhook endpoint. May it either be Success or Error. + diff --git a/docs/pdf/builders_api/UrlPdfBuilder.md b/docs/pdf/builders_api/UrlPdfBuilder.md index c1967c40..38b66391 100644 --- a/docs/pdf/builders_api/UrlPdfBuilder.md +++ b/docs/pdf/builders_api/UrlPdfBuilder.md @@ -140,6 +140,15 @@ Resets the metadata. * `addMetadata(string $key, string $value)`: The metadata to write. +* `splitMode(?Sensiolabs\GotenbergBundle\Enumeration\SplitMode $splitMode)`: +Either intervals or pages. (default None). + +* `splitSpan(string $splitSpan)`: +Either the intervals or the page ranges to extract, depending on the selected mode. (default None). + +* `splitUnify(bool $bool)`: +Specify whether to put extracted pages into a single file or as many files as there are page ranges. Only works with pages mode. (default false). + * `downloadFrom(array $downloadFrom)`: * `webhookConfiguration(string $name)`: diff --git a/docs/pdf/customization.md b/docs/pdf/customization.md index d0341b58..6126a2b2 100644 --- a/docs/pdf/customization.md +++ b/docs/pdf/customization.md @@ -23,6 +23,9 @@ [landscape](#landscape) [scale](#scale) [nativePageRanges](#nativePageRanges) +[splitMode](#splitMode) +[splitSpan](#splitSpan) +[splitUnify](#splitUnify) ### Additional content [header and footer](#header-and-footer) @@ -424,6 +427,96 @@ class YourController } } ``` + +## splitMode + +default: `None` + +Either `intervals` or `pages`. + +```php +namespace App\Controller; + +use Sensiolabs\GotenbergBundle\Enum\SplitMode; +use Sensiolabs\GotenbergBundle\GotenbergPdfInterface; + +class YourController +{ + public function yourControllerMethod(GotenbergPdfInterface $gotenberg): Response + { + return $gotenberg->html() + ->content('content.html.twig', [ + 'my_var' => 'value' + ]) + ->splitMode(SplitMode::Intervals) + ->splitSpan('1') + ->generate() + ->stream() + ; + } +} +``` + +## splitSpan + +default: `None` + +Either the intervals or the page ranges to extract, depending on the selected `splitMode`. + +```php +namespace App\Controller; + +use Sensiolabs\GotenbergBundle\Enumeration\SplitMode; +use Sensiolabs\GotenbergBundle\GotenbergPdfInterface; + +class YourController +{ + public function yourControllerMethod(GotenbergPdfInterface $gotenberg): Response + { + return $gotenberg->html() + ->content('content.html.twig', [ + 'my_var' => 'value' + ])) + ->splitMode(SplitMode::Intervals) + ->splitSpan('1') + ->generate() + ->stream() + ; + } +} +``` + +## splitUnify + +Default: `false` + +Specify whether to put extracted pages into a single file or as many files as +there are page ranges. Only works with `pages` mode. + +```php +namespace App\Controller; + +use Sensiolabs\GotenbergBundle\Enum\SplitMode; +use Sensiolabs\GotenbergBundle\GotenbergPdfInterface; + +class YourController +{ + public function yourControllerMethod(GotenbergPdfInterface $gotenberg): Response + { + return $gotenberg->html() + ->content('content.html.twig', [ + 'my_var' => 'value' + ]) + ->splitMode(SplitMode::Pages) + ->splitSpan('1-2') + ->splitUnify() // is same as ->splitUnify(true) + ->generate() + ->stream() + ; + } +} +``` + ## Additional content > [!WARNING] diff --git a/docs/pdf/office-builder.md b/docs/pdf/office-builder.md index 0b8fe11c..b7a05070 100644 --- a/docs/pdf/office-builder.md +++ b/docs/pdf/office-builder.md @@ -61,7 +61,50 @@ class YourController } ``` -## merge +## Available functions + +### Render +[merge](#merge) +[landscape](#landscape) +[nativePageRanges](#nativePageRanges) +[singlePageSheets](#singlePageSheets) +[skipEmptyPages](#skipEmptyPages) +[losslessImageCompression](#losslessImageCompression) +[quality](#quality) +[reduceImageResolution](#reduceImageResolution) +[maxImageResolution](#maxImageResolution) +[splitMode](#splitMode) +[splitSpan](#splitSpan) +[splitUnify](#splitUnify) + +### Additional content +[doNotExportFormFields](#doNotExportFormFields) +[allowDuplicateFieldNames](#allowDuplicateFieldNames) +[doNotExportBookmarks](#doNotExportBookmarks) +[exportBookmarksToPdfDestination](#exportBookmarksToPdfDestination) +[exportPlaceholders](#exportPlaceholders) +[exportNotes](#exportNotes) +[exportNotesPages](#exportNotesPages) +[exportOnlyNotesPages](#exportOnlyNotesPages) +[exportNotesInMargin](#exportNotesInMargin) +[exportLinksRelativeFsys](#exportLinksRelativeFsys) +[exportHiddenSlides](#exportHiddenSlides) +[addOriginalDocumentAsStream](#addOriginalDocumentAsStream) +[download from](#download-from) + +### Formatting +[metadata](#metadata) +[addMetadata](#addMetadata) +[pdfFormat](#pdfFormat) +[pdfUniversalAccess](#pdfUniversalAccess) +[convertOooTargetToPdfTarget](#convertOooTargetToPdfTarget) + +### Security +[password](#password) + +## Render + +### merge Default: `false` @@ -89,7 +132,7 @@ class YourController > [!TIP] > For more information go to [Gotenberg documentations](https://gotenberg.dev/docs/routes#merge-libreoffice). -## landscape +### landscape Default: `false` @@ -117,7 +160,7 @@ class YourController > [!TIP] > For more information go to [Gotenberg documentations](https://gotenberg.dev/docs/routes#page-properties-libreoffice). -## nativePageRanges +### nativePageRanges Default: `All pages generated` @@ -145,12 +188,11 @@ class YourController > [!TIP] > For more information go to [Gotenberg documentations](https://gotenberg.dev/docs/routes#page-properties-libreoffice). -## doNotExportFormFields +### singlePageSheets -Default: `true` +Default: `false` -Set whether to export the form fields or to use the inputted/selected content -of the fields. +Set whether to render the entire spreadsheet as a single page. ```php namespace App\Controller; @@ -163,7 +205,7 @@ class YourController { return $gotenberg->office() ->files('document.txt') - ->doNotExportFormFields() // is same as `->doNotExportFormFields(false)` + ->singlePageSheets() // is same as `->singlePageSheets(true)` ->generate() ->stream() ; @@ -174,11 +216,11 @@ class YourController > [!TIP] > For more information go to [Gotenberg documentations](https://gotenberg.dev/docs/routes#page-properties-libreoffice). -## singlePageSheets +### skipEmptyPages Default: `false` -Set whether to render the entire spreadsheet as a single page. +Specify that automatically inserted empty pages are suppressed. This option is active only if storing Writer documents. ```php namespace App\Controller; @@ -191,9 +233,8 @@ class YourController { return $gotenberg->office() ->files('document.txt') - ->singlePageSheets() // is same as `->singlePageSheets(true)` + ->skipEmptyPages() // is same as `->skipEmptyPages(true)` ->generate() - ->stream() ; } } @@ -202,16 +243,16 @@ class YourController > [!TIP] > For more information go to [Gotenberg documentations](https://gotenberg.dev/docs/routes#page-properties-libreoffice). -## pdfFormat +### losslessImageCompression -Default: `None` +Default: `false` -Convert the resulting PDF into the given PDF/A format. +Specify if images are exported to PDF using a lossless compression format like PNG or compressed using the JPEG format. ```php namespace App\Controller; -use Sensiolabs\GotenbergBundle\Enum\PdfFormat;use Sensiolabs\GotenbergBundle\GotenbergPdfInterface; +use Sensiolabs\GotenbergBundle\GotenbergPdfInterface; class YourController { @@ -219,27 +260,53 @@ class YourController { return $gotenberg->office() ->files('document.txt') - ->pdfFormat(PdfFormat::Pdf1b) + ->losslessImageCompression() // is same as `->losslessImageCompression(true)` ->generate() - ->stream() ; } } ``` > [!TIP] -> For more information go to [Gotenberg documentations](https://gotenberg.dev/docs/routes#pdfa-libreoffice). +> For more information go to [Gotenberg documentations](https://gotenberg.dev/docs/routes#images-libreoffice). -## pdfUniversalAccess +### quality + +Default: `90` + +Specify the quality of the JPG export. A higher value produces a higher-quality image and a larger file. Between 1 and 100. + +```php +namespace App\Controller; + +use Sensiolabs\GotenbergBundle\GotenbergPdfInterface; + +class YourController +{ + public function yourControllerMethod(GotenbergPdfInterface $gotenberg): Response + { + return $gotenberg->office() + ->files('document.txt') + ->quality(75) + ->generate() + ; + } +} +``` + +> [!TIP] +> For more information go to [Gotenberg documentations](https://gotenberg.dev/docs/routes#images-libreoffice). + +### reduceImageResolution Default: `false` -Enable PDF for Universal Access for optimal accessibility. +Specify if the resolution of each image is reduced to the resolution specified by the form field maxImageResolution. ```php namespace App\Controller; -use Sensiolabs\GotenbergBundle\Enum\PdfFormat;use Sensiolabs\GotenbergBundle\GotenbergPdfInterface; +use Sensiolabs\GotenbergBundle\GotenbergPdfInterface; class YourController { @@ -247,27 +314,27 @@ class YourController { return $gotenberg->office() ->files('document.txt') - ->pdfUniversalAccess() // is same as `->pdfUniversalAccess(true)` + ->reduceImageResolution() // is same as `->reduceImageResolution(true)` ->generate() - ->stream() ; } } ``` > [!TIP] -> For more information go to [Gotenberg documentations](https://gotenberg.dev/docs/routes#pdfa-libreoffice). +> For more information go to [Gotenberg documentations](https://gotenberg.dev/docs/routes#images-libreoffice). -## metatada +### maxImageResolution -Default: `None` +Default: `300` -Resets the configuration metadata and add new ones to write. +If the form field reduceImageResolution is set to true, tell if all images will be reduced to the given value in DPI. Possible values are: 75, 150, 300, 600 and 1200. ```php namespace App\Controller; -use Sensiolabs\GotenbergBundle\Enum\PdfFormat;use Sensiolabs\GotenbergBundle\GotenbergPdfInterface; +use Sensiolabs\GotenbergBundle\Enumeration\ImageResolutionDPI; +use Sensiolabs\GotenbergBundle\GotenbergPdfInterface; class YourController { @@ -275,24 +342,27 @@ class YourController { return $gotenberg->office() ->files('document.txt') - ->metadata(['Author' => 'SensioLabs', 'Subject' => 'Gotenberg']) + ->maxImageResolution(ImageResolutionDPI::DPI300) ->generate() - ->stream() ; } } ``` -## addMetadata +> [!TIP] +> For more information go to [Gotenberg documentations](https://gotenberg.dev/docs/routes#images-libreoffice). -Default: `None` +### splitMode -If you want to add metadata from the ones already loaded in the configuration. +default: `None` + +Either `intervals` or `pages`. ```php namespace App\Controller; -use Sensiolabs\GotenbergBundle\Enum\PdfFormat;use Sensiolabs\GotenbergBundle\GotenbergPdfInterface; +use Sensiolabs\GotenbergBundle\Enum\SplitMode; +use Sensiolabs\GotenbergBundle\GotenbergPdfInterface; class YourController { @@ -300,7 +370,8 @@ class YourController { return $gotenberg->office() ->files('document.txt') - ->addMetadata('key', 'value') + ->splitMode(SplitMode::Intervals) + ->splitSpan('1') ->generate() ->stream() ; @@ -309,17 +380,46 @@ class YourController ``` > [!TIP] -> For more information go to [Gotenberg documentations](https://gotenberg.dev/docs/routes#metadata-libreoffice). +> For more information go to [Gotenberg documentations](https://gotenberg.dev/docs/routes#split-libreoffice). + +### splitSpan + +default: `None` + +Either the intervals or the page ranges to extract, depending on the selected `splitMode`. + +```php +namespace App\Controller; + +use Sensiolabs\GotenbergBundle\Enumeration\SplitMode; +use Sensiolabs\GotenbergBundle\GotenbergPdfInterface; + +class YourController +{ + public function yourControllerMethod(GotenbergPdfInterface $gotenberg): Response + { + return $gotenberg->office() + ->files('document.txt') + ->splitMode(SplitMode::Intervals) + ->splitSpan('1') + ->generate() + ->stream() + ; + } +} +``` -## allowDuplicateFieldNames +### splitUnify Default: `false` -Specify whether multiple form fields exported are allowed to have the same field name. +Specify whether to put extracted pages into a single file or as many files as +there are page ranges. Only works with `pages` mode. ```php namespace App\Controller; +use Sensiolabs\GotenbergBundle\Enum\SplitMode; use Sensiolabs\GotenbergBundle\GotenbergPdfInterface; class YourController @@ -328,21 +428,24 @@ class YourController { return $gotenberg->office() ->files('document.txt') - ->allowDuplicateFieldNames() // is same as `->allowDuplicateFieldNames(true)` + ->splitMode(SplitMode::Pages) + ->splitSpan('1-2') + ->splitUnify() // is same as ->splitUnify(true) ->generate() + ->stream() ; } } ``` -> [!TIP] -> For more information go to [Gotenberg documentations](https://gotenberg.dev/docs/routes#page-properties-libreoffice). +## Additional content -## doNotExportBookmarks +### doNotExportFormFields Default: `true` -Specify if bookmarks are exported to PDF. +Set whether to export the form fields or to use the inputted/selected content +of the fields. ```php namespace App\Controller; @@ -355,8 +458,9 @@ class YourController { return $gotenberg->office() ->files('document.txt') - ->doNotExportBookmarks() // is same as `->doNotExportBookmarks(false)` + ->doNotExportFormFields() // is same as `->doNotExportFormFields(false)` ->generate() + ->stream() ; } } @@ -365,11 +469,11 @@ class YourController > [!TIP] > For more information go to [Gotenberg documentations](https://gotenberg.dev/docs/routes#page-properties-libreoffice). -## exportBookmarksToPdfDestination +### allowDuplicateFieldNames Default: `false` -Specify that the bookmarks contained in the source LibreOffice file should be exported to the PDF file as Named Destination. +Specify whether multiple form fields exported are allowed to have the same field name. ```php namespace App\Controller; @@ -382,7 +486,7 @@ class YourController { return $gotenberg->office() ->files('document.txt') - ->exportBookmarksToPdfDestination() // is same as `->exportBookmarksToPdfDestination(true)` + ->allowDuplicateFieldNames() // is same as `->allowDuplicateFieldNames(true)` ->generate() ; } @@ -392,11 +496,11 @@ class YourController > [!TIP] > For more information go to [Gotenberg documentations](https://gotenberg.dev/docs/routes#page-properties-libreoffice). -## exportPlaceholders +### doNotExportBookmarks -Default: `false` +Default: `true` -Export the placeholders fields visual markings only. The exported placeholder is ineffective. +Specify if bookmarks are exported to PDF. ```php namespace App\Controller; @@ -409,7 +513,7 @@ class YourController { return $gotenberg->office() ->files('document.txt') - ->exportPlaceholders() // is same as `->exportPlaceholders(true)` + ->doNotExportBookmarks() // is same as `->doNotExportBookmarks(false)` ->generate() ; } @@ -419,11 +523,11 @@ class YourController > [!TIP] > For more information go to [Gotenberg documentations](https://gotenberg.dev/docs/routes#page-properties-libreoffice). -## exportNotes +### exportBookmarksToPdfDestination Default: `false` -Specify if notes are exported to PDF. +Specify that the bookmarks contained in the source LibreOffice file should be exported to the PDF file as Named Destination. ```php namespace App\Controller; @@ -436,7 +540,7 @@ class YourController { return $gotenberg->office() ->files('document.txt') - ->exportNotes() // is same as `->exportNotes(true)` + ->exportBookmarksToPdfDestination() // is same as `->exportBookmarksToPdfDestination(true)` ->generate() ; } @@ -446,11 +550,11 @@ class YourController > [!TIP] > For more information go to [Gotenberg documentations](https://gotenberg.dev/docs/routes#page-properties-libreoffice). -## exportNotesPages +### exportPlaceholders Default: `false` -Specify if notes pages are exported to PDF. Notes pages are available in Impress documents only. +Export the placeholders fields visual markings only. The exported placeholder is ineffective. ```php namespace App\Controller; @@ -463,7 +567,7 @@ class YourController { return $gotenberg->office() ->files('document.txt') - ->exportNotesPages() // is same as `->exportNotesPages(true)` + ->exportPlaceholders() // is same as `->exportPlaceholders(true)` ->generate() ; } @@ -473,11 +577,11 @@ class YourController > [!TIP] > For more information go to [Gotenberg documentations](https://gotenberg.dev/docs/routes#page-properties-libreoffice). -## exportOnlyNotesPages +### exportNotes Default: `false` -Specify, if the form field exportNotesPages is set to true, if only notes pages are exported to PDF. +Specify if notes are exported to PDF. ```php namespace App\Controller; @@ -490,7 +594,7 @@ class YourController { return $gotenberg->office() ->files('document.txt') - ->exportOnlyNotesPages() // is same as `->exportOnlyNotesPages(true)` + ->exportNotes() // is same as `->exportNotes(true)` ->generate() ; } @@ -500,11 +604,11 @@ class YourController > [!TIP] > For more information go to [Gotenberg documentations](https://gotenberg.dev/docs/routes#page-properties-libreoffice). -## exportNotesInMargin +### exportNotesPages Default: `false` -Specify if notes in margin are exported to PDF. +Specify if notes pages are exported to PDF. Notes pages are available in Impress documents only. ```php namespace App\Controller; @@ -517,7 +621,7 @@ class YourController { return $gotenberg->office() ->files('document.txt') - ->exportNotesInMargin() // is same as `->exportNotesInMargin(true)` + ->exportNotesPages() // is same as `->exportNotesPages(true)` ->generate() ; } @@ -527,11 +631,11 @@ class YourController > [!TIP] > For more information go to [Gotenberg documentations](https://gotenberg.dev/docs/routes#page-properties-libreoffice). -## convertOooTargetToPdfTarget +### exportOnlyNotesPages Default: `false` -Specify that the target documents with .od[tpgs] extension, will have that extension changed to .pdf when the link is exported to PDF. The source document remains untouched. +Specify, if the form field exportNotesPages is set to true, if only notes pages are exported to PDF. ```php namespace App\Controller; @@ -544,7 +648,7 @@ class YourController { return $gotenberg->office() ->files('document.txt') - ->convertOooTargetToPdfTarget() // is same as `->convertOooTargetToPdfTarget(true)` + ->exportOnlyNotesPages() // is same as `->exportOnlyNotesPages(true)` ->generate() ; } @@ -554,11 +658,11 @@ class YourController > [!TIP] > For more information go to [Gotenberg documentations](https://gotenberg.dev/docs/routes#page-properties-libreoffice). -## exportLinksRelativeFsys +### exportNotesInMargin Default: `false` -Specify that the file system related hyperlinks (file:// protocol) present in the document will be exported as relative to the source document location. +Specify if notes in margin are exported to PDF. ```php namespace App\Controller; @@ -571,7 +675,7 @@ class YourController { return $gotenberg->office() ->files('document.txt') - ->exportLinksRelativeFsys() // is same as `->exportLinksRelativeFsys(true)` + ->exportNotesInMargin() // is same as `->exportNotesInMargin(true)` ->generate() ; } @@ -581,11 +685,11 @@ class YourController > [!TIP] > For more information go to [Gotenberg documentations](https://gotenberg.dev/docs/routes#page-properties-libreoffice). -## exportHiddenSlides +### exportLinksRelativeFsys Default: `false` -Export, for LibreOffice Impress, slides that are not included in slide shows. +Specify that the file system related hyperlinks (file:// protocol) present in the document will be exported as relative to the source document location. ```php namespace App\Controller; @@ -598,7 +702,7 @@ class YourController { return $gotenberg->office() ->files('document.txt') - ->exportHiddenSlides() // is same as `->exportHiddenSlides(true)` + ->exportLinksRelativeFsys() // is same as `->exportLinksRelativeFsys(true)` ->generate() ; } @@ -608,11 +712,11 @@ class YourController > [!TIP] > For more information go to [Gotenberg documentations](https://gotenberg.dev/docs/routes#page-properties-libreoffice). -## skipEmptyPages +### exportHiddenSlides Default: `false` -Specify that automatically inserted empty pages are suppressed. This option is active only if storing Writer documents. +Export, for LibreOffice Impress, slides that are not included in slide shows. ```php namespace App\Controller; @@ -625,7 +729,7 @@ class YourController { return $gotenberg->office() ->files('document.txt') - ->skipEmptyPages() // is same as `->skipEmptyPages(true)` + ->exportHiddenSlides() // is same as `->exportHiddenSlides(true)` ->generate() ; } @@ -635,7 +739,7 @@ class YourController > [!TIP] > For more information go to [Gotenberg documentations](https://gotenberg.dev/docs/routes#page-properties-libreoffice). -## addOriginalDocumentAsStream +### addOriginalDocumentAsStream Default: `false` @@ -662,43 +766,88 @@ class YourController > [!TIP] > For more information go to [Gotenberg documentations](https://gotenberg.dev/docs/routes#page-properties-libreoffice). -## losslessImageCompression +### download from -Default: `false` +> [!WARNING] +> URL of the file. It MUST return a `Content-Disposition` header with a filename parameter. -Specify if images are exported to PDF using a lossless compression format like PNG or compressed using the JPEG format. +To download files resource from URLs. ```php namespace App\Controller; use Sensiolabs\GotenbergBundle\GotenbergPdfInterface; +class YourController +{ + public function yourControllerMethod(GotenbergPdfInterface $gotenberg): Response + { + return $gotenberg + ->office() + ->downloadFrom([ + [ + 'url' => 'http://url/to/file.com', + 'extraHttpHeaders' => + [ + 'MyHeader' => 'MyValue', + ], + ], + [ + 'url' => 'http://url/to/file.com', + 'extraHttpHeaders' => + [ + 'MyHeaderOne' => 'MyValue', + 'MyHeaderTwo' => 'MyValue', + ], + ], + ]) + ->generate() + ->stream() + ; + } +} +``` + +> [!TIP] +> For more information go to [Gotenberg documentations](https://gotenberg.dev/docs/routes#download-from). + +## Formatting + +### metadata + +Default: `None` + +Resets the configuration metadata and add new ones to write. + +```php +namespace App\Controller; + +use Sensiolabs\GotenbergBundle\Enum\PdfFormat;use Sensiolabs\GotenbergBundle\GotenbergPdfInterface; + class YourController { public function yourControllerMethod(GotenbergPdfInterface $gotenberg): Response { return $gotenberg->office() ->files('document.txt') - ->losslessImageCompression() // is same as `->losslessImageCompression(true)` + ->metadata(['Author' => 'SensioLabs', 'Subject' => 'Gotenberg']) ->generate() + ->stream() ; } } ``` -> [!TIP] -> For more information go to [Gotenberg documentations](https://gotenberg.dev/docs/routes#images-libreoffice). - -## quality +### addMetadata -Default: `90` +Default: `None` -Specify the quality of the JPG export. A higher value produces a higher-quality image and a larger file. Between 1 and 100. +If you want to add metadata from the ones already loaded in the configuration. ```php namespace App\Controller; -use Sensiolabs\GotenbergBundle\GotenbergPdfInterface; +use Sensiolabs\GotenbergBundle\Enum\PdfFormat;use Sensiolabs\GotenbergBundle\GotenbergPdfInterface; class YourController { @@ -706,26 +855,27 @@ class YourController { return $gotenberg->office() ->files('document.txt') - ->quality(75) + ->addMetadata('key', 'value') ->generate() + ->stream() ; } } ``` > [!TIP] -> For more information go to [Gotenberg documentations](https://gotenberg.dev/docs/routes#images-libreoffice). +> For more information go to [Gotenberg documentations](https://gotenberg.dev/docs/routes#metadata-libreoffice). -## reduceImageResolution +### pdfFormat -Default: `false` +Default: `None` -Specify if the resolution of each image is reduced to the resolution specified by the form field maxImageResolution. +Convert the resulting PDF into the given PDF/A format. ```php namespace App\Controller; -use Sensiolabs\GotenbergBundle\GotenbergPdfInterface; +use Sensiolabs\GotenbergBundle\Enum\PdfFormat;use Sensiolabs\GotenbergBundle\GotenbergPdfInterface; class YourController { @@ -733,27 +883,27 @@ class YourController { return $gotenberg->office() ->files('document.txt') - ->reduceImageResolution() // is same as `->reduceImageResolution(true)` + ->pdfFormat(PdfFormat::Pdf1b) ->generate() + ->stream() ; } } ``` > [!TIP] -> For more information go to [Gotenberg documentations](https://gotenberg.dev/docs/routes#images-libreoffice). +> For more information go to [Gotenberg documentations](https://gotenberg.dev/docs/routes#pdfa-libreoffice). -## maxImageResolution +### pdfUniversalAccess -Default: `300` +Default: `false` -If the form field reduceImageResolution is set to true, tell if all images will be reduced to the given value in DPI. Possible values are: 75, 150, 300, 600 and 1200. +Enable PDF for Universal Access for optimal accessibility. ```php namespace App\Controller; -use Sensiolabs\GotenbergBundle\Enumeration\ImageResolutionDPI; -use Sensiolabs\GotenbergBundle\GotenbergPdfInterface; +use Sensiolabs\GotenbergBundle\Enum\PdfFormat;use Sensiolabs\GotenbergBundle\GotenbergPdfInterface; class YourController { @@ -761,22 +911,22 @@ class YourController { return $gotenberg->office() ->files('document.txt') - ->maxImageResolution(ImageResolutionDPI::DPI300) + ->pdfUniversalAccess() // is same as `->pdfUniversalAccess(true)` ->generate() + ->stream() ; } } ``` > [!TIP] -> For more information go to [Gotenberg documentations](https://gotenberg.dev/docs/routes#images-libreoffice). +> For more information go to [Gotenberg documentations](https://gotenberg.dev/docs/routes#pdfa-libreoffice). -### download from +### convertOooTargetToPdfTarget -> [!WARNING] -> URL of the file. It MUST return a `Content-Disposition` header with a filename parameter. +Default: `false` -To download files resource from URLs. +Specify that the target documents with .od[tpgs] extension, will have that extension changed to .pdf when the link is exported to PDF. The source document remains untouched. ```php namespace App\Controller; @@ -787,36 +937,21 @@ class YourController { public function yourControllerMethod(GotenbergPdfInterface $gotenberg): Response { - return $gotenberg - ->office() - ->downloadFrom([ - [ - 'url' => 'http://url/to/file.com', - 'extraHttpHeaders' => - [ - 'MyHeader' => 'MyValue', - ], - ], - [ - 'url' => 'http://url/to/file.com', - 'extraHttpHeaders' => - [ - 'MyHeaderOne' => 'MyValue', - 'MyHeaderTwo' => 'MyValue', - ], - ], - ]) + return $gotenberg->office() + ->files('document.txt') + ->convertOooTargetToPdfTarget() // is same as `->convertOooTargetToPdfTarget(true)` ->generate() - ->stream() - ; + ; } } ``` > [!TIP] -> For more information go to [Gotenberg documentations](https://gotenberg.dev/docs/routes#download-from). +> For more information go to [Gotenberg documentations](https://gotenberg.dev/docs/routes#page-properties-libreoffice). + +## Security -## password +### password Default: `None` diff --git a/docs/pdf/split-builder.md b/docs/pdf/split-builder.md new file mode 100644 index 00000000..aba8b31d --- /dev/null +++ b/docs/pdf/split-builder.md @@ -0,0 +1,125 @@ +# Split Builder + +You may have the possibility to split several PDF pages or documents. + +## Basic usage + +> [!WARNING] +> As assets files, by default the PDF files are fetch in the assets folder of +> your application. +> For more information about path resolution go to [assets documentation](../assets.md). + +```php +namespace App\Controller; + +use Sensiolabs\GotenbergBundle\GotenbergPdfInterface; + +class YourController +{ + public function yourControllerMethod(GotenbergPdfInterface $gotenberg): Response + { + return $gotenberg->split() + ->files( + 'document_1.pdf', + 'document_2.pdf', + ) + ->splitMode(SplitMode::Pages) + ->splitSpan('1-2') + ->splitUnify() + ->generate() + ->stream() + ; + } +} +``` + +> [!TIP] +> For more information go to [Gotenberg documentations](https://gotenberg.dev/docs/routes#split-pdfs-route). + +## splitMode + +> [!WARNING] +> Required + +Either `intervals` or `pages`. + +```php +namespace App\Controller; + +use Sensiolabs\GotenbergBundle\Enum\SplitMode; +use Sensiolabs\GotenbergBundle\GotenbergPdfInterface; + +class YourController +{ + public function yourControllerMethod(GotenbergPdfInterface $gotenberg): Response + { + return $gotenberg->split() + ->files( + 'document_1.pdf', + 'document_2.pdf', + ) + ->splitMode(SplitMode::Intervals) + ->splitSpan('1') + ->generate() + ->stream() + ; + } +} +``` + +## splitSpan + +> [!WARNING] +> Required + +Either the intervals or the page ranges to extract, depending on the selected `splitMode`. + +```php +namespace App\Controller; + +use Sensiolabs\GotenbergBundle\Enumeration\SplitMode; +use Sensiolabs\GotenbergBundle\GotenbergPdfInterface; + +class YourController +{ + public function yourControllerMethod(GotenbergPdfInterface $gotenberg): Response + { + return $gotenberg->split() + ->files('document_1.pdf') + ->splitMode(SplitMode::Intervals) + ->splitSpan('1') + ->generate() + ->stream() + ; + } +} +``` + +## splitUnify + +Default: `false` + +Specify whether to put extracted pages into a single file or as many files as +there are page ranges. Only works with `pages` mode. + +```php +namespace App\Controller; + +use Sensiolabs\GotenbergBundle\Enum\SplitMode; +use Sensiolabs\GotenbergBundle\GotenbergPdfInterface; + +class YourController +{ + public function yourControllerMethod(GotenbergPdfInterface $gotenberg): Response + { + return $gotenberg->split() + ->files('document_1.pdf') + ->splitMode(SplitMode::Pages) + ->splitSpan('1-2') + ->splitUnify() // is same as ->splitUnify(true) + ->generate() + ->stream() + ; + } +} +``` diff --git a/src/Builder/Pdf/AbstractChromiumPdfBuilder.php b/src/Builder/Pdf/AbstractChromiumPdfBuilder.php index c734cccf..deecefe0 100644 --- a/src/Builder/Pdf/AbstractChromiumPdfBuilder.php +++ b/src/Builder/Pdf/AbstractChromiumPdfBuilder.php @@ -9,6 +9,7 @@ use Sensiolabs\GotenbergBundle\Enumeration\PaperSizeInterface; use Sensiolabs\GotenbergBundle\Enumeration\Part; use Sensiolabs\GotenbergBundle\Enumeration\PdfFormat; +use Sensiolabs\GotenbergBundle\Enumeration\SplitMode; use Sensiolabs\GotenbergBundle\Enumeration\Unit; use Sensiolabs\GotenbergBundle\Enumeration\UserAgent; use Sensiolabs\GotenbergBundle\Exception\InvalidBuilderConfiguration; @@ -567,6 +568,48 @@ public function addMetadata(string $key, string $value): static return $this; } + /** + * Either intervals or pages. (default None). + * + * @see https://gotenberg.dev/docs/routes#split-chromium + */ + public function splitMode(SplitMode|null $splitMode = null): static + { + if (null === $splitMode) { + unset($this->formFields['splitMode']); + + return $this; + } + + $this->formFields['splitMode'] = $splitMode; + + return $this; + } + + /** + * Either the intervals or the page ranges to extract, depending on the selected mode. (default None). + * + * @see https://gotenberg.dev/docs/routes#split-chromium + */ + public function splitSpan(string $splitSpan): static + { + $this->formFields['splitSpan'] = $splitSpan; + + return $this; + } + + /** + * Specify whether to put extracted pages into a single file or as many files as there are page ranges. Only works with pages mode. (default false). + * + * @see https://gotenberg.dev/docs/routes#split-chromium + */ + public function splitUnify(bool $bool = true): static + { + $this->formFields['splitUnify'] = $bool; + + return $this; + } + protected function withPdfPartFile(Part $pdfPart, string $path): static { $dataPart = new DataPart( @@ -637,6 +680,9 @@ protected function addConfiguration(string $configurationName, mixed $value): vo 'skip_network_idle_event' => $this->skipNetworkIdleEvent($value), 'metadata' => $this->metadata($value), 'download_from' => $this->downloadFrom($value), + 'split_mode' => $this->splitMode(SplitMode::from($value)), + 'split_span' => $this->splitSpan($value), + 'split_unify' => $this->splitUnify($value), default => throw new InvalidBuilderConfiguration(\sprintf('Invalid option "%s": no method does not exist in class "%s" to configured it.', $configurationName, static::class)), }; } diff --git a/src/Builder/Pdf/LibreOfficePdfBuilder.php b/src/Builder/Pdf/LibreOfficePdfBuilder.php index 38272193..8a09a08e 100644 --- a/src/Builder/Pdf/LibreOfficePdfBuilder.php +++ b/src/Builder/Pdf/LibreOfficePdfBuilder.php @@ -4,6 +4,7 @@ use Sensiolabs\GotenbergBundle\Enumeration\ImageResolutionDPI; use Sensiolabs\GotenbergBundle\Enumeration\PdfFormat; +use Sensiolabs\GotenbergBundle\Enumeration\SplitMode; use Sensiolabs\GotenbergBundle\Exception\InvalidBuilderConfiguration; use Sensiolabs\GotenbergBundle\Exception\MissingRequiredFieldException; use Symfony\Component\Mime\Part\DataPart; @@ -338,6 +339,48 @@ public function maxImageResolution(ImageResolutionDPI $resolution): self return $this; } + /** + * Either intervals or pages. (default None). + * + * @see https://gotenberg.dev/docs/routes#split-libreoffice + */ + public function splitMode(SplitMode|null $splitMode = null): static + { + if (null === $splitMode) { + unset($this->formFields['splitMode']); + + return $this; + } + + $this->formFields['splitMode'] = $splitMode; + + return $this; + } + + /** + * Either the intervals or the page ranges to extract, depending on the selected mode. (default None). + * + * @see https://gotenberg.dev/docs/routes#split-libreoffice + */ + public function splitSpan(string $splitSpan): static + { + $this->formFields['splitSpan'] = $splitSpan; + + return $this; + } + + /** + * Specify whether to put extracted pages into a single file or as many files as there are page ranges. Only works with pages mode. (default false). + * + * @see https://gotenberg.dev/docs/routes#split-libreoffice + */ + public function splitUnify(bool $bool = true): static + { + $this->formFields['splitUnify'] = $bool; + + return $this; + } + public function getMultipartFormData(): array { if ([] === ($this->formFields['files'] ?? []) && [] === ($this->formFields['downloadFrom'] ?? [])) { @@ -382,6 +425,9 @@ private function addConfiguration(string $configurationName, mixed $value): void 'reduce_image_resolution' => $this->reduceImageResolution($value), 'max_image_resolution' => $this->maxImageResolution(ImageResolutionDPI::from($value)), 'download_from' => $this->downloadFrom($value), + 'split_mode' => $this->splitMode(SplitMode::from($value)), + 'split_span' => $this->splitSpan($value), + 'split_unify' => $this->splitUnify($value), default => throw new InvalidBuilderConfiguration(\sprintf('Invalid option "%s": no method does not exist in class "%s" to configured it.', $configurationName, static::class)), }; } diff --git a/src/Builder/Pdf/SplitPdfBuilder.php b/src/Builder/Pdf/SplitPdfBuilder.php new file mode 100644 index 00000000..f101d122 --- /dev/null +++ b/src/Builder/Pdf/SplitPdfBuilder.php @@ -0,0 +1,116 @@ + $configurations + */ + public function setConfigurations(array $configurations): static + { + foreach ($configurations as $property => $value) { + $this->addConfiguration($property, $value); + } + + return $this; + } + + /** + * Either intervals or pages. (default None). + * + * @see https://gotenberg.dev/docs/routes#split-pdfs-route + */ + public function splitMode(SplitMode|null $splitMode = null): self + { + if (null === $splitMode) { + unset($this->formFields['splitMode']); + + return $this; + } + + $this->formFields['splitMode'] = $splitMode; + + return $this; + } + + /** + * Either the intervals or the page ranges to extract, depending on the selected mode. (default None). + * + * @see https://gotenberg.dev/docs/routes#split-pdfs-route + */ + public function splitSpan(string $splitSpan): self + { + $this->formFields['splitSpan'] = $splitSpan; + + return $this; + } + + /** + * Specify whether to put extracted pages into a single file or as many files as there are page ranges. Only works with pages mode. (default false). + * + * @see https://gotenberg.dev/docs/routes#split-pdfs-route + */ + public function splitUnify(bool $bool = true): self + { + $this->formFields['splitUnify'] = $bool; + + return $this; + } + + public function files(string ...$paths): self + { + $this->formFields['files'] = []; + + foreach ($paths as $path) { + $this->assertFileExtension($path, ['pdf']); + + $dataPart = new DataPart(new DataPartFile($this->asset->resolve($path))); + + $this->formFields['files'][$path] = $dataPart; + } + + return $this; + } + + public function getMultipartFormData(): array + { + if (!\array_key_exists('splitMode', $this->formFields) || !\array_key_exists('splitSpan', $this->formFields)) { + throw new MissingRequiredFieldException('"splitMode" and "splitSpan" must be provided.'); + } + + if ([] === ($this->formFields['files'] ?? [])) { + throw new MissingRequiredFieldException('At least one PDF file is required'); + } + + return parent::getMultipartFormData(); + } + + protected function getEndpoint(): string + { + return self::ENDPOINT; + } + + private function addConfiguration(string $configurationName, mixed $value): void + { + match ($configurationName) { + 'split_mode' => $this->splitMode(SplitMode::from($value)), + 'split_span' => $this->splitSpan($value), + 'split_unify' => $this->splitUnify($value), + default => throw new InvalidBuilderConfiguration(\sprintf('Invalid option "%s": no method does not exist in class "%s" to configured it.', $configurationName, static::class)), + }; + } +} diff --git a/src/Debug/TraceableGotenbergPdf.php b/src/Debug/TraceableGotenbergPdf.php index d70dd42b..09cfc7f7 100644 --- a/src/Debug/TraceableGotenbergPdf.php +++ b/src/Debug/TraceableGotenbergPdf.php @@ -8,6 +8,7 @@ use Sensiolabs\GotenbergBundle\Builder\Pdf\MarkdownPdfBuilder; use Sensiolabs\GotenbergBundle\Builder\Pdf\MergePdfBuilder; use Sensiolabs\GotenbergBundle\Builder\Pdf\PdfBuilderInterface; +use Sensiolabs\GotenbergBundle\Builder\Pdf\SplitPdfBuilder; use Sensiolabs\GotenbergBundle\Builder\Pdf\UrlPdfBuilder; use Sensiolabs\GotenbergBundle\Debug\Builder\TraceablePdfBuilder; use Sensiolabs\GotenbergBundle\GotenbergPdfInterface; @@ -139,6 +140,23 @@ public function convert(): PdfBuilderInterface return $traceableBuilder; } + /** + * @return SplitPdfBuilder|TraceablePdfBuilder + */ + public function split(): PdfBuilderInterface + { + /** @var SplitPdfBuilder|TraceablePdfBuilder $traceableBuilder */ + $traceableBuilder = $this->inner->split(); + + if (!$traceableBuilder instanceof TraceablePdfBuilder) { + return $traceableBuilder; + } + + $this->builders[] = ['split', $traceableBuilder]; + + return $traceableBuilder; + } + /** * @return list */ diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php index 47e65493..c8d5b30d 100644 --- a/src/DependencyInjection/Configuration.php +++ b/src/DependencyInjection/Configuration.php @@ -7,6 +7,7 @@ use Sensiolabs\GotenbergBundle\Enumeration\PaperSize; use Sensiolabs\GotenbergBundle\Enumeration\PdfFormat; use Sensiolabs\GotenbergBundle\Enumeration\ScreenshotFormat; +use Sensiolabs\GotenbergBundle\Enumeration\SplitMode; use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition; use Symfony\Component\Config\Definition\Builder\NodeDefinition; use Symfony\Component\Config\Definition\Builder\TreeBuilder; @@ -57,6 +58,7 @@ public function getConfigTreeBuilder(): TreeBuilder ->append($this->addPdfOfficeNode()) ->append($this->addPdfMergeNode()) ->append($this->addPdfConvertNode()) + ->append($this->addPdfSplitNode()) ->end() ->arrayNode('screenshot') ->addDefaultsIfNotSet() @@ -356,6 +358,7 @@ private function addChromiumPdfOptionsNode(ArrayNodeDefinition $parent): void ; $this->addPdfFormat($parent); + $this->addSplitConfigurationNode($parent); } private function addChromiumScreenshotOptionsNode(ArrayNodeDefinition $parent): void @@ -597,6 +600,7 @@ private function addPdfOfficeNode(): NodeDefinition ; $this->addPdfFormat($treeBuilder->getRootNode()); + $this->addSplitConfigurationNode($treeBuilder->getRootNode()); return $treeBuilder->getRootNode(); } @@ -624,6 +628,14 @@ private function addPdfMergeNode(): NodeDefinition return $treeBuilder->getRootNode(); } + private function addPdfSplitNode(): NodeDefinition + { + $treeBuilder = new TreeBuilder('split'); + $this->addSplitConfigurationNode($treeBuilder->getRootNode()); + + return $treeBuilder->getRootNode(); + } + private function addPdfFormat(ArrayNodeDefinition $parent): void { $parent @@ -882,4 +894,38 @@ private function addExtraHttpHeaders(): NodeDefinition ->end() ; } + + private function addSplitConfigurationNode(ArrayNodeDefinition $parent): void + { + $parent + ->addDefaultsIfNotSet() + ->children() + ->enumNode('split_mode') + ->info('Either intervals or pages. - default None. https://gotenberg.dev/docs/routes#split-chromium') + ->values(array_map(static fn (SplitMode $case): string => $case->value, SplitMode::cases())) + ->defaultNull() + ->end() + ->scalarNode('split_span') + ->info('Either the intervals or the page ranges to extract, depending on the selected mode. - default None. https://gotenberg.dev/docs/routes#split-chromium') + ->defaultNull() + ->validate() + ->ifTrue(static function ($option): bool { + return preg_match('/([\d]+[-][\d]+)/', $option) !== 1 && preg_match('/(\d+)/', $option) !== 1; + }) + ->thenInvalid('Invalid value, the range value format need to look like e.g 1-20 or as a single int value e.g 2.') + ->end() + ->end() + ->booleanNode('split_unify') + ->info('Specify whether to put extracted pages into a single file or as many files as there are page ranges. Only works with pages mode. - default false. https://gotenberg.dev/docs/routes#split-chromium') + ->defaultNull() + ->end() + ->end() + ->validate() + ->ifTrue(static function ($option): bool { + return isset($option['split_mode']) && !isset($option['split_span']); + }) + ->thenInvalid('"splitMode" and "splitSpan" must be provided.') + ->end() + ; + } } diff --git a/src/DependencyInjection/SensiolabsGotenbergExtension.php b/src/DependencyInjection/SensiolabsGotenbergExtension.php index b9c490fa..8214c6f3 100644 --- a/src/DependencyInjection/SensiolabsGotenbergExtension.php +++ b/src/DependencyInjection/SensiolabsGotenbergExtension.php @@ -31,7 +31,8 @@ * markdown: array, * office: array, * merge: array, - * convert: array + * convert: array, + * split: array * }, * screenshot: array{ * html: array, @@ -71,6 +72,7 @@ public function load(array $configs, ContainerBuilder $container): void 'office' => $this->cleanUserOptions($config['default_options']['pdf']['office']), 'merge' => $this->cleanUserOptions($config['default_options']['pdf']['merge']), 'convert' => $this->cleanUserOptions($config['default_options']['pdf']['convert']), + 'split' => $this->cleanUserOptions($config['default_options']['pdf']['split']), ]) ; } @@ -112,6 +114,8 @@ public function load(array $configs, ContainerBuilder $container): void $this->processDefaultOptions($container, $config, '.sensiolabs_gotenberg.pdf_builder.convert', $config['default_options']['pdf']['convert']); + $this->processDefaultOptions($container, $config, '.sensiolabs_gotenberg.pdf_builder.split', $config['default_options']['pdf']['split']); + $this->processDefaultOptions($container, $config, '.sensiolabs_gotenberg.screenshot_builder.html', $config['default_options']['screenshot']['html']); $this->processDefaultOptions($container, $config, '.sensiolabs_gotenberg.screenshot_builder.url', $config['default_options']['screenshot']['url']); diff --git a/src/Enumeration/SplitMode.php b/src/Enumeration/SplitMode.php new file mode 100644 index 00000000..6370a3d0 --- /dev/null +++ b/src/Enumeration/SplitMode.php @@ -0,0 +1,9 @@ +getInternal('convert'); } + + public function split(): PdfBuilderInterface + { + return $this->getInternal('split'); + } } diff --git a/src/GotenbergPdfInterface.php b/src/GotenbergPdfInterface.php index e695c17d..8a952884 100644 --- a/src/GotenbergPdfInterface.php +++ b/src/GotenbergPdfInterface.php @@ -8,6 +8,7 @@ use Sensiolabs\GotenbergBundle\Builder\Pdf\MarkdownPdfBuilder; use Sensiolabs\GotenbergBundle\Builder\Pdf\MergePdfBuilder; use Sensiolabs\GotenbergBundle\Builder\Pdf\PdfBuilderInterface; +use Sensiolabs\GotenbergBundle\Builder\Pdf\SplitPdfBuilder; use Sensiolabs\GotenbergBundle\Builder\Pdf\UrlPdfBuilder; interface GotenbergPdfInterface @@ -50,4 +51,9 @@ public function merge(): PdfBuilderInterface; * @return ConvertPdfBuilder */ public function convert(): PdfBuilderInterface; + + /** + * @return SplitPdfBuilder + */ + public function split(): PdfBuilderInterface; } diff --git a/tests/Builder/Pdf/SplitPdfBuilderTest.php b/tests/Builder/Pdf/SplitPdfBuilderTest.php new file mode 100644 index 00000000..100218df --- /dev/null +++ b/tests/Builder/Pdf/SplitPdfBuilderTest.php @@ -0,0 +1,120 @@ +gotenbergClient + ->expects($this->once()) + ->method('call') + ->with( + $this->equalTo('/forms/pdfengines/split'), + $this->anything(), + $this->anything(), + ) + ; + + $this->getSplitPdfBuilder() + ->files(self::PDF_DOCUMENTS_DIR.'/multi_page.pdf') + ->splitMode(SplitMode::Pages) + ->splitSpan('1') + ->generate() + ; + } + + public static function configurationIsCorrectlySetProvider(): \Generator + { + yield 'split_mode' => [ + [ + 'split_mode' => 'pages', + 'split_span' => '1', + ], + [ + 'splitMode' => 'pages', + ], + ]; + yield 'split_span' => [ + [ + 'split_span' => '1', + 'split_mode' => 'pages', + ], + [ + 'splitSpan' => '1', + ], + ]; + yield 'split_unify' => [ + [ + 'split_unify' => true, + 'split_span' => '1', + 'split_mode' => 'pages', + ], + [ + 'splitUnify' => true, + ], + ]; + } + + /** + * @param array $configurations + * @param array $expected + */ + #[DataProvider('configurationIsCorrectlySetProvider')] + public function testConfigurationIsCorrectlySet(array $configurations, array $expected): void + { + $builder = $this->getSplitPdfBuilder(); + $builder->setConfigurations($configurations); + $builder->files(self::PDF_DOCUMENTS_DIR.'/multi_page.pdf'); + + self::assertEquals($expected, $builder->getMultipartFormData()[0]); + } + + public function testRequiredFormData(): void + { + $builder = $this->getSplitPdfBuilder(); + + $this->expectException(MissingRequiredFieldException::class); + $this->expectExceptionMessage('"splitMode" and "splitSpan" must be provided.'); + + $builder->getMultipartFormData(); + } + + public function testRequiredFile(): void + { + $builder = $this->getSplitPdfBuilder() + ->splitMode(SplitMode::Pages) + ->splitSpan('1') + ; + + $this->expectException(MissingRequiredFieldException::class); + $this->expectExceptionMessage('At least one PDF file is required'); + + $builder->getMultipartFormData(); + } + + private function getSplitPdfBuilder(): SplitPdfBuilder + { + return (new SplitPdfBuilder($this->gotenbergClient, self::$assetBaseDirFormatter, $this->webhookConfigurationRegistry)) + ->processor(new NullProcessor()) + ; + } +} diff --git a/tests/DependencyInjection/ConfigurationTest.php b/tests/DependencyInjection/ConfigurationTest.php index f24e583b..4fdefb97 100644 --- a/tests/DependencyInjection/ConfigurationTest.php +++ b/tests/DependencyInjection/ConfigurationTest.php @@ -263,6 +263,9 @@ private static function getBundleDefaultConfig(): array 'pdf_format' => null, 'pdf_universal_access' => null, 'download_from' => [], + 'split_mode' => null, + 'split_span' => null, + 'split_unify' => null, ], 'url' => [ 'single_page' => null, @@ -294,6 +297,9 @@ private static function getBundleDefaultConfig(): array 'pdf_format' => null, 'pdf_universal_access' => null, 'download_from' => [], + 'split_mode' => null, + 'split_span' => null, + 'split_unify' => null, ], 'markdown' => [ 'single_page' => null, @@ -325,6 +331,9 @@ private static function getBundleDefaultConfig(): array 'pdf_format' => null, 'pdf_universal_access' => null, 'download_from' => [], + 'split_mode' => null, + 'split_span' => null, + 'split_unify' => null, ], 'office' => [ 'password' => null, @@ -353,6 +362,9 @@ private static function getBundleDefaultConfig(): array 'reduce_image_resolution' => null, 'max_image_resolution' => null, 'download_from' => [], + 'split_mode' => null, + 'split_span' => null, + 'split_unify' => null, ], 'merge' => [ 'pdf_format' => null, @@ -364,6 +376,11 @@ private static function getBundleDefaultConfig(): array 'pdf_universal_access' => null, 'download_from' => [], ], + 'split' => [ + 'split_mode' => null, + 'split_span' => null, + 'split_unify' => null, + ], ], 'screenshot' => [ 'html' => [ diff --git a/tests/DependencyInjection/SensiolabsGotenbergExtensionTest.php b/tests/DependencyInjection/SensiolabsGotenbergExtensionTest.php index a69c7dd4..d984c616 100644 --- a/tests/DependencyInjection/SensiolabsGotenbergExtensionTest.php +++ b/tests/DependencyInjection/SensiolabsGotenbergExtensionTest.php @@ -426,6 +426,7 @@ public function testDataCollectorIsProperlyConfiguredIfEnabled(): void 'pdf_format' => 'PDF/A-2b', 'download_from' => [], ], + 'split' => [], ], $dataCollectorOptions); } diff --git a/tests/Fixtures/pdf/multi_page.pdf b/tests/Fixtures/pdf/multi_page.pdf new file mode 100644 index 00000000..bb43e8f1 Binary files /dev/null and b/tests/Fixtures/pdf/multi_page.pdf differ