Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[RELEASE-V8] Add new fields #33

Merged
merged 11 commits into from
May 23, 2024
Merged
53 changes: 50 additions & 3 deletions docs/configuration.rst
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,11 @@ The default configuration for the bundle looks like :
wait_delay: null # None
wait_for_expression: null # None
emulated_media_type: null # 'print'
cookies: null # None
extra_http_headers: null # None
fail_on_http_status_codes: null # [499-599]
fail_on_console_exceptions: null # false
skip_network_idle_event: null # false
pdf_format: null # None
pdf_universal_access: null # false
url:
Expand All @@ -48,8 +51,11 @@ The default configuration for the bundle looks like :
wait_delay: null # None
wait_for_expression: null # None
emulated_media_type: null # 'print'
cookies: null # None
extra_http_headers: null # None
fail_on_http_status_codes: null # [499-599]
fail_on_console_exceptions: null # false
skip_network_idle_event: null # false
pdf_format: null # None
pdf_universal_access: null # false
markdown:
Expand All @@ -68,8 +74,11 @@ The default configuration for the bundle looks like :
wait_delay: null # None
wait_for_expression: null # None
emulated_media_type: null # 'print'
cookies: null # None
extra_http_headers: null # None
fail_on_http_status_codes: null # [499-599]
fail_on_console_exceptions: null # false
skip_network_idle_event: null # false
pdf_format: null # None
pdf_universal_access: null # false
office:
Expand Down Expand Up @@ -100,13 +109,51 @@ HTTP headers to send by Chromium while loading the HTML document.

sensiolabs_gotenberg:
base_uri: 'http://localhost:3000'
options:
extra_http_headers:
- { name: 'My-Header', value: 'MyValue' }
default_options:
html:
extra_http_headers:
- { name: 'My-Header', value: 'MyValue' }

.. tip::

For more information about `custom HTTP headers`_.

Invalid HTTP Status Codes
~~~~~~~~~~~~~~~~~~~~~~~~~

To return a 409 Conflict response if the HTTP status code from the main page is not acceptable.

.. code-block:: yaml

sensiolabs_gotenberg:
base_uri: 'http://localhost:3000'
default_options:
html:
fail_on_http_status_codes: [401, 403]

.. tip::

For more information about `Invalid HTTP Status Codes`_.

Cookies
~~~~~~~

Cookies to store in the Chromium cookie jar.

.. code-block:: yaml

sensiolabs_gotenberg:
base_uri: 'http://localhost:3000'
default_options:
html:
cookies:
- { name: 'yummy_cookie', value: 'choco', domain: 'example.com' }
- { name: 'my_cookie', value: 'symfony', domain: 'symfony.com', secure: true, httpOnly: true, sameSite: 'Lax' }

.. tip::

For more information about `custom HTTP headers`_.

.. _defaults properties: https://gotenberg.dev/docs/routes#page-properties-chromium
.. _custom HTTP headers: https://gotenberg.dev/docs/routes#custom-http-headers
.. _Invalid HTTP Status Codes: https://gotenberg.dev/docs/routes#invalid-http-status-codes-chromium
87 changes: 87 additions & 0 deletions docs/customization.rst
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,54 @@ Some websites have dedicated CSS rules for print. Using ``screen`` allows you to

For more information about `emulated Media Type`_.

Cookies
-------

``default: None``

Cookies to store in the Chromium cookie jar.

.. code-block:: php

$twigPdfBuilder
Jean-Beru marked this conversation as resolved.
Show resolved Hide resolved
->content('path/to/template.html.twig')
->cookies([
[
'name' => 'my_cookie',
'value' => 'symfony',
'domain' => 'symfony.com',
'secure' => true,
'httpOnly' => true,
'sameSite' => 'Lax',
],
]);

.. warning::

`cookies` method overrides any previous cookies.

If you want to add cookies from the ones already loaded in the configuration you
can use `addCookie`.

.. code-block:: php

$twigPdfBuilder
->content('path/to/template.html.twig')
->addCookies([
Neirda24 marked this conversation as resolved.
Show resolved Hide resolved
[
'name' => 'my_cookie',
'value' => 'symfony',
'domain' => 'symfony.com',
'secure' => true,
'httpOnly' => true,
'sameSite' => 'Lax',
],
]);

.. tip::

For more information about `cookies`_.

Extra HTTP headers
------------------

Expand All @@ -323,6 +371,23 @@ HTTP headers to send by Chromium while loading the HTML document.

For more information about `custom HTTP headers`_.

Invalid HTTP Status Codes
-------------------------

``default: [499,599]``

