Skip to content

Commit

Permalink
[FEATURE] Allow Cookie object from http-foundation & ->forwardCookie(…
Browse files Browse the repository at this point in the history
…string $name) (#89)
  • Loading branch information
Neirda24 authored Jul 9, 2024
1 parent 224eb5b commit f323d27
Show file tree
Hide file tree
Showing 20 changed files with 279 additions and 242 deletions.
1 change: 1 addition & 0 deletions .php-cs-fixer.dist.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
;

return (new PhpCsFixer\Config())
->setParallelConfig(PhpCsFixer\Runner\Parallel\ParallelConfigFactory::detect())
->setUsingCache(false)
->setRiskyAllowed(true)
->setRules([
Expand Down
3 changes: 3 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('request_stack'),
service('twig')->nullOnInvalid(),
])
->call('setLogger', [service('logger')->nullOnInvalid()])
Expand All @@ -32,6 +33,7 @@
->args([
service('sensiolabs_gotenberg.client'),
service('sensiolabs_gotenberg.asset.base_dir_formatter'),
service('request_stack'),
service('twig')->nullOnInvalid(),
service('router')->nullOnInvalid(),
])
Expand All @@ -45,6 +47,7 @@
->args([
service('sensiolabs_gotenberg.client'),
service('sensiolabs_gotenberg.asset.base_dir_formatter'),
service('request_stack'),
service('twig')->nullOnInvalid(),
])
->call('setLogger', [service('logger')->nullOnInvalid()])
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('request_stack'),
service('twig')->nullOnInvalid(),
])
->call('setLogger', [service('logger')->nullOnInvalid()])
Expand All @@ -29,6 +30,7 @@
->args([
service('sensiolabs_gotenberg.client'),
service('sensiolabs_gotenberg.asset.base_dir_formatter'),
service('request_stack'),
service('twig')->nullOnInvalid(),
service('router')->nullOnInvalid(),
])
Expand All @@ -42,6 +44,7 @@
->args([
service('sensiolabs_gotenberg.client'),
service('sensiolabs_gotenberg.asset.base_dir_formatter'),
service('request_stack'),
service('twig')->nullOnInvalid(),
])
->call('setLogger', [service('logger')->nullOnInvalid()])
Expand Down
149 changes: 149 additions & 0 deletions src/Builder/CookieAwareTrait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
<?php

declare(strict_types=1);

namespace Sensiolabs\GotenbergBundle\Builder;

use Psr\Log\LoggerInterface;
use Symfony\Component\HttpFoundation\Cookie;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Mime\Part\DataPart;

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

/**
* @param array{cookies?: array<string, Cookie|array{name: string, value: string, domain: string, path?: string|null, secure?: bool|null, httpOnly?: bool|null, sameSite?: 'Strict'|'Lax'|null}>} $formFields
* @param list<Cookie|array{name: string, value: string, domain: string, path?: string|null, secure?: bool|null, httpOnly?: bool|null, sameSite?: 'Strict'|'Lax'|null}> $cookies
*/
private function withCookies(array &$formFields, array $cookies): static
{
if ([] === $cookies) {
unset($formFields['cookies']);

return $this;
}

$formFields['cookies'] = [];

foreach ($cookies as $cookie) {
if ($cookie instanceof Cookie) {
$this->setCookie($cookie->getName(), $cookie);

continue;
}

$this->setCookie($cookie['name'], $cookie);
}

return $this;
}

/**
* @param Cookie|array{name: string, value: string, domain: string, path?: string|null, secure?: bool|null, httpOnly?: bool|null, sameSite?: 'Strict'|'Lax'|null} $cookie
*/
abstract public function setCookie(string $key, Cookie|array $cookie): static;

