Skip to content

Commit

Permalink
[Feature] Async generation (sensiolabs#84)
Browse files Browse the repository at this point in the history
  • Loading branch information
maelanleborgne authored Nov 19, 2024
1 parent 0b9b868 commit bbdfaeb
Show file tree
Hide file tree
Showing 63 changed files with 2,779 additions and 268 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@
.php-cs-fixer.cache
.phpunit.result.cache
composer.lock
phpstan.neon
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,7 @@ class YourController
1. [Configuration](./docs/configuration.md)
2. [Working with assets](./docs/assets.md)
3. [Builders API](./docs/builders_api.md)
4. [Async & Webhooks](./docs/webhook.md)

#### PDF

Expand Down
6 changes: 6 additions & 0 deletions config/builder_pdf.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
->args([
service('sensiolabs_gotenberg.client'),
service('sensiolabs_gotenberg.asset.base_dir_formatter'),
service('.sensiolabs_gotenberg.webhook_configuration_registry'),
service('request_stack'),
service('twig')->nullOnInvalid(),
])
Expand All @@ -33,6 +34,7 @@
->args([
service('sensiolabs_gotenberg.client'),
service('sensiolabs_gotenberg.asset.base_dir_formatter'),
service('.sensiolabs_gotenberg.webhook_configuration_registry'),
service('request_stack'),
service('twig')->nullOnInvalid(),
service('router')->nullOnInvalid(),
Expand All @@ -47,6 +49,7 @@
->args([
service('sensiolabs_gotenberg.client'),
service('sensiolabs_gotenberg.asset.base_dir_formatter'),
service('.sensiolabs_gotenberg.webhook_configuration_registry'),
service('request_stack'),
service('twig')->nullOnInvalid(),
])
Expand All @@ -59,6 +62,7 @@
->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')
Expand All @@ -69,6 +73,7 @@
->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')
Expand All @@ -79,6 +84,7 @@
->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')
Expand Down
3 changes: 3 additions & 0 deletions config/builder_screenshot.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
->args([
service('sensiolabs_gotenberg.client'),
service('sensiolabs_gotenberg.asset.base_dir_formatter'),
service('.sensiolabs_gotenberg.webhook_configuration_registry'),
service('request_stack'),
service('twig')->nullOnInvalid(),
])
Expand All @@ -30,6 +31,7 @@
->args([
service('sensiolabs_gotenberg.client'),
service('sensiolabs_gotenberg.asset.base_dir_formatter'),
service('.sensiolabs_gotenberg.webhook_configuration_registry'),
service('request_stack'),
service('twig')->nullOnInvalid(),
service('router')->nullOnInvalid(),
Expand All @@ -44,6 +46,7 @@
->args([
service('sensiolabs_gotenberg.client'),
service('sensiolabs_gotenberg.asset.base_dir_formatter'),
service('.sensiolabs_gotenberg.webhook_configuration_registry'),
service('request_stack'),
service('twig')->nullOnInvalid(),
])
Expand Down
10 changes: 10 additions & 0 deletions config/services.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
use Sensiolabs\GotenbergBundle\GotenbergScreenshot;
use Sensiolabs\GotenbergBundle\GotenbergScreenshotInterface;
use Sensiolabs\GotenbergBundle\Twig\GotenbergAssetExtension;
use Sensiolabs\GotenbergBundle\Webhook\WebhookConfigurationRegistry;
use Sensiolabs\GotenbergBundle\Webhook\WebhookConfigurationRegistryInterface;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
use Symfony\Component\Filesystem\Filesystem;
use function Symfony\Component\DependencyInjection\Loader\Configurator\abstract_arg;
Expand Down Expand Up @@ -68,4 +70,12 @@
$services->set('sensiolabs_gotenberg.http_kernel.stream_builder', ProcessBuilderOnControllerResponse::class)
->tag('kernel.event_listener', ['method' => 'streamBuilder', 'event' => 'kernel.view'])
;

$services->set('.sensiolabs_gotenberg.webhook_configuration_registry', WebhookConfigurationRegistry::class)
->args([
service('router'),
service('.sensiolabs_gotenberg.request_context')->nullOnInvalid(),
])
->alias(WebhookConfigurationRegistryInterface::class, '.sensiolabs_gotenberg.webhook_configuration_registry')
;
};
199 changes: 199 additions & 0 deletions docs/async/native.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
## Using the native feature

Gotenberg [allows](https://gotenberg.dev/docs/configuration#webhook) to defer the generation of your files through webhooks.
When it is done creating your file, it calls back whatever header you sent.

To use this feature you need two things :
- Send the appropriate headers
- use `->generateAsync()` method

### Through Bundle configuration

Using bundle configuration you can define :
- named configurations
- default named configuration
- per context (PDF+HTML, PDF+URL, SCREENSHOT+MARKDOWN)

```yaml
# config/packages/sensiolabs_gotenberg.yaml

sensiolabs_gotenberg:

webhook:

# Prototype
name:
name: ~
success:

# The URL to call.
url: ~

# Route configuration.
route: ~

# Examples:
# - 'https://webhook.site/#!/view/{some-token}'
# - [my_route, { param1: value1, param2: value2 }]

# HTTP method to use on that endpoint.
method: null # One of "POST"; "PUT"; "PATCH"
error:

# The URL to call.
url: ~

# Route configuration.
route: ~

# Examples:
# - 'https://webhook.site/#!/view/{some-token}'
# - [my_route, { param1: value1, param2: value2 }]

# HTTP method to use on that endpoint.
method: null # One of "POST"; "PUT"; "PATCH"

# HTTP headers to send back to both success and error endpoints - default None. https://gotenberg.dev/docs/webhook
extra_http_headers:

# Prototype
name:
name: ~
value: ~
default_options:

# Webhook configuration name.
webhook: ~
```
Each named configuration requires at least a `success` URL which can be set either through a plain URL (`sensiolabs_gotenberg.webhook.{name}.success.url`) or by using a defined route in your application (`sensiolabs_gotenberg.webhook.{name}.success.route`).

Here are some examples :

```yaml
sensiolabs_gotenberg:
webhook:
default:
success:
url: 'https://webhook.site/#!/view/{some-uuid}'
```
or
```yaml
sensiolabs_gotenberg:
webhook:
default:
success:
route: ['my_route', {'param1': 'value1'}]
```

Once a named configuration has been set, you can set it as a global default for all your builders :

```yaml
sensiolabs_gotenberg:
default_options:
webhook: 'default'
```

or set it per builder :

```yaml
sensiolabs_gotenberg:
webhook:
default:
success:
url: 'https://webhook.site/#!/view/{some-uuid}'
pdf_html:
success:
url: 'https://webhook.site/#!/view/{some-other-uuid}'
default_options:
pdf:
html:
webhook:
config_name: 'pdf_html'
```

finally you can do it like so :

```yaml
sensiolabs_gotenberg:
default_options:
pdf:
html:
webhook:
success:
url: 'https://webhook.site/#!/view/{some-uuid}'
```

> [!WARNING]
> When using both `config_name` and a custom configuration on a builder,
> it will load the named configuration and merge it with the builder's configuration.
>
> See the following example :

```yaml
sensiolabs_gotenberg:
webhook:
default:
success:
url: 'https://webhook.site/#!/view/{some-success-uuid}'
error:
url: 'https://webhook.site/#!/view/{some-error-uuid}'
default_options:
pdf:
html:
webhook:
config_name: 'default'
success:
url: 'https://webhook.site/#!/view/{some-other-uuid}'
```

is equivalent to :

```yaml
sensiolabs_gotenberg:
default_options:
pdf:
html:
webhook:
success:
url: 'https://webhook.site/#!/view/{some-other-uuid}'
error:
url: 'https://webhook.site/#!/view/{some-error-uuid}'
```

### At runtime

You can define webhook configuration at runtime.

If you defined some named configuration like seen earlier, the simplest way is then to do the following:

```diff
$builder = $this->gotenberg->pdf()->html()
+ ->webhookConfiguration('default')
->header('header.html.twig')
->content('html.html.twig', ['name' => 'Plop'])
->fileName('html.pdf')
;
```

Or you can also define manually using :

```diff
$builder = $this->gotenberg->pdf()->html()
+ ->webhookUrl($this->router->generate('my_route'))
->header('header.html.twig')
->content('html.html.twig', ['name' => 'Plop'])
->fileName('html.pdf')
;
```

> [!WARNING]
> If combining both `->webhookConfiguration()` & `->webhookUrl()`, the order is important :
>
> If calling `->webhookConfiguration()` first then `->webhookUrl()` will override only the "success" part.
>
> If calling `->webhookUrl()` first then `->webhookConfiguration()` totally overrides previously set values.


> [!NOTE]
> If only success URL is set, error URL will fallback to the success one.
16 changes: 9 additions & 7 deletions docs/builders_api.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,16 @@

## Pdf

* [HtmlPdfBuilder](./pdf/builders_api/HtmlPdfBuilder.md)
* [UrlPdfBuilder](./pdf/builders_api/UrlPdfBuilder.md)
* [MarkdownPdfBuilder](./pdf/builders_api/MarkdownPdfBuilder.md)
* [LibreOfficePdfBuilder](./pdf/builders_api/LibreOfficePdfBuilder.md)
* [HtmlPdfBuilder](./Pdf/builders_api/HtmlPdfBuilder.md)
* [UrlPdfBuilder](./Pdf/builders_api/UrlPdfBuilder.md)
* [MarkdownPdfBuilder](./Pdf/builders_api/MarkdownPdfBuilder.md)
* [LibreOfficePdfBuilder](./Pdf/builders_api/LibreOfficePdfBuilder.md)
* [MergePdfBuilder](./Pdf/builders_api/MergePdfBuilder.md)
* [ConvertPdfBuilder](./Pdf/builders_api/ConvertPdfBuilder.md)

## Screenshot

* [HtmlScreenshotBuilder](./screenshot/builders_api/HtmlScreenshotBuilder.md)
* [UrlScreenshotBuilder](./screenshot/builders_api/UrlScreenshotBuilder.md)
* [MarkdownScreenshotBuilder](./screenshot/builders_api/MarkdownScreenshotBuilder.md)
* [HtmlScreenshotBuilder](./Screenshot/builders_api/HtmlScreenshotBuilder.md)
* [UrlScreenshotBuilder](./Screenshot/builders_api/UrlScreenshotBuilder.md)
* [MarkdownScreenshotBuilder](./Screenshot/builders_api/MarkdownScreenshotBuilder.md)

Loading

0 comments on commit bbdfaeb

Please sign in to comment.