To return a 409 Conflict response if the HTTP status code from the main page is not acceptable..

.. code-block:: php

$twigPdfBuilder
->content('path/to/template.html.twig')
->failOnHttpStatusCodes([401, 403]);

.. tip::

For more information about `invalid HTTP Status Codes`_.

Console Exceptions
------------------

Expand All @@ -340,6 +405,25 @@ Return a 409 Conflict response if there are exceptions in the Chromium console.

For more information about `console Exceptions`_.

Performance Mode
----------------

``default: false``

Gotenberg, by default, waits for the network idle event to ensure that the majority of the page is rendered during conversion.
However, this often significantly slows down the conversion process.
Setting this form field to true can greatly enhance the conversion speed.

.. code-block:: php

$twigPdfBuilder
->content('path/to/template.html.twig')
->skipNetworkIdleEvent();

.. tip::

For more information about `performance mode`_.

PDF Format
----------

Expand Down Expand Up @@ -381,6 +465,9 @@ Enable PDF for Universal Access for optimal accessibility.
.. _delay: https://gotenberg.dev/docs/routes#wait-before-rendering
.. _wait for expression: https://gotenberg.dev/docs/routes#wait-before-rendering
.. _emulated Media Type: https://gotenberg.dev/docs/routes#emulated-media-type
.. _cookies: https://gotenberg.dev/docs/routes#cookies-chromium
.. _custom HTTP headers: https://gotenberg.dev/docs/routes#custom-http-headers
.. _invalid HTTP Status Codes: https://gotenberg.dev/docs/routes#invalid-http-status-codes-chromium
.. _console Exceptions: https://gotenberg.dev/docs/routes#console-exceptions
.. _performance mode: https://gotenberg.dev/docs/routes#performance-mode-chromium
.. _pdf formats: https://gotenberg.dev/docs/routes#pdfa-chromium
71 changes: 71 additions & 0 deletions src/Builder/AbstractChromiumPdfBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use Sensiolabs\GotenbergBundle\Exception\InvalidBuilderConfiguration;
use Sensiolabs\GotenbergBundle\Exception\PdfPartRenderingException;
use Sensiolabs\GotenbergBundle\Formatter\AssetBaseDirFormatter;
use Symfony\Component\HttpFoundation\Cookie;
use Symfony\Component\Mime\Part\DataPart;
use Symfony\Component\Mime\Part\File as DataPartFile;
use Twig\Environment;
Expand Down Expand Up @@ -307,6 +308,51 @@ public function emulatedMediaType(string $mediaType): static
return $this;
}

/**
* Cookies to store in the Chromium cookie jar. (overrides any previous cookies).
*
* @see https://gotenberg.dev/docs/routes#cookies-chromium
*
* @param list<array{name: string, value: string, domain: string, path?: string|null, secure?: bool|null, httpOnly?: bool|null, sameSite?: 'Strict'|'Lax'|null}> $cookies
*/
public function cookies(array $cookies): static
{
$this->formFields['cookies'] = [];

foreach ($cookies as $cookie) {
$this->setCookie($cookie['name'], $cookie);
}

return $this;
}

/**
* @param array{name: string, value: string, domain: string, path?: string|null, secure?: bool|null, httpOnly?: bool|null, sameSite?: 'Strict'|'Lax'|null} $cookie
*/
public function setCookie(string $key, array $cookie): static
{
$this->formFields['cookies'] ??= [];
$this->formFields['cookies'][$key] = $cookie;

return $this;
}

/**
* Add cookies to store in the Chromium cookie jar.
*
* @see https://gotenberg.dev/docs/routes#cookies-chromium
*
* @param list<array{name: string, value: string, domain: string, path?: string|null, secure?: bool|null, httpOnly?: bool|null, sameSite?: 'Strict'|'Lax'|null}> $cookies
*/
public function addCookies(array $cookies): static
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

addCookie or just cookie ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As addExtraHttpHeader you can add cookies in addition to the ones in the configuration file if needed.

And if not use cookies only.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can have a look about the doc where I explain that 😉 Let me know what you think
https://github.com/sensiolabs/GotenbergBundle/pull/33/files#diff-dbcb3d682e3e3080ba4b0f0195b7215457be7782b74898ccbefed9a74ba3be26R267

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So addCookies could be named addCookie since we only add one.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I updated the method if the user wants to add several to those already loaded from their configuration file.
WDYT?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it is confusing. On other classes we have singulars on add methods. I don't see why this one needs to be different. But maybe I'm just missing something.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought about addExtraHttpHeaders when I created that one.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let me know and I can rename it ;)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we name them addCookies and addExtraHttpHeaders, they should accept a list. If we name them without a "s" (addCookie and addExtraHttpHeader), they should accept a single value.

