From 4105571f36e1bd1edafa36a5e28bbdb6e37e9f00 Mon Sep 17 00:00:00 2001 From: Steven Renaux Date: Thu, 18 Sep 2025 17:10:57 +0200 Subject: [PATCH 1/8] Wip forwardAuthenticationCookie --- composer.json | 4 ++- .../Behaviors/Chromium/CookieTrait.php | 26 ++++++++++++++++++- .../Dependencies/RequestAwareTrait.php | 7 +++-- .../SecurityTokenStorageTrait.php | 25 ++++++++++++++++++ 4 files changed, 56 insertions(+), 6 deletions(-) create mode 100644 src/Builder/Behaviors/Dependencies/SecurityTokenStorageTrait.php diff --git a/composer.json b/composer.json index 61cbc3ec..7813078c 100644 --- a/composer.json +++ b/composer.json @@ -50,6 +50,7 @@ "symfony/http-client": "^6.4 || ^7.0", "symfony/monolog-bundle": "^3.10", "symfony/routing": "^6.4 || ^7.0", + "symfony/security-bundle": "^7.3", "symfony/stopwatch": "^6.4 || ^7.0", "symfony/twig-bundle": "^6.4 || ^7.0", "symfony/var-dumper": "^6.4 || ^7.0", @@ -68,6 +69,7 @@ "symfony/twig-bundle": "Allows you to use Twig to render templates into PDF.", "monolog/monolog": "Enables logging througout the generating process.", "async-aws/s3": "Upload any file to aws s3 compatible endpoints supporting multi part upload without memory overhead.", - "league/flysystem-bundle": "Upload any file using this filesystem abstraction package." + "league/flysystem-bundle": "Upload any file using this filesystem abstraction package.", + "symfony/security-bundle": "Allows you to generate PDF as a specific user." } } diff --git a/src/Builder/Behaviors/Chromium/CookieTrait.php b/src/Builder/Behaviors/Chromium/CookieTrait.php index 3ba20d51..1078eb3e 100644 --- a/src/Builder/Behaviors/Chromium/CookieTrait.php +++ b/src/Builder/Behaviors/Chromium/CookieTrait.php @@ -6,6 +6,7 @@ use Sensiolabs\GotenbergBundle\Builder\Attributes\WithConfigurationNode; use Sensiolabs\GotenbergBundle\Builder\Behaviors\Dependencies\LoggerAwareTrait; use Sensiolabs\GotenbergBundle\Builder\Behaviors\Dependencies\RequestAwareTrait; +use Sensiolabs\GotenbergBundle\Builder\Behaviors\Dependencies\SecurityTokenStorageTrait; use Sensiolabs\GotenbergBundle\Builder\BodyBag; use Sensiolabs\GotenbergBundle\Builder\Util\NormalizerFactory; use Sensiolabs\GotenbergBundle\Builder\Util\ValidatorFactory; @@ -14,6 +15,7 @@ use Sensiolabs\GotenbergBundle\NodeBuilder\EnumNodeBuilder; use Sensiolabs\GotenbergBundle\NodeBuilder\ScalarNodeBuilder; use Symfony\Component\HttpFoundation\Cookie; +use Symfony\Component\HttpFoundation\Request; /** * @see https://gotenberg.dev/docs/routes#cookies-chromium @@ -24,6 +26,7 @@ trait CookieTrait { use LoggerAwareTrait; use RequestAwareTrait; + use SecurityTokenStorageTrait; abstract protected function getBodyBag(): BodyBag; @@ -92,7 +95,7 @@ public function setCookie(string $name, Cookie|array $cookie): static public function forwardCookie(string $name): static { - $request = $this->getCurrentRequest(); + $request = $this->getRequestStack()->getCurrentRequest(); if (null === $request) { $this->getLogger()?->debug('Cookie {sensiolabs_gotenberg.cookie_name} cannot be forwarded because there is no Request.', [ @@ -102,6 +105,26 @@ public function forwardCookie(string $name): static return $this; } + return $this->setForwardCookie($request, $name); + } + + public function forwardAuthentication(): static + { + $request = $this->getRequestStack()->getCurrentRequest(); + + if (null === $request) { + $this->getLogger()?->debug('Cookie cannot be forwarded with authentication because there is no Request.'); + + return $this; + } + + $request->getSession()->save(); + + return $this->setForwardCookie($request, $request->getSession()->getName()); + } + + private function setForwardCookie(Request $request, string $name): static + { if (false === $request->cookies->has($name)) { $this->getLogger()?->debug('Cookie {sensiolabs_gotenberg.cookie_name} does not exists.', [ 'sensiolabs_gotenberg.cookie_name' => $name, @@ -110,6 +133,7 @@ public function forwardCookie(string $name): static return $this; } + // In docker context: $request->getHost() = localhost (don't work) but works with docker service name, maybe get host from request_context? return $this->setCookie($name, [ 'name' => $name, 'value' => (string) $request->cookies->get($name), diff --git a/src/Builder/Behaviors/Dependencies/RequestAwareTrait.php b/src/Builder/Behaviors/Dependencies/RequestAwareTrait.php index a4230d50..187da1c0 100644 --- a/src/Builder/Behaviors/Dependencies/RequestAwareTrait.php +++ b/src/Builder/Behaviors/Dependencies/RequestAwareTrait.php @@ -2,7 +2,6 @@ namespace Sensiolabs\GotenbergBundle\Builder\Behaviors\Dependencies; -use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Contracts\Service\Attribute\SubscribedService; use Symfony\Contracts\Service\ServiceSubscriberTrait; @@ -11,8 +10,8 @@ trait RequestAwareTrait { use ServiceSubscriberTrait; - #[SubscribedService('request_stack', nullable: true)] - protected function getCurrentRequest(): Request|null + #[SubscribedService('request_stack')] + protected function getRequestStack(): RequestStack { if ( !$this->container->has('request_stack') @@ -21,6 +20,6 @@ protected function getCurrentRequest(): Request|null throw new \LogicException(\sprintf('RequestStack is required to use "%s" method. Try to run "composer require symfony/http-foundation".', __METHOD__)); } - return $requestStack->getCurrentRequest(); + return $requestStack; } } diff --git a/src/Builder/Behaviors/Dependencies/SecurityTokenStorageTrait.php b/src/Builder/Behaviors/Dependencies/SecurityTokenStorageTrait.php new file mode 100644 index 00000000..6e49d7d6 --- /dev/null +++ b/src/Builder/Behaviors/Dependencies/SecurityTokenStorageTrait.php @@ -0,0 +1,25 @@ +container->has('security.token_storage') + || !($security = $this->container->get('security.token_storage')) instanceof TokenStorageInterface + ) { + throw new \LogicException(\sprintf('Security is required to use "%s" method. Try to run "composer require symfony/security-bundle".', __METHOD__)); + } + + return $security; + } +} From c351d9c133ffb7a7815e78d1f5cbb1953d63fe83 Mon Sep 17 00:00:00 2001 From: Steven Renaux Date: Fri, 19 Sep 2025 11:12:41 +0200 Subject: [PATCH 2/8] Fix RequestContext --- src/Builder/Behaviors/Chromium/CookieTrait.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Builder/Behaviors/Chromium/CookieTrait.php b/src/Builder/Behaviors/Chromium/CookieTrait.php index 1078eb3e..8bbf3ff4 100644 --- a/src/Builder/Behaviors/Chromium/CookieTrait.php +++ b/src/Builder/Behaviors/Chromium/CookieTrait.php @@ -6,6 +6,7 @@ use Sensiolabs\GotenbergBundle\Builder\Attributes\WithConfigurationNode; use Sensiolabs\GotenbergBundle\Builder\Behaviors\Dependencies\LoggerAwareTrait; use Sensiolabs\GotenbergBundle\Builder\Behaviors\Dependencies\RequestAwareTrait; +use Sensiolabs\GotenbergBundle\Builder\Behaviors\Dependencies\RequestContextAwareTrait; use Sensiolabs\GotenbergBundle\Builder\Behaviors\Dependencies\SecurityTokenStorageTrait; use Sensiolabs\GotenbergBundle\Builder\BodyBag; use Sensiolabs\GotenbergBundle\Builder\Util\NormalizerFactory; @@ -27,6 +28,7 @@ trait CookieTrait use LoggerAwareTrait; use RequestAwareTrait; use SecurityTokenStorageTrait; + use RequestContextAwareTrait; abstract protected function getBodyBag(): BodyBag; @@ -133,11 +135,10 @@ private function setForwardCookie(Request $request, string $name): static return $this; } - // In docker context: $request->getHost() = localhost (don't work) but works with docker service name, maybe get host from request_context? return $this->setCookie($name, [ 'name' => $name, 'value' => (string) $request->cookies->get($name), - 'domain' => $request->getHost(), + 'domain' => $this->getRequestContext()?->getHost() ?? $request->getHost(), ]); } From 25269904968b5ec5457c4de4acabffc897bf1149 Mon Sep 17 00:00:00 2001 From: Steven Renaux Date: Mon, 22 Sep 2025 11:10:36 +0200 Subject: [PATCH 3/8] Add asUser method --- composer.json | 2 +- .../Behaviors/Chromium/CookieTrait.php | 28 +++++++++++++++++-- .../SecurityTokenStorageTrait.php | 25 ----------------- 3 files changed, 27 insertions(+), 28 deletions(-) delete mode 100644 src/Builder/Behaviors/Dependencies/SecurityTokenStorageTrait.php diff --git a/composer.json b/composer.json index 7813078c..f9546b6d 100644 --- a/composer.json +++ b/composer.json @@ -50,7 +50,7 @@ "symfony/http-client": "^6.4 || ^7.0", "symfony/monolog-bundle": "^3.10", "symfony/routing": "^6.4 || ^7.0", - "symfony/security-bundle": "^7.3", + "symfony/security-bundle": "^6.4 || ^7.0", "symfony/stopwatch": "^6.4 || ^7.0", "symfony/twig-bundle": "^6.4 || ^7.0", "symfony/var-dumper": "^6.4 || ^7.0", diff --git a/src/Builder/Behaviors/Chromium/CookieTrait.php b/src/Builder/Behaviors/Chromium/CookieTrait.php index 8bbf3ff4..a32521cf 100644 --- a/src/Builder/Behaviors/Chromium/CookieTrait.php +++ b/src/Builder/Behaviors/Chromium/CookieTrait.php @@ -7,7 +7,6 @@ use Sensiolabs\GotenbergBundle\Builder\Behaviors\Dependencies\LoggerAwareTrait; use Sensiolabs\GotenbergBundle\Builder\Behaviors\Dependencies\RequestAwareTrait; use Sensiolabs\GotenbergBundle\Builder\Behaviors\Dependencies\RequestContextAwareTrait; -use Sensiolabs\GotenbergBundle\Builder\Behaviors\Dependencies\SecurityTokenStorageTrait; use Sensiolabs\GotenbergBundle\Builder\BodyBag; use Sensiolabs\GotenbergBundle\Builder\Util\NormalizerFactory; use Sensiolabs\GotenbergBundle\Builder\Util\ValidatorFactory; @@ -17,6 +16,9 @@ use Sensiolabs\GotenbergBundle\NodeBuilder\ScalarNodeBuilder; use Symfony\Component\HttpFoundation\Cookie; use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Session\Session; +use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken; +use Symfony\Component\Security\Core\User\UserInterface; /** * @see https://gotenberg.dev/docs/routes#cookies-chromium @@ -27,7 +29,6 @@ trait CookieTrait { use LoggerAwareTrait; use RequestAwareTrait; - use SecurityTokenStorageTrait; use RequestContextAwareTrait; abstract protected function getBodyBag(): BodyBag; @@ -125,6 +126,29 @@ public function forwardAuthentication(): static return $this->setForwardCookie($request, $request->getSession()->getName()); } + public function asUser(UserInterface $user, string $firewallName = 'main'): static + { + if (!class_exists(UsernamePasswordToken::class)) { + throw new \LogicException(\sprintf('UsernamePasswordToken is required to use "%s" method. Try to run "composer require symfony/security-bundle".', __METHOD__)); + } + + $token = new UsernamePasswordToken($user, $firewallName, $user->getRoles()); + + $session = new Session(); + $session->set('_security_'.$firewallName, serialize($token)); + $session->save(); + + $request = new Request(); + $request->setSession($session); + $this->getRequestStack()->push($request); + + return $this->setCookie($request->getSession()->getName(), [ + 'name' => $request->getSession()->getName(), + 'value' => $request->getSession()->getId(), + 'domain' => $this->getRequestContext()?->getHost(), + ]); + } + private function setForwardCookie(Request $request, string $name): static { if (false === $request->cookies->has($name)) { diff --git a/src/Builder/Behaviors/Dependencies/SecurityTokenStorageTrait.php b/src/Builder/Behaviors/Dependencies/SecurityTokenStorageTrait.php deleted file mode 100644 index 6e49d7d6..00000000 --- a/src/Builder/Behaviors/Dependencies/SecurityTokenStorageTrait.php +++ /dev/null @@ -1,25 +0,0 @@ -container->has('security.token_storage') - || !($security = $this->container->get('security.token_storage')) instanceof TokenStorageInterface - ) { - throw new \LogicException(\sprintf('Security is required to use "%s" method. Try to run "composer require symfony/security-bundle".', __METHOD__)); - } - - return $security; - } -} From 2ff794902cd8200820b9dc07106e1a987f5770b7 Mon Sep 17 00:00:00 2001 From: Steven Renaux Date: Mon, 22 Sep 2025 13:16:01 +0200 Subject: [PATCH 4/8] Add tests --- .../Behaviors/Chromium/CookieTrait.php | 3 ++ .../Chromium/CookieTestCaseTrait.php | 39 ++++++++++++++++++- tests/Fixtures/Entity/FakeUser.php | 29 ++++++++++++++ 3 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 tests/Fixtures/Entity/FakeUser.php diff --git a/src/Builder/Behaviors/Chromium/CookieTrait.php b/src/Builder/Behaviors/Chromium/CookieTrait.php index a32521cf..21726ea2 100644 --- a/src/Builder/Behaviors/Chromium/CookieTrait.php +++ b/src/Builder/Behaviors/Chromium/CookieTrait.php @@ -126,6 +126,9 @@ public function forwardAuthentication(): static return $this->setForwardCookie($request, $request->getSession()->getName()); } + /** + * Usage for CLI command. + */ public function asUser(UserInterface $user, string $firewallName = 'main'): static { if (!class_exists(UsernamePasswordToken::class)) { diff --git a/tests/Builder/Behaviors/Chromium/CookieTestCaseTrait.php b/tests/Builder/Behaviors/Chromium/CookieTestCaseTrait.php index ce79a3a6..77ecace9 100644 --- a/tests/Builder/Behaviors/Chromium/CookieTestCaseTrait.php +++ b/tests/Builder/Behaviors/Chromium/CookieTestCaseTrait.php @@ -5,9 +5,12 @@ use Psr\Log\LoggerInterface; use Sensiolabs\GotenbergBundle\Builder\BuilderInterface; use Sensiolabs\GotenbergBundle\Tests\Builder\Behaviors\BehaviorTrait; +use Sensiolabs\GotenbergBundle\Tests\Fixtures\Entity\FakeUser; use Symfony\Component\HttpFoundation\Cookie; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RequestStack; +use Symfony\Component\HttpFoundation\Session\Session; +use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken; /** * @template T of BuilderInterface @@ -175,10 +178,44 @@ public function testToForwardCookiesWithCurrentRequestWithoutCookies(): void public function testRequestStackDependencyRequirementForForwardCookies(): void { $this->expectException(\LogicException::class); - $this->expectExceptionMessage('RequestStack is required to use "Sensiolabs\GotenbergBundle\Builder\Behaviors\Dependencies\RequestAwareTrait::getCurrentRequest" method. Try to run "composer require symfony/http-foundation".'); + $this->expectExceptionMessage('RequestStack is required to use "Sensiolabs\GotenbergBundle\Builder\Behaviors\Dependencies\RequestAwareTrait::getRequestStack" method. Try to run "composer require symfony/http-foundation".'); $this->getDefaultBuilder() ->forwardCookie('my_cookie') ; } + + public function testForwardAuthentication(): void + { + $request = new Request(); + $request->setMethod('GET'); + $request->setSession(new Session()); + $request->cookies->set($request->getSession()->getName(), $request->getSession()->getId()); + + $requestStack = new RequestStack(); + $requestStack->push($request); + + $this->container->set('request_stack', $requestStack); + + $builder = $this->getDefaultBuilder() + ->forwardAuthentication() + ; + + self::assertArrayHasKey('cookies', $builder->getBodyBag()->all()); + + $cookies = $builder->getBodyBag()->all()['cookies']; + self::assertSame($cookies[$request->getSession()->getName()]['name'], $request->getSession()->getName()); + self::assertSame($cookies[$request->getSession()->getName()]['value'], $request->getSession()->getId()); + } + + public function testAsUser(): void + { + $this->container->set('request_stack', new RequestStack()); + + $builder = $this->getDefaultBuilder() + ->asUser(new FakeUser()) + ; + + self::assertArrayHasKey('cookies', $builder->getBodyBag()->all()); + } } diff --git a/tests/Fixtures/Entity/FakeUser.php b/tests/Fixtures/Entity/FakeUser.php new file mode 100644 index 00000000..fe986ce7 --- /dev/null +++ b/tests/Fixtures/Entity/FakeUser.php @@ -0,0 +1,29 @@ + Date: Mon, 22 Sep 2025 13:38:00 +0200 Subject: [PATCH 5/8] Add documentation --- docs/pdf/customization.md | 213 +++++++++++++----- docs/screenshot/customization.md | 147 ++++++++++-- .../Behaviors/Chromium/CookieTrait.php | 2 +- 3 files changed, 280 insertions(+), 82 deletions(-) diff --git a/docs/pdf/customization.md b/docs/pdf/customization.md index 7c0d25ad..6fff9b65 100644 --- a/docs/pdf/customization.md +++ b/docs/pdf/customization.md @@ -1,63 +1,66 @@ # PDF customization -> [!NOTE] +> [!NOTE] > All of these functions are available for `HtmlPdfBuilder`, `UrlPdfBuilder` and -> `MarkdownPdfBuilder`. +> `MarkdownPdfBuilder`. > To customize `LibreOfficePdfBuilder` see the related [documentation](office-builder.md). ## Available functions ### Render -[paperSize](#paperSize) -[paperStandardSize](#paperStandardSize) -[paperWidth](#paperWidth) -[paperHeight](#paperHeight) -[margins](#margins) -[marginTop](#margins) -[marginBottom](#margins) -[marginLeft](#margins) -[marginRight](#margins) -[preferCssPageSize](#preferCssPageSize) -[printBackground](#printBackground) -[omitBackground](#omitBackground) -[landscape](#landscape) -[scale](#scale) -[nativePageRanges](#nativePageRanges) -[splitMode](#splitMode) -[splitSpan](#splitSpan) -[splitUnify](#splitUnify) - -### Additional content -[header and footer](#header-and-footer) -[headerFile and footerFile](#headerfile-and-footerfile) +[paperSize](#paperSize) +[paperStandardSize](#paperStandardSize) +[paperWidth](#paperWidth) +[paperHeight](#paperHeight) +[margins](#margins) +[marginTop](#margins) +[marginBottom](#margins) +[marginLeft](#margins) +[marginRight](#margins) +[preferCssPageSize](#preferCssPageSize) +[printBackground](#printBackground) +[omitBackground](#omitBackground) +[landscape](#landscape) +[scale](#scale) +[nativePageRanges](#nativePageRanges) +[splitMode](#splitMode) +[splitSpan](#splitSpan) +[splitUnify](#splitUnify) + +### Additional content +[header and footer](#header-and-footer) +[headerFile and footerFile](#headerfile-and-footerfile) [download from](#download-from) ### Style -[assets](../assets.md) -[addAsset](../assets.md) +[assets](../assets.md) +[addAsset](../assets.md) ### Request -[waitDelay](#waitDelay) -[waitForExpression](#waitForExpression) -[emulatedMediaType](#emulatedMediaType) -[cookies](#cookies) -[setCookie](#setCookie) -[addCookies](#addCookies) -[userAgent](#userAgent) -[extraHttpHeaders](#extraHttpHeaders) -[addExtraHttpHeaders](#addExtraHttpHeaders) -[failOnHttpStatusCodes](#failOnHttpStatusCodes) -[failOnResourceHttpStatusCodes](#failOnResourceHttpStatusCodes) -[failOnResourceLoadingFailed](#failOnResourceLoadingFailed) -[failOnConsoleExceptions](#failOnConsoleExceptions) -[skipNetworkIdleEvent](#skipNetworkIdleEvent) +[waitDelay](#waitDelay) +[waitForExpression](#waitForExpression) +[emulatedMediaType](#emulatedMediaType) +[cookies](#cookies) +[setCookie](#setCookie) +[addCookies](#addCookies) +[forwardCookie](#forwardCookie) +[forwardAuthentication](#forwardAuthentication) +[asUser](#asUser) +[userAgent](#userAgent) +[extraHttpHeaders](#extraHttpHeaders) +[addExtraHttpHeaders](#addExtraHttpHeaders) +[failOnHttpStatusCodes](#failOnHttpStatusCodes) +[failOnResourceHttpStatusCodes](#failOnResourceHttpStatusCodes) +[failOnResourceLoadingFailed](#failOnResourceLoadingFailed) +[failOnConsoleExceptions](#failOnConsoleExceptions) +[skipNetworkIdleEvent](#skipNetworkIdleEvent) ### Formatting -[metadata](#metadata) -[addMetadata](#addMetadata) -[pdfFormat](#pdfFormat) -[pdfUniversalAccess](#pdfUniversalAccess) -[generateDocumentOutline](#generateDocumentOutline) +[metadata](#metadata) +[addMetadata](#addMetadata) +[pdfFormat](#pdfFormat) +[pdfUniversalAccess](#pdfUniversalAccess) +[generateDocumentOutline](#generateDocumentOutline) [generateTaggedPdf](#generateTaggedPdf) ## Render @@ -66,7 +69,7 @@ Default: `8.5 inches x 11 inches` -You can override the default paper size with `height`, `width` and `unit`. +You can override the default paper size with `height`, `width` and `unit`. `unit` is optional but by default in inches. ```php @@ -135,7 +138,7 @@ class MyInvoiceSize implements PaperSizeInterface { return 200; } - + public function unit(): Unit { return Unit::Inches; @@ -147,7 +150,7 @@ class MyInvoiceSize implements PaperSizeInterface Default: `8.5 inches` -You can override the default `width` and `unit`. +You can override the default `width` and `unit`. `unit` is optional but by default in inches. ```php @@ -179,7 +182,7 @@ class YourController Default: `11 inches` -You can override the default `height` and `unit`. +You can override the default `height` and `unit`. `unit` is optional but by default in inches. ```php @@ -211,8 +214,8 @@ class YourController Default: `0.39 inches` on all four sides -You can override the default margins, with the arguments `top`, `bottom`, `right`, -`left` and `unit`. +You can override the default margins, with the arguments `top`, `bottom`, `right`, +`left` and `unit`. `unit` is optional but by default in inches. ```php @@ -237,7 +240,7 @@ class YourController } ``` -Or you can override all margins individually with respective `unit`. +Or you can override all margins individually with respective `unit`. `unit` is always optional but by default in inches. ```php @@ -521,7 +524,7 @@ class YourController ## Additional content -> [!WARNING] +> [!WARNING] > Every Header or Footer templates you pass to Gotenberg need to have > the following structure. > ```html @@ -537,7 +540,7 @@ class YourController > > ``` > -> Some other limitations exist about header and footer. +> Some other limitations exist about header and footer. > For more information about [Header and Footer](https://gotenberg.dev/docs/routes#header-footer-chromium). ### header and footer @@ -574,9 +577,9 @@ class YourController ### headerFile and footerFile -> [!WARNING] +> [!WARNING] > As assets files, by default the HTML files are fetch in the assets folder of -> your application. +> your application. > If your HTML files are in another folder, you can override the default value > of assets_directory in your configuration file config/sensiolabs_gotenberg.yml. @@ -626,7 +629,7 @@ class YourController ### download from -> [!WARNING] +> [!WARNING] > URL of the file. It MUST return a `Content-Disposition` header with a filename parameter. To download files resource from URLs. @@ -652,7 +655,7 @@ class YourController ], [ 'url' => 'http://example.com/url/to/file', - 'extraHttpHeaders' => + 'extraHttpHeaders' => [ 'MyHeaderOne' => 'MyValue', 'MyHeaderTwo' => 'MyValue', @@ -872,6 +875,96 @@ class YourController } ``` +### forwardCookie + +If you want to forward existing cookie from the current request. + +```php +namespace App\Controller; + +use Sensiolabs\GotenbergBundle\GotenbergPdfInterface; + +class YourController +{ + public function yourControllerMethod(GotenbergPdfInterface $gotenberg): Response + { + return $gotenberg + ->html() + ->content('content.html.twig', [ + 'my_var' => 'value' + ]) + ->forwardCookie('my_cookie') + ->generate() + ->stream() + ; + } +} +``` + +### forwardAuthentication + +If you want to forward the authentication cookie from the current request. +Can be useful to generate a PDF from restricted route. + +```php +namespace App\Controller; + +use Sensiolabs\GotenbergBundle\GotenbergPdfInterface; + +class YourController +{ + public function yourControllerMethod(GotenbergPdfInterface $gotenberg): Response + { + return $gotenberg + ->url() + ->route('auth_route') + ->forwardAuthentication() + ->generate() + ->stream() + ; + } +} +``` + +### asUser + +If you want to generate a PDF for a restricted route in a CLI context. + +```php +namespace App\Controller; + +use Sensiolabs\GotenbergBundle\GotenbergPdfInterface; + +#[AsCommand(name: 'app:create-pdf', description: 'Create pdf')] +final class CreatePdf extends Command +{ + public function __construct( + private readonly GotenbergPdfInterface $gotenberg, + private readonly UserProviderInterface $userProvider, + ) { + parent::__construct(); + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + $user = $this->userProvider->loadUserByIdentifier('john_doe'); + + return $this->gotenberg + ->url() + ->route('auth_route') + ->asUser($user) + ->processor(new FileProcessor(new Filesystem(), dirname(__DIR__).'/../var/pdf')) + ->generate() + ->process() + ; + + $output->writeln('PDF generated'); + + return Command::SUCCESS; + } +} +``` + ### userAgent() default: `None` @@ -997,7 +1090,7 @@ class YourController default: `None` -Return a 409 Conflict response if the HTTP status code from at least one resource +Return a 409 Conflict response if the HTTP status code from at least one resource is not acceptable. ```php @@ -1029,7 +1122,7 @@ class YourController default: `false` -Return a 409 Conflict response if there are exceptions to load at least one resource +Return a 409 Conflict response if there are exceptions to load at least one resource in the Chromium. ```php diff --git a/docs/screenshot/customization.md b/docs/screenshot/customization.md index a9a95cb1..4807a017 100644 --- a/docs/screenshot/customization.md +++ b/docs/screenshot/customization.md @@ -3,34 +3,37 @@ ## Available functions ### Render -[width](#width) -[height](#height) -[clip](#clip) -[quality](#quality) -[omitBackground](#omitBackground) +[width](#width) +[height](#height) +[clip](#clip) +[quality](#quality) +[omitBackground](#omitBackground) ### Additional content [download from](#download-from) ### Style -[assets](../assets.md) +[assets](../assets.md) [addAsset](../assets.md) ### Request [optimizeForSpeed](#optimizeForSpeed) -[waitDelay](#waitDelay) -[waitForExpression](#waitForExpression) -[emulatedMediaType](#emulatedMediaType) -[cookies](#cookies) -[setCookie](#setCookie) -[addCookies](#addCookies) -[userAgent](#userAgent) -[extraHttpHeaders](#extraHttpHeaders) -[addExtraHttpHeaders](#addExtraHttpHeaders) -[failOnHttpStatusCodes](#failOnHttpStatusCodes) -[failOnResourceHttpStatusCodes](#failOnResourceHttpStatusCodes) -[failOnResourceLoadingFailed](#failOnResourceLoadingFailed) -[failOnConsoleExceptions](#failOnConsoleExceptions) +[waitDelay](#waitDelay) +[waitForExpression](#waitForExpression) +[emulatedMediaType](#emulatedMediaType) +[cookies](#cookies) +[setCookie](#setCookie) +[addCookies](#addCookies) +[forwardCookie](#forwardCookie) +[forwardAuthentication](#forwardAuthentication) +[asUser](#asUser) +[userAgent](#userAgent) +[extraHttpHeaders](#extraHttpHeaders) +[addExtraHttpHeaders](#addExtraHttpHeaders) +[failOnHttpStatusCodes](#failOnHttpStatusCodes) +[failOnResourceHttpStatusCodes](#failOnResourceHttpStatusCodes) +[failOnResourceLoadingFailed](#failOnResourceLoadingFailed) +[failOnConsoleExceptions](#failOnConsoleExceptions) [skipNetworkIdleEvent](#skipNetworkIdleEvent) ### Formatting @@ -191,7 +194,7 @@ class YourController ### download from -> [!WARNING] +> [!WARNING] > URL of the file. It MUST return a `Content-Disposition` header with a filename parameter. To download files resource from URLs. @@ -217,7 +220,7 @@ class YourController ], [ 'url' => 'http://example.com/url/to/file', - 'extraHttpHeaders' => + 'extraHttpHeaders' => [ 'MyHeaderOne' => 'MyValue', 'MyHeaderTwo' => 'MyValue', @@ -283,6 +286,9 @@ class YourController { return $gotenberg ->html() + ->content('twig_simple_pdf.html.twig', [ + 'my_var' => 'value' + ]) ->waitDelay('5s') ->generate() ->stream() @@ -309,6 +315,9 @@ class YourController { return $gotenberg ->html() + ->content('twig_simple_pdf.html.twig', [ + 'my_var' => 'value' + ]) ->waitForExpression("window.globalVar === 'ready'") ->generate() ->stream() @@ -400,6 +409,9 @@ class YourController { return $gotenberg ->html() + ->content('twig_simple_pdf.html.twig', [ + 'my_var' => 'value' + ]) ->setCookie([ 'name' => 'my_cookie', 'value' => 'symfony', @@ -431,6 +443,9 @@ class YourController { return $gotenberg ->html() + ->content('twig_simple_pdf.html.twig', [ + 'my_var' => 'value' + ]) ->addCookies([[ 'name' => 'my_cookie', 'value' => 'symfony', @@ -446,6 +461,96 @@ class YourController } ``` +### forwardCookie + +If you want to forward existing cookie from the current request. + +```php +namespace App\Controller; + +use Sensiolabs\GotenbergBundle\GotenbergScreenshotInterface; + +class YourController +{ + public function yourControllerMethod(GotenbergScreenshotInterface $gotenberg): Response + { + return $gotenberg + ->html() + ->content('content.html.twig', [ + 'my_var' => 'value' + ]) + ->forwardCookie('my_cookie') + ->generate() + ->stream() + ; + } +} +``` + +### forwardAuthentication + +If you want to forward the authentication cookie from the current request. +Can be useful to generate a screenshot from restricted route. + +```php +namespace App\Controller; + +use Sensiolabs\GotenbergBundle\GotenbergScreenshotInterface; + +class YourController +{ + public function yourControllerMethod(GotenbergScreenshotInterface $gotenberg): Response + { + return $gotenberg + ->url() + ->route('auth_route') + ->forwardAuthentication() + ->generate() + ->stream() + ; + } +} +``` + +### asUser + +If you want to generate a screenshot for a restricted route in a CLI context. + +```php +namespace App\Controller; + +use Sensiolabs\GotenbergBundle\GotenbergScreenshotInterface; + +#[AsCommand(name: 'app:create-pdf', description: 'Create pdf')] +final class CreatePdf extends Command +{ + public function __construct( + private readonly GotenbergScreenshotInterface $gotenberg, + private readonly UserProviderInterface $userProvider, + ) { + parent::__construct(); + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + $user = $this->userProvider->loadUserByIdentifier('john_doe'); + + return $this->gotenberg + ->url() + ->route('auth_route') + ->asUser($user) + ->processor(new FileProcessor(new Filesystem(), dirname(__DIR__).'/../var/screenshot')) + ->generate() + ->process() + ; + + $output->writeln('PDF generated'); + + return Command::SUCCESS; + } +} +``` + ### userAgent() default: `None` diff --git a/src/Builder/Behaviors/Chromium/CookieTrait.php b/src/Builder/Behaviors/Chromium/CookieTrait.php index 21726ea2..a4e04c58 100644 --- a/src/Builder/Behaviors/Chromium/CookieTrait.php +++ b/src/Builder/Behaviors/Chromium/CookieTrait.php @@ -127,7 +127,7 @@ public function forwardAuthentication(): static } /** - * Usage for CLI command. + * For CLI generation usage. */ public function asUser(UserInterface $user, string $firewallName = 'main'): static { From b3e6482aa866976bb56e0f8987d5d84f5b147b2d Mon Sep 17 00:00:00 2001 From: Steven Renaux Date: Mon, 22 Sep 2025 13:38:17 +0200 Subject: [PATCH 6/8] Add API doc --- docs/pdf/builders_api/HtmlPdfBuilder.md | 4 ++++ docs/pdf/builders_api/MarkdownPdfBuilder.md | 4 ++++ docs/pdf/builders_api/UrlPdfBuilder.md | 4 ++++ docs/screenshot/builders_api/HtmlScreenshotBuilder.md | 4 ++++ docs/screenshot/builders_api/MarkdownScreenshotBuilder.md | 4 ++++ docs/screenshot/builders_api/UrlScreenshotBuilder.md | 4 ++++ 6 files changed, 24 insertions(+) diff --git a/docs/pdf/builders_api/HtmlPdfBuilder.md b/docs/pdf/builders_api/HtmlPdfBuilder.md index 130eb3cf..a57e80f1 100644 --- a/docs/pdf/builders_api/HtmlPdfBuilder.md +++ b/docs/pdf/builders_api/HtmlPdfBuilder.md @@ -64,7 +64,11 @@ Sets the webhook for cases of success.
Optionally sets a custom HTTP method ### addCookies(array $cookies) Add cookies to store in the Chromium cookie jar.
+### asUser(Symfony\Component\Security\Core\User\UserInterface $user, string $firewallName) +For CLI generation usage. + ### cookies(array $cookies) +### forwardAuthentication() ### forwardCookie(string $name) ### setCookie(string $name, Symfony\Component\HttpFoundation\Cookie|array $cookie) ### generateDocumentOutline(bool $bool) diff --git a/docs/pdf/builders_api/MarkdownPdfBuilder.md b/docs/pdf/builders_api/MarkdownPdfBuilder.md index 463e1edb..8ad810cf 100644 --- a/docs/pdf/builders_api/MarkdownPdfBuilder.md +++ b/docs/pdf/builders_api/MarkdownPdfBuilder.md @@ -76,7 +76,11 @@ Sets the webhook for cases of success.
Optionally sets a custom HTTP method ### addCookies(array $cookies) Add cookies to store in the Chromium cookie jar.
+### asUser(Symfony\Component\Security\Core\User\UserInterface $user, string $firewallName) +For CLI generation usage. + ### cookies(array $cookies) +### forwardAuthentication() ### forwardCookie(string $name) ### setCookie(string $name, Symfony\Component\HttpFoundation\Cookie|array $cookie) ### generateDocumentOutline(bool $bool) diff --git a/docs/pdf/builders_api/UrlPdfBuilder.md b/docs/pdf/builders_api/UrlPdfBuilder.md index cbfaf1a2..f22f3003 100644 --- a/docs/pdf/builders_api/UrlPdfBuilder.md +++ b/docs/pdf/builders_api/UrlPdfBuilder.md @@ -74,7 +74,11 @@ Sets the webhook for cases of success.
Optionally sets a custom HTTP method ### addCookies(array $cookies) Add cookies to store in the Chromium cookie jar.
+### asUser(Symfony\Component\Security\Core\User\UserInterface $user, string $firewallName) +For CLI generation usage. + ### cookies(array $cookies) +### forwardAuthentication() ### forwardCookie(string $name) ### setCookie(string $name, Symfony\Component\HttpFoundation\Cookie|array $cookie) ### generateDocumentOutline(bool $bool) diff --git a/docs/screenshot/builders_api/HtmlScreenshotBuilder.md b/docs/screenshot/builders_api/HtmlScreenshotBuilder.md index 492d49ff..1b7560d0 100644 --- a/docs/screenshot/builders_api/HtmlScreenshotBuilder.md +++ b/docs/screenshot/builders_api/HtmlScreenshotBuilder.md @@ -36,7 +36,11 @@ Sets the webhook for cases of success.
Optionally sets a custom HTTP method ### addCookies(array $cookies) Add cookies to store in the Chromium cookie jar.
+### asUser(Symfony\Component\Security\Core\User\UserInterface $user, string $firewallName) +For CLI generation usage. + ### cookies(array $cookies) +### forwardAuthentication() ### forwardCookie(string $name) ### setCookie(string $name, Symfony\Component\HttpFoundation\Cookie|array $cookie) ### clip(bool $bool) diff --git a/docs/screenshot/builders_api/MarkdownScreenshotBuilder.md b/docs/screenshot/builders_api/MarkdownScreenshotBuilder.md index 4fec9639..f5de81d5 100644 --- a/docs/screenshot/builders_api/MarkdownScreenshotBuilder.md +++ b/docs/screenshot/builders_api/MarkdownScreenshotBuilder.md @@ -48,7 +48,11 @@ Sets the webhook for cases of success.
Optionally sets a custom HTTP method ### addCookies(array $cookies) Add cookies to store in the Chromium cookie jar.
+### asUser(Symfony\Component\Security\Core\User\UserInterface $user, string $firewallName) +For CLI generation usage. + ### cookies(array $cookies) +### forwardAuthentication() ### forwardCookie(string $name) ### setCookie(string $name, Symfony\Component\HttpFoundation\Cookie|array $cookie) ### clip(bool $bool) diff --git a/docs/screenshot/builders_api/UrlScreenshotBuilder.md b/docs/screenshot/builders_api/UrlScreenshotBuilder.md index a2942e4d..bd0f5f17 100644 --- a/docs/screenshot/builders_api/UrlScreenshotBuilder.md +++ b/docs/screenshot/builders_api/UrlScreenshotBuilder.md @@ -45,7 +45,11 @@ Sets the webhook for cases of success.
Optionally sets a custom HTTP method ### addCookies(array $cookies) Add cookies to store in the Chromium cookie jar.
+### asUser(Symfony\Component\Security\Core\User\UserInterface $user, string $firewallName) +For CLI generation usage. + ### cookies(array $cookies) +### forwardAuthentication() ### forwardCookie(string $name) ### setCookie(string $name, Symfony\Component\HttpFoundation\Cookie|array $cookie) ### clip(bool $bool) From d56e194d0acd312c893f61c75f162d3d6533479e Mon Sep 17 00:00:00 2001 From: Steven Renaux Date: Mon, 22 Sep 2025 13:55:13 +0200 Subject: [PATCH 7/8] Fix CS fixer + composer-dependency --- composer.json | 5 +- docs/pdf/customization.md | 126 +++++++++--------- docs/screenshot/customization.md | 52 ++++---- .../Behaviors/Chromium/CookieTrait.php | 2 +- .../Chromium/CookieTestCaseTrait.php | 1 - tests/Fixtures/Entity/FakeUser.php | 5 - 6 files changed, 95 insertions(+), 96 deletions(-) diff --git a/composer.json b/composer.json index f9546b6d..be32567c 100644 --- a/composer.json +++ b/composer.json @@ -32,6 +32,7 @@ "symfony/http-foundation": "^6.4 || ^7.0", "symfony/http-kernel": "^6.4 || ^7.0", "symfony/mime": "^6.4 || ^7.0", + "symfony/security-core": "^6.4 || ^7.0", "symfony/service-contracts": "^3.6" }, "require-dev": { @@ -50,7 +51,6 @@ "symfony/http-client": "^6.4 || ^7.0", "symfony/monolog-bundle": "^3.10", "symfony/routing": "^6.4 || ^7.0", - "symfony/security-bundle": "^6.4 || ^7.0", "symfony/stopwatch": "^6.4 || ^7.0", "symfony/twig-bundle": "^6.4 || ^7.0", "symfony/var-dumper": "^6.4 || ^7.0", @@ -69,7 +69,6 @@ "symfony/twig-bundle": "Allows you to use Twig to render templates into PDF.", "monolog/monolog": "Enables logging througout the generating process.", "async-aws/s3": "Upload any file to aws s3 compatible endpoints supporting multi part upload without memory overhead.", - "league/flysystem-bundle": "Upload any file using this filesystem abstraction package.", - "symfony/security-bundle": "Allows you to generate PDF as a specific user." + "league/flysystem-bundle": "Upload any file using this filesystem abstraction package." } } diff --git a/docs/pdf/customization.md b/docs/pdf/customization.md index 6fff9b65..4e70afc2 100644 --- a/docs/pdf/customization.md +++ b/docs/pdf/customization.md @@ -1,66 +1,66 @@ # PDF customization -> [!NOTE] +> [!NOTE] > All of these functions are available for `HtmlPdfBuilder`, `UrlPdfBuilder` and -> `MarkdownPdfBuilder`. +> `MarkdownPdfBuilder`. > To customize `LibreOfficePdfBuilder` see the related [documentation](office-builder.md). ## Available functions ### Render -[paperSize](#paperSize) -[paperStandardSize](#paperStandardSize) -[paperWidth](#paperWidth) -[paperHeight](#paperHeight) -[margins](#margins) -[marginTop](#margins) -[marginBottom](#margins) -[marginLeft](#margins) -[marginRight](#margins) -[preferCssPageSize](#preferCssPageSize) -[printBackground](#printBackground) -[omitBackground](#omitBackground) -[landscape](#landscape) -[scale](#scale) -[nativePageRanges](#nativePageRanges) -[splitMode](#splitMode) -[splitSpan](#splitSpan) -[splitUnify](#splitUnify) - -### Additional content -[header and footer](#header-and-footer) -[headerFile and footerFile](#headerfile-and-footerfile) +[paperSize](#paperSize) +[paperStandardSize](#paperStandardSize) +[paperWidth](#paperWidth) +[paperHeight](#paperHeight) +[margins](#margins) +[marginTop](#margins) +[marginBottom](#margins) +[marginLeft](#margins) +[marginRight](#margins) +[preferCssPageSize](#preferCssPageSize) +[printBackground](#printBackground) +[omitBackground](#omitBackground) +[landscape](#landscape) +[scale](#scale) +[nativePageRanges](#nativePageRanges) +[splitMode](#splitMode) +[splitSpan](#splitSpan) +[splitUnify](#splitUnify) + +### Additional content +[header and footer](#header-and-footer) +[headerFile and footerFile](#headerfile-and-footerfile) [download from](#download-from) ### Style -[assets](../assets.md) -[addAsset](../assets.md) +[assets](../assets.md) +[addAsset](../assets.md) ### Request -[waitDelay](#waitDelay) -[waitForExpression](#waitForExpression) -[emulatedMediaType](#emulatedMediaType) -[cookies](#cookies) -[setCookie](#setCookie) -[addCookies](#addCookies) -[forwardCookie](#forwardCookie) -[forwardAuthentication](#forwardAuthentication) -[asUser](#asUser) -[userAgent](#userAgent) -[extraHttpHeaders](#extraHttpHeaders) -[addExtraHttpHeaders](#addExtraHttpHeaders) -[failOnHttpStatusCodes](#failOnHttpStatusCodes) -[failOnResourceHttpStatusCodes](#failOnResourceHttpStatusCodes) -[failOnResourceLoadingFailed](#failOnResourceLoadingFailed) -[failOnConsoleExceptions](#failOnConsoleExceptions) -[skipNetworkIdleEvent](#skipNetworkIdleEvent) +[waitDelay](#waitDelay) +[waitForExpression](#waitForExpression) +[emulatedMediaType](#emulatedMediaType) +[cookies](#cookies) +[setCookie](#setCookie) +[addCookies](#addCookies) +[forwardCookie](#forwardCookie) +[forwardAuthentication](#forwardAuthentication) +[asUser](#asUser) +[userAgent](#userAgent) +[extraHttpHeaders](#extraHttpHeaders) +[addExtraHttpHeaders](#addExtraHttpHeaders) +[failOnHttpStatusCodes](#failOnHttpStatusCodes) +[failOnResourceHttpStatusCodes](#failOnResourceHttpStatusCodes) +[failOnResourceLoadingFailed](#failOnResourceLoadingFailed) +[failOnConsoleExceptions](#failOnConsoleExceptions) +[skipNetworkIdleEvent](#skipNetworkIdleEvent) ### Formatting -[metadata](#metadata) -[addMetadata](#addMetadata) -[pdfFormat](#pdfFormat) -[pdfUniversalAccess](#pdfUniversalAccess) -[generateDocumentOutline](#generateDocumentOutline) +[metadata](#metadata) +[addMetadata](#addMetadata) +[pdfFormat](#pdfFormat) +[pdfUniversalAccess](#pdfUniversalAccess) +[generateDocumentOutline](#generateDocumentOutline) [generateTaggedPdf](#generateTaggedPdf) ## Render @@ -69,7 +69,7 @@ Default: `8.5 inches x 11 inches` -You can override the default paper size with `height`, `width` and `unit`. +You can override the default paper size with `height`, `width` and `unit`. `unit` is optional but by default in inches. ```php @@ -138,7 +138,7 @@ class MyInvoiceSize implements PaperSizeInterface { return 200; } - + public function unit(): Unit { return Unit::Inches; @@ -150,7 +150,7 @@ class MyInvoiceSize implements PaperSizeInterface Default: `8.5 inches` -You can override the default `width` and `unit`. +You can override the default `width` and `unit`. `unit` is optional but by default in inches. ```php @@ -182,7 +182,7 @@ class YourController Default: `11 inches` -You can override the default `height` and `unit`. +You can override the default `height` and `unit`. `unit` is optional but by default in inches. ```php @@ -214,8 +214,8 @@ class YourController Default: `0.39 inches` on all four sides -You can override the default margins, with the arguments `top`, `bottom`, `right`, -`left` and `unit`. +You can override the default margins, with the arguments `top`, `bottom`, `right`, +`left` and `unit`. `unit` is optional but by default in inches. ```php @@ -240,7 +240,7 @@ class YourController } ``` -Or you can override all margins individually with respective `unit`. +Or you can override all margins individually with respective `unit`. `unit` is always optional but by default in inches. ```php @@ -524,7 +524,7 @@ class YourController ## Additional content -> [!WARNING] +> [!WARNING] > Every Header or Footer templates you pass to Gotenberg need to have > the following structure. > ```html @@ -540,7 +540,7 @@ class YourController > > ``` > -> Some other limitations exist about header and footer. +> Some other limitations exist about header and footer. > For more information about [Header and Footer](https://gotenberg.dev/docs/routes#header-footer-chromium). ### header and footer @@ -577,9 +577,9 @@ class YourController ### headerFile and footerFile -> [!WARNING] +> [!WARNING] > As assets files, by default the HTML files are fetch in the assets folder of -> your application. +> your application. > If your HTML files are in another folder, you can override the default value > of assets_directory in your configuration file config/sensiolabs_gotenberg.yml. @@ -629,7 +629,7 @@ class YourController ### download from -> [!WARNING] +> [!WARNING] > URL of the file. It MUST return a `Content-Disposition` header with a filename parameter. To download files resource from URLs. @@ -655,7 +655,7 @@ class YourController ], [ 'url' => 'http://example.com/url/to/file', - 'extraHttpHeaders' => + 'extraHttpHeaders' => [ 'MyHeaderOne' => 'MyValue', 'MyHeaderTwo' => 'MyValue', @@ -1090,7 +1090,7 @@ class YourController default: `None` -Return a 409 Conflict response if the HTTP status code from at least one resource +Return a 409 Conflict response if the HTTP status code from at least one resource is not acceptable. ```php @@ -1122,7 +1122,7 @@ class YourController default: `false` -Return a 409 Conflict response if there are exceptions to load at least one resource +Return a 409 Conflict response if there are exceptions to load at least one resource in the Chromium. ```php diff --git a/docs/screenshot/customization.md b/docs/screenshot/customization.md index 4807a017..239bd230 100644 --- a/docs/screenshot/customization.md +++ b/docs/screenshot/customization.md @@ -3,37 +3,37 @@ ## Available functions ### Render -[width](#width) -[height](#height) -[clip](#clip) -[quality](#quality) -[omitBackground](#omitBackground) +[width](#width) +[height](#height) +[clip](#clip) +[quality](#quality) +[omitBackground](#omitBackground) ### Additional content [download from](#download-from) ### Style -[assets](../assets.md) +[assets](../assets.md) [addAsset](../assets.md) ### Request [optimizeForSpeed](#optimizeForSpeed) -[waitDelay](#waitDelay) -[waitForExpression](#waitForExpression) -[emulatedMediaType](#emulatedMediaType) -[cookies](#cookies) -[setCookie](#setCookie) -[addCookies](#addCookies) -[forwardCookie](#forwardCookie) -[forwardAuthentication](#forwardAuthentication) -[asUser](#asUser) -[userAgent](#userAgent) -[extraHttpHeaders](#extraHttpHeaders) -[addExtraHttpHeaders](#addExtraHttpHeaders) -[failOnHttpStatusCodes](#failOnHttpStatusCodes) -[failOnResourceHttpStatusCodes](#failOnResourceHttpStatusCodes) -[failOnResourceLoadingFailed](#failOnResourceLoadingFailed) -[failOnConsoleExceptions](#failOnConsoleExceptions) +[waitDelay](#waitDelay) +[waitForExpression](#waitForExpression) +[emulatedMediaType](#emulatedMediaType) +[cookies](#cookies) +[setCookie](#setCookie) +[addCookies](#addCookies) +[forwardCookie](#forwardCookie) +[forwardAuthentication](#forwardAuthentication) +[asUser](#asUser) +[userAgent](#userAgent) +[extraHttpHeaders](#extraHttpHeaders) +[addExtraHttpHeaders](#addExtraHttpHeaders) +[failOnHttpStatusCodes](#failOnHttpStatusCodes) +[failOnResourceHttpStatusCodes](#failOnResourceHttpStatusCodes) +[failOnResourceLoadingFailed](#failOnResourceLoadingFailed) +[failOnConsoleExceptions](#failOnConsoleExceptions) [skipNetworkIdleEvent](#skipNetworkIdleEvent) ### Formatting @@ -194,7 +194,7 @@ class YourController ### download from -> [!WARNING] +> [!WARNING] > URL of the file. It MUST return a `Content-Disposition` header with a filename parameter. To download files resource from URLs. @@ -348,6 +348,9 @@ class YourController { return $gotenberg ->html() + ->content('twig_simple_pdf.html.twig', [ + 'my_var' => 'value' + ]) ->emulatedMediaType(EmulatedMediaType::Screen) ->generate() ->stream() @@ -375,6 +378,9 @@ class YourController { return $gotenberg ->html() + ->content('twig_simple_pdf.html.twig', [ + 'my_var' => 'value' + ]) ->cookies([[ 'name' => 'my_cookie', 'value' => 'symfony', diff --git a/src/Builder/Behaviors/Chromium/CookieTrait.php b/src/Builder/Behaviors/Chromium/CookieTrait.php index a4e04c58..5fccb5de 100644 --- a/src/Builder/Behaviors/Chromium/CookieTrait.php +++ b/src/Builder/Behaviors/Chromium/CookieTrait.php @@ -148,7 +148,7 @@ public function asUser(UserInterface $user, string $firewallName = 'main'): stat return $this->setCookie($request->getSession()->getName(), [ 'name' => $request->getSession()->getName(), 'value' => $request->getSession()->getId(), - 'domain' => $this->getRequestContext()?->getHost(), + 'domain' => $this->getRequestContext()?->getHost() ?? $request->getHost(), ]); } diff --git a/tests/Builder/Behaviors/Chromium/CookieTestCaseTrait.php b/tests/Builder/Behaviors/Chromium/CookieTestCaseTrait.php index 77ecace9..b333d091 100644 --- a/tests/Builder/Behaviors/Chromium/CookieTestCaseTrait.php +++ b/tests/Builder/Behaviors/Chromium/CookieTestCaseTrait.php @@ -10,7 +10,6 @@ use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpFoundation\Session\Session; -use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken; /** * @template T of BuilderInterface diff --git a/tests/Fixtures/Entity/FakeUser.php b/tests/Fixtures/Entity/FakeUser.php index fe986ce7..37e4bde3 100644 --- a/tests/Fixtures/Entity/FakeUser.php +++ b/tests/Fixtures/Entity/FakeUser.php @@ -21,9 +21,4 @@ public function getUserIdentifier(): string { return 'John Doe'; } - - public function __serialize():array - { - return []; - } } From dd09abb2fef025e761fcd0bec8183b659b964349 Mon Sep 17 00:00:00 2001 From: Steven Renaux Date: Thu, 25 Sep 2025 11:29:43 +0200 Subject: [PATCH 8/8] Update dependencies --- composer-dependency-analyser.php | 3 +++ composer.json | 5 +++-- src/Builder/Behaviors/Chromium/CookieTrait.php | 4 ---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/composer-dependency-analyser.php b/composer-dependency-analyser.php index 95d1b58e..94b07a9a 100644 --- a/composer-dependency-analyser.php +++ b/composer-dependency-analyser.php @@ -31,6 +31,9 @@ ->ignoreErrorsOnPackage('twig/twig', [ ErrorType::DEV_DEPENDENCY_IN_PROD, ]) + ->ignoreErrorsOnPackage('symfony/security-core', [ + ErrorType::DEV_DEPENDENCY_IN_PROD, + ]) ; if (\PHP_VERSION_ID < 80200) { // TODO: Requires PHP >= 8.2 diff --git a/composer.json b/composer.json index be32567c..6b0244dd 100644 --- a/composer.json +++ b/composer.json @@ -32,7 +32,6 @@ "symfony/http-foundation": "^6.4 || ^7.0", "symfony/http-kernel": "^6.4 || ^7.0", "symfony/mime": "^6.4 || ^7.0", - "symfony/security-core": "^6.4 || ^7.0", "symfony/service-contracts": "^3.6" }, "require-dev": { @@ -51,6 +50,7 @@ "symfony/http-client": "^6.4 || ^7.0", "symfony/monolog-bundle": "^3.10", "symfony/routing": "^6.4 || ^7.0", + "symfony/security-core": "^6.4 || ^7.0", "symfony/stopwatch": "^6.4 || ^7.0", "symfony/twig-bundle": "^6.4 || ^7.0", "symfony/var-dumper": "^6.4 || ^7.0", @@ -69,6 +69,7 @@ "symfony/twig-bundle": "Allows you to use Twig to render templates into PDF.", "monolog/monolog": "Enables logging througout the generating process.", "async-aws/s3": "Upload any file to aws s3 compatible endpoints supporting multi part upload without memory overhead.", - "league/flysystem-bundle": "Upload any file using this filesystem abstraction package." + "league/flysystem-bundle": "Upload any file using this filesystem abstraction package.", + "symfony/security-core": "Allows you to use asUser method to generate with CLI required an authentication" } } diff --git a/src/Builder/Behaviors/Chromium/CookieTrait.php b/src/Builder/Behaviors/Chromium/CookieTrait.php index 5fccb5de..759d8738 100644 --- a/src/Builder/Behaviors/Chromium/CookieTrait.php +++ b/src/Builder/Behaviors/Chromium/CookieTrait.php @@ -131,10 +131,6 @@ public function forwardAuthentication(): static */ public function asUser(UserInterface $user, string $firewallName = 'main'): static { - if (!class_exists(UsernamePasswordToken::class)) { - throw new \LogicException(\sprintf('UsernamePasswordToken is required to use "%s" method. Try to run "composer require symfony/security-bundle".', __METHOD__)); - } - $token = new UsernamePasswordToken($user, $firewallName, $user->getRoles()); $session = new Session();