/**
* @param array{cookies?: array<string, Cookie|array{name: string, value: string, domain: string, path?: string|null, secure?: bool|null, httpOnly?: bool|null, sameSite?: 'Strict'|'Lax'|null}>} $formFields
* @param Cookie|array{name: string, value: string, domain: string, path?: string|null, secure?: bool|null, httpOnly?: bool|null, sameSite?: 'Strict'|'Lax'|null} $cookie
*/
private function withCookie(array &$formFields, string $key, Cookie|array $cookie): static
{
$formFields['cookies'] ??= [];
$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<Cookie|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
{
foreach ($cookies as $cookie) {
if ($cookie instanceof Cookie) {
$this->setCookie($cookie->getName(), $cookie);

continue;
}

$this->setCookie($cookie['name'], $cookie);
}

return $this;
}

private function forwardCookieFromRequest(Request|null $request, string $key, LoggerInterface|null $logger = null): static
{
if (null === $request) {
$logger?->debug('Cookie {sensiolabs_gotenberg.cookie_name} cannot be forwarded because there is no Request.', [
'sensiolabs_gotenberg.cookie_name' => $key,
]);

return $this;
}

if (false === $request->cookies->has($key)) {
$logger?->debug('Cookie {sensiolabs_gotenberg.cookie_name} does not exists.', [
'sensiolabs_gotenberg.cookie_name' => $key,
]);

return $this;
}

$value = $request->cookies->get($key);
$domain = $request->getHost();

return $this->setCookie($key, [
'name' => $key,
'value' => $value,
'domain' => $domain,
]);
}

abstract public function forwardCookie(string $name): static;

/**
* @param (\Closure(string, mixed): array<string, mixed>) $encoder
*
* @return array<string, array<string|int, mixed>|string|\Stringable|int|float|bool|\BackedEnum|DataPart>
*/
private function cookieNormalizer(mixed $value, callable $encoder): array
{
$cookies = array_values($value);
$data = [];

foreach ($cookies as $cookie) {
if ($cookie instanceof Cookie) {
$data[] = [
'name' => $cookie->getName(),
'value' => $cookie->getValue(),
'domain' => $cookie->getDomain(),
'path' => $cookie->getPath(),
'secure' => $cookie->isSecure(),
'httpOnly' => $cookie->isHttpOnly(),
'sameSite' => null !== ($sameSite = $cookie->getSameSite()) ? ucfirst(strtolower($sameSite)) : null,
];

continue;
}

$data[] = $cookie;
}

return $encoder('cookies', $data);
}
}
2 changes: 1 addition & 1 deletion src/Builder/DefaultBuilderTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ protected function addNormalizer(string $key, \Closure $normalizer): void
/**
* @return array<string, mixed>
*/
private function encodeData(string $key, mixed $value): array
protected function encodeData(string $key, mixed $value): array
{
try {
$encodedValue = json_encode($value, \JSON_THROW_ON_ERROR);
Expand Down
104 changes: 53 additions & 51 deletions src/Builder/Pdf/AbstractChromiumPdfBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Sensiolabs\GotenbergBundle\Builder\Pdf;

use Sensiolabs\GotenbergBundle\Builder\CookieAwareTrait;
use Sensiolabs\GotenbergBundle\Client\GotenbergClientInterface;
use Sensiolabs\GotenbergBundle\Enumeration\EmulatedMediaType;
use Sensiolabs\GotenbergBundle\Enumeration\PaperSizeInterface;
Expand All @@ -11,18 +12,49 @@
use Sensiolabs\GotenbergBundle\Exception\InvalidBuilderConfiguration;
use Sensiolabs\GotenbergBundle\Exception\PdfPartRenderingException;
use Sensiolabs\GotenbergBundle\Formatter\AssetBaseDirFormatter;
use Symfony\Component\HttpFoundation\Cookie;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\Mime\Part\DataPart;
use Symfony\Component\Mime\Part\File as DataPartFile;
use Twig\Environment;

abstract class AbstractChromiumPdfBuilder extends AbstractPdfBuilder
{
use CookieAwareTrait;

public function __construct(
GotenbergClientInterface $gotenbergClient,
AssetBaseDirFormatter $asset,
private readonly RequestStack $requestStack,
private readonly Environment|null $twig = null,
) {
parent::__construct($gotenbergClient, $asset);

$normalizers = [
'extraHttpHeaders' => function (mixed $value): array {
return $this->encodeData('extraHttpHeaders', $value);
},
'assets' => static function (array $value): array {
return ['files' => $value];
},
Part::Header->value => static function (DataPart $value): array {
return ['files' => $value];
},
Part::Body->value => static function (DataPart $value): array {
return ['files' => $value];
},
Part::Footer->value => static function (DataPart $value): array {
return ['files' => $value];
},
'failOnHttpStatusCodes' => function (mixed $value): array {
return $this->encodeData('failOnHttpStatusCodes', $value);
},
'cookies' => fn (mixed $value): array => $this->cookieNormalizer($value, $this->encodeData(...)),
];

foreach ($normalizers as $key => $normalizer) {
$this->addNormalizer($key, $normalizer);
}
}

/**
Expand All @@ -39,6 +71,27 @@ public function setConfigurations(array $configurations): static
return $this;
}

/**
* @param list<Cookie|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
{
return $this->withCookies($this->formFields, $cookies);
}

/**
* @param Cookie|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, Cookie|array $cookie): static
{
return $this->withCookie($this->formFields, $key, $cookie);
}

public function forwardCookie(string $name): static
{
return $this->forwardCookieFromRequest($this->requestStack->getCurrentRequest(), $name, $this->logger);
}

/**
* Define whether to print the entire content in one single page.
*
Expand Down Expand Up @@ -322,57 +375,6 @@ public function emulatedMediaType(EmulatedMediaType $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
{
if ([] === $cookies) {
unset($this->formFields['cookies']);

return $this;
}

$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
{
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
23 changes: 0 additions & 23 deletions src/Builder/Pdf/AbstractPdfBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@
use Sensiolabs\GotenbergBundle\Builder\DefaultBuilderTrait;
use Sensiolabs\GotenbergBundle\Client\GotenbergClientInterface;
use Sensiolabs\GotenbergBundle\Client\GotenbergResponse;
use Sensiolabs\GotenbergBundle\Enumeration\Part;
use Sensiolabs\GotenbergBundle\Formatter\AssetBaseDirFormatter;
use Symfony\Component\Mime\Part\DataPart;

abstract class AbstractPdfBuilder implements PdfBuilderInterface
{
Expand All @@ -21,27 +19,6 @@ public function __construct(
$this->asset = $asset;

$this->normalizers = [
'extraHttpHeaders' => function (mixed $value): array {
return $this->encodeData('extraHttpHeaders', $value);
},
'assets' => static function (array $value): array {
return ['files' => $value];
},
Part::Header->value => static function (DataPart $value): array {
return ['files' => $value];
},
Part::Body->value => static function (DataPart $value): array {
return ['files' => $value];
},
Part::Footer->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));
},
'metadata' => function (mixed $value): array {
return $this->encodeData('metadata', $value);
},
Expand Down
Loading

0 comments on commit f323d27

Please sign in to comment.