PS: I don't have a strong opinion on choosing one of these two solutions

{
foreach ($cookies as $cookie) {
$this->setCookie($cookie['name'], $cookie);
}

return $this;
}

/**
* Sets extra HTTP headers that Chromium will send when loading the HTML
* document. (default None). (overrides any previous headers).
Expand Down Expand Up @@ -337,6 +383,21 @@ public function addExtraHttpHeaders(array $headers): static
return $this;
}

/**
* Return a 409 Conflict response if the HTTP status code from
* the main page is not acceptable. (default [499,599]). (overrides any previous configuration).
*
* @see https://gotenberg.dev/docs/routes#invalid-http-status-codes-chromium
*
* @param array<int, int> $statusCodes
*/
public function failOnHttpStatusCodes(array $statusCodes): static
{
$this->formFields['failOnHttpStatusCodes'] = $statusCodes;

return $this;
}

/**
* Forces Gotenberg to return a 409 Conflict response if there are
* exceptions in the Chromium console. (default false).
Expand All @@ -350,6 +411,13 @@ public function failOnConsoleExceptions(bool $bool = true): static
return $this;
}

public function skipNetworkIdleEvent(bool $bool = true): static
{
$this->formFields['skipNetworkIdleEvent'] = $bool;

return $this;
}

/**
* Sets the PDF format of the resulting PDF. (default None).
*
Expand Down Expand Up @@ -429,8 +497,11 @@ private function addConfiguration(string $configurationName, mixed $value): void
'wait_delay' => $this->waitDelay($value),
'wait_for_expression' => $this->waitForExpression($value),
'emulated_media_type' => $this->emulatedMediaType($value),
'cookies' => $this->cookies($value),
'extra_http_headers' => $this->extraHttpHeaders($value),
'fail_on_http_status_codes' => $this->failOnHttpStatusCodes($value),
'fail_on_console_exceptions' => $this->failOnConsoleExceptions($value),
'skip_network_idle_event' => $this->skipNetworkIdleEvent($value),
default => throw new InvalidBuilderConfiguration(sprintf('Invalid option "%s": no method does not exist in class "%s" to configured it.', $configurationName, static::class)),
};
}
Expand Down
32 changes: 23 additions & 9 deletions src/Builder/AbstractPdfBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
use Sensiolabs\GotenbergBundle\Client\GotenbergClientInterface;
use Sensiolabs\GotenbergBundle\Client\PdfResponse;
use Sensiolabs\GotenbergBundle\Enum\PdfPart;
use Sensiolabs\GotenbergBundle\Exception\ExtraHttpHeadersJsonEncodingException;
use Sensiolabs\GotenbergBundle\Exception\JsonEncodingException;
use Sensiolabs\GotenbergBundle\Formatter\AssetBaseDirFormatter;
use Symfony\Component\HttpFoundation\File\File;
use Symfony\Component\HttpFoundation\HeaderUtils;
Expand All @@ -32,14 +32,8 @@ public function __construct(
protected readonly AssetBaseDirFormatter $asset,
) {
$this->normalizers = [
'extraHttpHeaders' => static function (mixed $value): array {
try {
$extraHttpHeaders = json_encode($value, \JSON_THROW_ON_ERROR);
} catch (\JsonException $exception) {
throw new ExtraHttpHeadersJsonEncodingException('Could not encode extra HTTP headers into JSON', previous: $exception);
}

return ['extraHttpHeaders' => $extraHttpHeaders];
'extraHttpHeaders' => function (mixed $value): array {
return $this->encodeData('extraHttpHeaders', $value);
},
'assets' => static function (array $value): array {
return ['files' => $value];
Expand All @@ -53,9 +47,29 @@ public function __construct(
PdfPart::FooterPart->value => static function (DataPart $value): array {
return ['files' => $value];
},
'failOnHttpStatusCodes' => function (mixed $value): array {
return $this->encodeData('failOnHttpStatusCodes', $value);
},
'cookies' => function (mixed $value): array {
return $this->encodeData('cookies', array_values($value));
},
];
}

/**
* @return array<string, mixed>
*/
private function encodeData(string $key, mixed $value): array
{
try {
$encodedValue = json_encode($value, \JSON_THROW_ON_ERROR);
} catch (\JsonException $exception) {
throw new JsonEncodingException(sprintf('Could not encode property "%s" into JSON', $key), previous: $exception);
}

return [$key => $encodedValue];
}

/**
* The Gotenberg API endpoint path.
*/
Expand Down
Loading