Let's say you want to save the PDF or Screenshot as a file, you will need to use a Sensiolabs\GotenbergBundle\Processor\ProcessorInterface
.
To avoid loading the whole file content in memory you can stream it to the browser.
You can also hook on the stream and save the file chunk by chunk. To do so we leverage the ->stream
method from the HttpClientInterface and use a powerful feature from PHP Generators : ->send
.
Given an exemple for a PDF (works the same for Screenshots):
/** @var GotenbergPdfInterface $gotenbergPdf */
use Sensiolabs\GotenbergBundle\Builder\GotenbergFileResult;$gotenbergPdf = /* ... */;
/** @var GotenbergFileResult $gotenbergFileResult */
$gotenbergFileResult = $gotenbergPdf->html()
// ...
->fileName('my_pdf')
->processor(/* ... */)
->generate()
;
// Either process it with
$result = $gotenbergFileResult->process(); // `$result` depends on the Processor used. See below.
// or to send a response to the browser :
$result = $gotenbergFileResult->stream(); // `$result` is a `Symfony\Component\HttpFoundation\StreamedResponse`
Here is the list of existing Processors :
Useful if you want to store the file in the local filesystem.
Example in a controller
use Sensiolabs\GotenbergBundle\GotenbergPdfInterface;
use Sensiolabs\GotenbergBundle\Processor\FileProcessor;
use Symfony\Component\DependencyInjection\Attribute\Autowire;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\HttpFoundation\Response;
#[Route(path: '/my-pdf', name: 'my_pdf')]
public function pdf(
GotenbergPdfInterface $gotenbergPdf,
Filesystem $filesystem,
#[Autowire('%kernel.project_dir%/var/pdf')]
string $pdfStorage,
): Response {
return $gotenbergPdf->html()
// ...
->fileName('my_pdf')
->processor(new FileProcessor(
$filesystem,
$pdfStorage,
))
->generate()
->stream()
;
}
This will save the file under %kernel.project_dir%/var/pdf/my_pdf.pdf
once the file has been fully streamed to the browser.
If you are not streaming to a browser, you can still process the file using the `process` method instead of `stream`
use Sensiolabs\GotenbergBundle\GotenbergPdfInterface;
use Sensiolabs\GotenbergBundle\Processor\FileProcessor;
use Symfony\Component\Filesystem\Filesystem;
class SomeService
{
public function __construct(
private readonly GotenbergPdfInterface $gotenbergPdf,
#[Autowire('%kernel.project_dir%/var/pdf')]
private readonly string $pdfStorage,
) {}
public function pdf(): \SplFileInfo
{
return $this->gotenbergPdf->html()
//
->fileName('my_pdf')
->processor(new FileProcessor(
new Filesystem(),
$pdfStorage,
))
->generate()
->process()
;
}
}
This will return a SplFileInfo
of the generated file stored at %kernel.project_dir%/var/pdf/my_pdf.pdf
.
Empty processor. Does nothing. Returns null
.
Creates a temporary file and dump all chunks into it. Return a ressource
of said tmpfile()
.
Example in a service
use Sensiolabs\GotenbergBundle\GotenbergPdfInterface;
use Sensiolabs\GotenbergBundle\Processor\TempfileProcessor;
use Symfony\Component\Filesystem\Filesystem;
class SomeService
{
public function __construct(
private readonly GotenbergPdfInterface $gotenbergPdf,
) {}
/**
* @return resource
*/
public function pdf(): mixed
{
return $this->gotenbergPdf->html()
//
->fileName('my_pdf')
->processor(new TempfileProcessor())
->generate()
->process()
;
}
}
Apply multiple processors. Each chunk will be sent to each processor sequentially. Return an array of values returned by chained processors.
Example in a service
use Sensiolabs\GotenbergBundle\GotenbergPdfInterface;
use Sensiolabs\GotenbergBundle\Processor\ChainProcessor;
use Sensiolabs\GotenbergBundle\Processor\FileProcessor;
use Sensiolabs\GotenbergBundle\Processor\ProcessorInterface;
use Symfony\Component\Filesystem\Filesystem;
/**
* @implements ProcessorInterface<int>
*/
class CustomProcessor implements ProcessorInterface
{
public function __invoke(string|null $fileName): \Generator { /* ... */ } // Implement your own logic
}
class SomeService
{
public function __construct(
private readonly GotenbergPdfInterface $gotenbergPdf,
#[Autowire('%kernel.project_dir%/var/pdf')]
private readonly string $pdfStorage,
) {}
/**
* @return array{0: \SplFileInfo, 1: int}
*/
public function pdf(): array
{
return $this->gotenbergPdf->html()
//
->fileName('my_pdf')
->processor(new ChainProcessor([
new FileProcessor(
new Filesystem(),
$pdfStorage,
),
new CustomProcessor(),
]))
->generate()
->process()
;
}
}
Upload using the league/flysystem-bundle
package. Returns a callable
. This callable will return the uploaded content.
Example in a service
use League\Flysystem\FilesystemOperator;
use Sensiolabs\GotenbergBundle\GotenbergPdfInterface;
use Sensiolabs\GotenbergBundle\Bridge\LeagueFlysystem\Processor\FlysystemProcessor;
use Symfony\Component\DependencyInjection\Attribute\Autowire;
class SomeService
{
public function __construct(
private readonly GotenbergPdfInterface $gotenbergPdf,
#[Autowire(service: 'pdfs.storage')] // Use the name under the `flysystem.storages` key in your packages configuration.
private readonly FilesystemOperator $filesystemOperator,
) {}
/**
* @return Closure(): string
*/
public function pdf(): Closure
{
return $this->gotenbergPdf->html()
//
->fileName('my_pdf')
->processor(new FlysystemProcessor(
$this->filesystemOperator,
))
->generate()
->process()
;
}
}
Upload using the async-aws/s3
package. Uploads using the multipart upload feature of S3. Returns a AsyncAws\S3\Result\CompleteMultipartUploadOutput
object.
Example in a service
use AsyncAws\S3\Result\CompleteMultipartUploadOutput;
use Sensiolabs\GotenbergBundle\Bridge\AsyncAws\Processor\AsyncAwsS3MultiPartProcessor;
use Sensiolabs\GotenbergBundle\GotenbergPdfInterface;
class SomeService
{
public function __construct(
private readonly GotenbergPdfInterface $gotenbergPdf,
private readonly S3Client $s3Client,
) {}
public function pdf(): CompleteMultipartUploadOutput
{
return $this->gotenbergPdf->html()
//
->fileName('my_pdf')
->processor(new AsyncAwsS3MultiPartProcessor(
$this->s3Client,
'bucket-name',
))
->generate()
->process()
;
}
}
A custom processor must implement Sensiolabs\GotenbergBundle\Processor\ProcessorInterface
which require that your __invoke
method is a \Generator
. To receive a chunk you must assign yield
to a variable like so : $chunk = yield
.
The basic needed code is the following :
use Sensiolabs\GotenbergBundle\Processor\ProcessorInterface;
/**
* @implements ProcessorInterface<YOUR_GENERATOR_RETURN_TYPE>
*/
class CustomProcessor implements ProcessorInterface
{
public function __invoke(string|null $fileName): \Generator
{
do {
$chunk = yield;
// do something with it
} while (!$chunk->isLast());
// rest of your code
}
}