--- url: /advanced/attachments.md description: >- Embed file attachments and XMP metadata in PDFs. Supports EU e-invoicing standards like ZUGFeRD and Factur-X. --- # Attachments & Metadata WeasyPrint supports embedding file attachments and XMP metadata in generated PDFs. ## Attachments You can attach files to a PDF by calling `addAttachment()` on the factory after preparing a source: ```php $factory->prepareSource('

Invoice

') ->addAttachment('/path/to/terms.pdf') ->addAttachment('/path/to/receipt.png'); ``` The method is fluent, so you can chain as many attachments as needed. ### Relationships You can optionally specify a relationship type for each attachment, which describes how the attachment relates to the PDF: ```php $factory->prepareSource('

Invoice

') ->addAttachment('/path/to/invoice.xml', relationship: 'Data') ->addAttachment('/path/to/terms.pdf', relationship: 'Supplement'); ``` This maps to the `--attachment-relationship` flag in the WeasyPrint CLI. ### Using a `Source` Object You can also add attachments via a `Source` object before passing it to the factory: ```php use WeasyPrint\Objects\Source; $source = new Source('

Invoice

'); $source->addAttachment('/path/to/terms.pdf'); $factory->prepareSource($source); ``` ### File Validation Attachment files are validated when the PDF is built. If a file does not exist, an `AttachmentNotFoundException` is thrown. ## XMP Metadata XMP (Extensible Metadata Platform) metadata can be embedded in the PDF using `addXmpMetadata()`. This accepts a path to an RDF/XML file: ```php $factory->prepareSource('

Invoice

') ->addXmpMetadata('/path/to/metadata.xml'); ``` Like attachments, the method is fluent and can be called multiple times: ```php $factory->prepareSource('

Invoice

') ->addXmpMetadata('/path/to/facturx.xml') ->addXmpMetadata('/path/to/additional-metadata.xml'); ``` ### EU E-Invoicing XMP metadata is particularly useful for EU e-invoicing standards like ZUGFeRD and Factur-X, where a conforming PDF must include structured metadata alongside an XML invoice attachment: ```php $factory->prepareSource($invoiceHtml) ->addAttachment('/path/to/factur-x.xml', relationship: 'Data') ->addXmpMetadata('/path/to/factur-x-metadata.xml'); ``` --- --- url: /usage/output.md description: >- Build PDF output and stream, download, or save it. Supports inline display, forced downloads, Flysystem, and Laravel Storage. --- # Building the `Output` Now that you have [prepared a source](/usage/source), you are ready to build the output and return it to your user or save it to disk (or do whatever you'd like to do with it). To do this, you can call the `->build()` method on the factory, which will return an instance of `WeasyPrint\Objects\Output`: ```php $output = $factory->build(); ``` ## Using the `Output` The `Output` object makes the following methods available: ### `stream()` This method creates a Symfony [`StreamedResponse`](https://symfony.com/doc/current/components/http_foundation.html#streaming-a-response) that may be used to download or inline the PDF to the client (such as a browser). ```php public function stream( string $filename, array $headers = [], StreamMode $mode = StreamMode::INLINE, ): StreamedResponse ``` The `$headers` parameter allows you to set custom HTTP response headers. For example, you might add cache control headers or custom application headers. The `$mode` parameter sets the `Content-Disposition` HTTP header, which controls how the browser handles the PDF: | Mode | Value | Behavior | | ------------------------------ | ------------ | ------------------------------------- | | `StreamMode::INLINE` (default) | `inline` | Display the PDF in the browser | | `StreamMode::DOWNLOAD` | `attachment` | Force the browser to download the PDF | **Examples:** ```php use Symfony\Component\HttpFoundation\StreamedResponse; use WeasyPrint\WeasyPrintFactory; public function generatePdf(): StreamedResponse { $factory = new WeasyPrintFactory() ->prepareSource('

WeasyPrint rocks!

'); $output = $factory->build(); return $output->stream('weasyprint-rocks.pdf'); } ``` For more control, use `stream()` with custom headers or a different mode: ```php use WeasyPrint\Enums\StreamMode; // Force the browser to download the PDF instead of displaying it: $response = $output->stream( 'weasyprint-rocks.pdf', mode: StreamMode::DOWNLOAD, ); // Add custom headers (while keeping default inline behavior): $response = $output->stream( 'weasyprint-rocks.pdf', headers: ['X-Custom-Header' => 'value'], ); // Do both things at the same time: $response = $output->stream( 'weasyprint-rocks.pdf', headers: ['X-Custom-Header' => 'value'], mode: StreamMode::DOWNLOAD, ); ``` ::: tip Working with Streamed Responses For more information on working with the `$response` from these examples, see the [Symfony StreamedResponse documentation](https://symfony.com/doc/current/components/http_foundation.html#streaming-a-response). ::: ### `download()` This is a shorthand for `stream()` using `StreamMode::DOWNLOAD`. ```php public function download( string $filename, array $headers = [], ): StreamedResponse ``` **Examples:** ```php // Force the browser to download the PDF: $response = $output->download('weasyprint-rocks.pdf'); // With custom headers: $response = $output->download( 'weasyprint-rocks.pdf', headers: ['X-Custom-Header' => 'value'], ); ``` ### `inline()` This is a shorthand for `stream()` using `StreamMode::INLINE` (the default behavior of `stream()`). ```php public function inline( string $filename, array $headers = [], ): StreamedResponse ``` **Examples:** ```php // Display the PDF in the browser: $response = $output->inline('weasyprint-rocks.pdf'); // With custom headers: $response = $output->inline( 'weasyprint-rocks.pdf', headers: ['X-Custom-Header' => 'value'], ); ``` ### As a string Beyond streaming the PDF to the browser, you can also get the underlying string data and do whatever you'd like with it. #### `Stringable` The `Output` object implements `\Stringable`, and so may be consumed as a string. This can be useful in cases where you want to pass it to a class, method or function that expects a string. For example, you can write directly to disk: ```php file_put_contents('weasyprint-rocks.pdf', $output); ``` When assigning to a variable, you can also cast it: ```php $pdfData = (string) $output; ``` #### Flysystem + AWS You can use Flysystem to store PDFs directly to AWS S3: ```php use League\Flysystem\AwsS3V3\AwsS3V3Adapter; use League\Flysystem\Filesystem; use Aws\S3\S3Client; $s3Client = new S3Client([ 'version' => 'latest', 'region' => 'us-east-1', ]); $adapter = new AwsS3V3Adapter($s3Client, 'bucket-name'); $filesystem = new Filesystem($adapter); $filesystem->write('path/to/weasyprint-rocks.pdf', $output); ``` To learn more about how to use Flysystem with AWS S3, see the [official documentation](https://flysystem.thephpleague.com/docs/adapter/aws-s3-v3/). #### Laravel Storage With Laravel, use the `Storage` facade: ```php use Illuminate\Support\Facades\Storage; Storage::put('path/to/weasyprint-rocks.pdf', $output); ``` To learn more about how to use Laravel’s File Storage features, see the [official documentation](https://laravel.com/docs/filesystem). #### `getData()` If you don't want to take advantage of the `Stringable` interface, then you can simply get the data directly: ```php $pdfData = $output->getData(); ``` ## Skipping `build()` The factory also exposes `stream()`, `download()`, `inline()`, and `getData()` directly, so you can skip the explicit `build()` call when you don't need to interact with the `Output` object: ```php $factory = new WeasyPrintFactory(); return $factory ->prepareSource('

WeasyPrint rocks!

') ->download('weasyprint-rocks.pdf'); ``` These methods have the same signatures as their `Output` counterparts - they call `build()` internally and forward the result. --- --- url: /frameworks/laravel/pdf-class.md description: >- Create reusable, class-based PDFs in Laravel with WeasyPrint for PHP. Encapsulate source, filename, config, and headers in a single class. --- # Class-based PDFs The Laravel integration provides an abstract `PDF` class that lets you encapsulate PDF logic in dedicated, reusable classes. This is useful when a PDF has its own source, filename, and configuration that you want to keep together. ## Creating a PDF Class Extend `WeasyPrint\Integration\Laravel\PDF` and implement the `source()` and `filename()` methods: ```php use WeasyPrint\Integration\Laravel\PDF; use Illuminate\Contracts\Support\Renderable; class InvoicePdf extends PDF { public function __construct( private Invoice $invoice, ) {} public function source(): Renderable { return view('invoices.template', [ 'invoice' => $this->invoice, ]); } public function filename(): string { return "invoice-{$this->invoice->number}.pdf"; } } ``` The `source()` method accepts the same types as `prepareSource()` - a string, a `Renderable`, or a `Source` object. ## Returning from Controllers The `PDF` class implements Laravel's `Responsable` interface, so you can return it directly from a controller: ```php class InvoiceController { public function show(Invoice $invoice) { return new InvoicePdf($invoice); } } ``` By default, this displays the PDF inline in the browser. ## Stream Modes To change the default stream mode, override the `defaultStreamMode()` method: ```php use WeasyPrint\Enums\StreamMode; class InvoicePdf extends PDF { // ... public function defaultStreamMode(): StreamMode { return StreamMode::DOWNLOAD; } } ``` You can also call the output methods directly for explicit control: ```php $pdf = new InvoicePdf($invoice); return $pdf->download(); return $pdf->inline(); return $pdf->stream(StreamMode::DOWNLOAD); ``` ## Custom Configuration Override the `config()` method to customise configuration for a specific PDF class: ```php use WeasyPrint\Objects\Config; class InvoicePdf extends PDF { // ... public function config(Config $config): void { $config->timeout = 120; $config->optimizeImages = true; } } ``` This works like `tapConfig()` - you mutate specific properties and everything else retains its defaults. ## Custom Headers Override the `headers()` method to add custom HTTP response headers: ```php class InvoicePdf extends PDF { // ... public function headers(): array { return [ 'X-Invoice-Number' => $this->invoice->number, ]; } } ``` --- --- url: /advanced/config.md description: >- Configure WeasyPrint for PHP - all available options including PDF variants, versions, image optimisation, and more. --- # Configuration The factory comes with sensible defaults out of the box, so configuration is entirely optional. When you do need to customise behaviour, there are a few ways to do it. ## Passing Configuration As covered in the [Factory](/usage/factory) docs, you can pass configuration when creating a new instance - either as a `Config` object or an array: ```php use WeasyPrint\Objects\Config; use WeasyPrint\WeasyPrintFactory; // Using the Config class (recommended for type-safety and IDE hints): $factory = new WeasyPrintFactory( new Config( timeout: 120, optimizeImages: true, ) ); // Using an array: $factory = new WeasyPrintFactory([ 'timeout' => 120, 'optimize_images' => true, ]); ``` ## Changing Configuration After creating a factory, you can change its configuration using `tapConfig()` or `setConfig()`. ### `tapConfig()` Tapping lets you mutate specific properties on the existing `Config` object while leaving everything else untouched: ```php use WeasyPrint\Objects\Config; $factory->tapConfig( static function (Config $config): void { $config->binary = '/usr/local/bin/weasyprint'; $config->timeout = 120; } ); ``` ### `setConfig()` To replace the configuration entirely, use `setConfig()` with a new `Config` object: ```php use WeasyPrint\Objects\Config; $factory->setConfig(new Config( binary: '/usr/local/bin/weasyprint', timeout: 120, )); ``` ::: warning Unlike `tapConfig()`, this replaces the entire configuration. Any values you don't explicitly set will fall back to the `Config` constructor defaults, not any previously configured values. ::: ## Available Options ### `binary` * **Type:** `string|null` - **Default:** `null` The path to the WeasyPrint binary. If WeasyPrint is available globally, the package will find and use it automatically. Otherwise, provide an absolute path. ### `cachePrefix` * **Type:** `string` - **Default:** `'weasyprint_cache'` The prefix used for temporary filenames. ### `timeout` * **Type:** `int` - **Default:** `60` The number of seconds to allow a conversion to run for. ### `inputEncoding` * **Type:** `string` - **Default:** `'utf-8'` Force the input character encoding. Must be a valid encoding supported by `mb_list_encodings()`. ### `presentationalHints` * **Type:** `bool` - **Default:** `true` Enable or disable HTML Presentational Hints. ### `mediaType` * **Type:** `string|null` - **Default:** `null` Set the media type to use for CSS @media. Defaults to `print` at binary level. ### `baseUrl` * **Type:** `string|null` - **Default:** `null` Set the base URL for relative URLs in the HTML input. ### `stylesheets` * **Type:** `array` - **Default:** `[]` Additional stylesheets to use alongside the HTML input. Each entry may be an absolute file path or a URL. ### `processEnvironment` * **Type:** `array` - **Default:** `['LC_ALL' => 'en_US.UTF-8']` Environment variables passed to Symfony Process when executing the binary. ### `pdfVariant` * **Type:** `PDFVariant|string|null` - **Default:** `null` Specify a PDF variant. You can pass the enum directly or use its string value: ```php use WeasyPrint\Enums\PDFVariant; new Config(pdfVariant: PDFVariant::PDF_A_2B); new Config(pdfVariant: 'pdf/a-2b'); ``` ::: details Available variants **PDF/A:** `PDF_A_1B`, `PDF_A_2B`, `PDF_A_3B`, `PDF_A_1A`, `PDF_A_2A`, `PDF_A_3A`, `PDF_A_2U`, `PDF_A_3U`, `PDF_A_4U`, `PDF_A_4E`, `PDF_A_4F` **PDF/UA:** `PDF_UA_1`, `PDF_UA_2` **PDF/X:** `PDF_X_1A`, `PDF_X_3`, `PDF_X_4`, `PDF_X_5G` **Debug:** `DEBUG` ::: ### `pdfVersion` * **Type:** `PDFVersion|string|null` - **Default:** `null` Specify a PDF version. You can pass the enum directly or use its string value: ```php use WeasyPrint\Enums\PDFVersion; new Config(pdfVersion: PDFVersion::VERSION_2_0); new Config(pdfVersion: '2.0'); ``` ::: details Available versions `VERSION_1_4` (`1.4`), `VERSION_1_7` (`1.7`), `VERSION_2_0` (`2.0`) ::: ### `skipCompression` * **Type:** `bool` - **Default:** `false` Do not compress PDFs. Useful for debugging. ### `customMetadata` * **Type:** `bool` - **Default:** `false` Include custom HTML meta tags in PDF metadata. ### `srgb` * **Type:** `bool` - **Default:** `false` Include the sRGB color profile. When running against WeasyPrint 69 or newer, this uses `--output-intent srgb`. ### `outputIntent` * **Type:** `string|null` - **Default:** `null` Set the PDF output intent. This maps to WeasyPrint 69's `--output-intent` option and accepts values such as `srgb`, `device-cmyk`, or the CSS identifier of a `@color-profile` rule. ### `optimizeImages` * **Type:** `bool` - **Default:** `false` Optimize the size of embedded images with no quality loss. ### `fullFonts` * **Type:** `bool` - **Default:** `false` When possible, embed unmodified font files in the PDF. ### `hinting` * **Type:** `bool` - **Default:** `false` Keep hinting information in embedded font files. ### `dpi` * **Type:** `int|null` - **Default:** `null` Set the maximum resolution of images embedded in the PDF. Must be greater than 0 when set. ### `jpegQuality` * **Type:** `int|null` - **Default:** `null` Set the JPEG output quality, from 0 (worst) to 95 (best). ### `pdfForms` * **Type:** `bool` - **Default:** `false` Render PDF forms from HTML elements. ### `noHttpRedirects` * **Type:** `bool` - **Default:** `false` Disable following HTTP redirects. ### `failOnHttpErrors` * **Type:** `bool` - **Default:** `false` Abort the conversion on HTTP errors. ## Validation The `Config` class validates certain options on construction: * `dpi` must be greater than 0 when set. * `jpegQuality` must be between 0 and 95 when set. * `inputEncoding` must be a valid encoding supported by PHP's `mb_list_encodings()`. Invalid values will throw an exception immediately, so configuration errors surface early. --- --- url: /contributing.md description: >- How to contribute to WeasyPrint for PHP - development environment, tests, formatting, and commit guidelines. --- # Contributing Contributions are always welcome! Feel free to [submit a pull request](https://github.com/mikerockett/weasyprint/pulls) to the `main` or current-release branch: 1. **Non-breaking** changes must target the `V.x` branch (where `V` is the latest major version). If accepted, the PR will also be merged into the applicable branches for other maintained versions. 2. **Breaking** changes must target the `main` branch. These will be released in a new major version and won't be backported. Provide as much detail as possible in your pull request, unless it's a trivial change. ## Development Environment This package uses Docker for local development. You don't need PHP, Composer, or WeasyPrint installed on your machine - everything runs inside the container. ::: tip A [justfile](https://github.com/casey/just) is provided for convenience. If you don't have Just installed, you can substitute `just ` with the equivalent `docker compose run --rm wp `. ::: To get started, make sure you have Docker installed and then build the image: ```shell just build ``` Then install dependencies: ```shell just composer install ``` You can run any Composer command via `just composer `. ## Tests If your changes impact existing tests, update them. If you're adding new functionality: 1. **New feature:** Create a new test case covering all functionality. 2. **Existing feature improvement:** Add a test to the applicable test case. Run tests before submitting your PR: ```shell just test ``` ## Formatting This package uses PHP CS Fixer for code formatting. Format all your changes before committing: ```shell just fix ``` ## Commit Messages Keep commit messages short and to the point - for example, "fix timeout handling when binary is unresponsive" or "add support for PDF/UA-2 variant". Long messages are strongly discouraged. Avoid generic messages like "fix bug" or "update code". For bug reports or feature requests, [open an issue](https://github.com/mikerockett/weasyprint/issues). --- --- url: /usage/source.md description: >- Prepare HTML sources for PDF generation using strings, URLs, Renderable objects, or Source instances. --- # Creating a `Source` Now that you have a [Factory instance](/usage/factory), you can prepare a source. Sources prepare and hold the HTML content that WeasyPrint will render into a PDF. On your `$factory` instance, you can use the `prepareSource()` method, which accepts a single argument that can be one of the following types: * **`string`** - HTML content or a URL to fetch * **`Renderable`** - An object implementing the `Renderable` interface * **`Source`** - A `WeasyPrint\Objects\Source` instance Here's the method signature: ```php public function prepareSource(string|Renderable|Source $source): self ``` When this method is called, it sets the source on the factory, [ready to be built](/usage/output), and returns the factory. ## HTML String The simplest approach, pass HTML directly as a string: ```php $factory->prepareSource('

Invoice

Total: USD 100.00

'); ``` For longer HTML content, use a [HEREDOC](https://www.php.net/manual/en/language.types.string.php#language.types.string.syntax.heredoc): ```php $factory->prepareSource(<<Invoice

Total: USD 100.00

HTML); ``` ## URL You can also pass in a URL, which will be fetched and rendered into an HTML string. ```php $factory->prepareSource('https://example.com/invoice/123'); ``` ## Renderable You can also use a class that implements the `Renderable` contract from Laravel's [Support library](https://packagist.org/packages/illuminate/support), which is already a dependency of this package. In this case, the `render()` method will be called automatically. ```php use Illuminate\Contracts\Support\Renderable; class InvoiceTemplate implements Renderable { public function __construct(private array $data) {} public function render(): string { $total = number_format($this->data['total'], 2); return <<Invoice

Total: USD $total

HTML; } } // Usage $factory->prepareSource(new InvoiceTemplate(['total' => 100.0])); ``` Laravel Views implement `Renderable`, so you can pass them directly: ```php $factory->prepareSource( view('invoices.template', ['total' => 100.0]) ); ``` ## Source Object For more control, use the `Source` class: ```php use WeasyPrint\Objects\Source; $source = new Source('

Invoice

'); $factory->prepareSource($source); ``` The `Source` class also supports attachments (files to include in the PDF): ```php $source = new Source('

Invoice

'); $source->addAttachment('/path/to/file.pdf'); $factory->prepareSource($source); ``` Alternatively, add attachments after preparing the source: ```php $factory->prepareSource('

Invoice

') ->addAttachment('/path/to/file.pdf'); ``` --- --- url: /advanced/errors.md description: >- All exceptions thrown by WeasyPrint for PHP, including configuration, source, build, and output errors. --- # Error Handling The package throws specific exceptions for different failure scenarios. All exceptions extend `RuntimeException`. ## Configuration Errors ### `InvalidConfigValueException` Thrown when a config value fails validation during construction or after calling `tapConfig()` / `setConfig()`. ```php use WeasyPrint\Exceptions\InvalidConfigValueException; ``` This is thrown for: * `dpi` set to 0 or a negative number * `jpegQuality` outside the 0-95 range * `inputEncoding` not supported by `mb_list_encodings()` ## Source Errors ### `SourceNotSetException` Thrown when calling `build()` or `addAttachment()` without first preparing a source. ```php use WeasyPrint\Exceptions\SourceNotSetException; ``` ## Build Errors ### `BinaryNotFoundException` Thrown when the WeasyPrint binary cannot be found or is not executable. This applies both when a custom path is configured via the `binary` config option and when the package attempts to locate it automatically. ```php use WeasyPrint\Exceptions\BinaryNotFoundException; ``` ### `UnsupportedVersionException` Thrown at the start of a build if the installed WeasyPrint binary version does not satisfy the package's version constraint. ```php use WeasyPrint\Exceptions\UnsupportedVersionException; ``` ### `AttachmentNotFoundException` Thrown during a build if an attachment file path does not exist on disk. ```php use WeasyPrint\Exceptions\AttachmentNotFoundException; ``` ### `TemporaryFileException` Thrown when the package fails to write the HTML source to a temporary file for processing. ```php use WeasyPrint\Exceptions\TemporaryFileException; ``` ## Output Errors ### `MissingOutputFileException` Thrown when the WeasyPrint binary completes but no output file is found at the expected path. ```php use WeasyPrint\Exceptions\MissingOutputFileException; ``` ### `OutputReadFailedException` Thrown when the output file exists but cannot be read into memory. ```php use WeasyPrint\Exceptions\OutputReadFailedException; ``` --- --- url: /frameworks.md description: >- Framework integrations for WeasyPrint for PHP (previously WeasyPrint for Laravel). Now framework-agnostic with optional Laravel support. --- # Framework Integrations Prior to v11, this package was called **WeasyPrint for Laravel** and required Laravel as a dependency. It has since been renamed to **WeasyPrint for PHP** and rebuilt to be fully framework-agnostic - Laravel is no longer required, though first-class support for it remains. The core package works anywhere PHP runs. Framework integrations are optional extras that provide tighter, more idiomatic bindings for specific frameworks. ## Supported Frameworks ### Laravel The package ships with a built-in Laravel integration, including automatic service container binding, configuration publishing, and a class-based PDF generation API. Laravel Integration ### Tempest We are considering adding first-class support for [Tempest](https://tempestphp.com) in a future release. If this is something you'd like to see, feel free to [open an issue](https://github.com/mikerockett/weasyprint/issues) to share your interest. --- --- url: /usage/get-started.md description: >- Get started with WeasyPrint for PHP (previously WeasyPrint for Laravel). Install the package and generate your first PDF in minutes. --- # Getting Started Getting up and running with WeasyPrint for PHP is straightforward. Within minutes, you'll be able to use WeasyPrint in your PHP projects to generate beautiful PDFs. ## Check Version Compatibility Before diving in, please review the version support table, which outlines the compatibility between different versions of WeasyPrint and the package. Typically, it's recommended to ensure you're using the latest versions of both WeasyPrint and the package. **[Supported Versions →](/versions)** ## Installation First make sure the appropriate version of WeasyPrint is installed on your system: WeasyPrint Installation Docs ↗ Then, install the package with Composer: ```shell composer require rockett/weasyprint ``` If you're using Laravel, see the [Laravel integration guide](/frameworks/laravel/) for additional steps (optional). --- --- url: /frameworks/laravel.md description: >- Laravel integration for WeasyPrint for PHP (previously WeasyPrint for Laravel) - service container binding, config publishing, facade, and class-based PDFs. --- # Laravel Integration The package ships with a built-in Laravel integration that provides automatic service container binding, publishable configuration, a facade, and a class-based PDF generation API. ## Setup After [installing the package](/usage/get-started), the service provider is auto-discovered by Laravel. No additional registration is needed. ### Publishing Configuration To customise the default configuration, publish the config file: ```shell php artisan vendor:publish --tag=weasyprint.config ``` This creates a `config/weasyprint.php` file in your application. All options can be set via environment variables - see the [Configuration](/advanced/config#available-options) reference for available options. ## Using the Factory The service provider binds `WeasyPrintFactory` to the `WeasyPrint` contract as a scoped singleton, meaning a single instance is reused throughout a request lifecycle (including with Laravel Octane). ### Dependency Injection As covered in the [Factory](/usage/factory) docs, inject the contract into your classes: ```php use WeasyPrint\Contracts\WeasyPrint; class InvoiceController { public function download(WeasyPrint $weasyprint) { return $weasyprint ->prepareSource(view('invoices.template', ['total' => 100.0])) ->build() ->download('invoice.pdf'); } } ``` ### Facade The `WeasyPrint` facade provides static access to the factory: ```php use WeasyPrint\Integration\Laravel\WeasyPrint; $output = WeasyPrint::prepareSource('

Invoice

') ->build(); return $output->download('invoice.pdf'); ``` ## Class-based PDFs For a more structured approach, the Laravel integration also provides an abstract `PDF` class that lets you encapsulate source, filename, configuration, and headers in a single, reusable class. Learn about class-based PDFs --- --- url: /advanced/testing.md description: >- Test your PDF generation with WeasyPrint::fake(), a built-in test double for Laravel, or mock the contract in any framework. --- # Testing The package provides a built-in fake for Laravel and implements a contract interface for easy mocking in any framework. ## Laravel: `WeasyPrint::fake()` The Laravel facade provides a `fake()` method that swaps the container binding with a test double. The fake records all calls without invoking the WeasyPrint binary and provides fluent assertion methods. ```php use WeasyPrint\Integration\Laravel\WeasyPrint; it('generates an invoice PDF', function () { $fake = WeasyPrint::fake(); $response = $this->get('/invoices/1/pdf'); $response->assertOk(); $fake->assertSourcePrepared() ->assertDownloaded('invoice.pdf'); }); ``` ### Available Assertions All assertion methods are chainable. #### `assertBuilt()` Assert that `build()` was called. Optionally pass a count: ```php $fake->assertBuilt(); $fake->assertBuilt(times: 2); ``` #### `assertNotBuilt()` / `assertNothingBuilt()` Assert that `build()` was never called: ```php $fake->assertNotBuilt(); ``` #### `assertSourcePrepared()` Assert that `prepareSource()` was called. Optionally pass a callback to inspect the source: ```php $fake->assertSourcePrepared(); $fake->assertSourcePrepared(function ($source) { expect($source)->toBeInstanceOf(Source::class); }); ``` #### `assertDownloaded()` Assert that `download()` was called. Optionally assert the filename: ```php $fake->assertDownloaded(); $fake->assertDownloaded('invoice.pdf'); ``` #### `assertInlined()` Assert that `inline()` was called. Optionally assert the filename: ```php $fake->assertInlined(); $fake->assertInlined('invoice.pdf'); ``` #### `assertStreamed()` Assert that `stream()` was called. Optionally assert the filename and/or mode: ```php use WeasyPrint\Enums\StreamMode; $fake->assertStreamed(); $fake->assertStreamed('invoice.pdf'); $fake->assertStreamed('invoice.pdf', mode: StreamMode::DOWNLOAD); ``` #### `assertAttachmentAdded()` Assert that `addAttachment()` was called. Optionally assert the path: ```php $fake->assertAttachmentAdded(); $fake->assertAttachmentAdded('/path/to/terms.pdf'); ``` #### `assertXmpMetadataAdded()` Assert that `addXmpMetadata()` was called. Optionally assert the path: ```php $fake->assertXmpMetadataAdded(); $fake->assertXmpMetadataAdded('/path/to/metadata.xml'); ``` ### Fake Return Values The fake returns sensible defaults so your code can run through its full path: * `build()` returns an `Output` with fake PDF data * `getData()` returns `'%PDF-1.4 fake'` * `stream()`, `download()`, `inline()` return a `StreamedResponse` with correct headers * `getWeasyPrintVersion()` returns `'68.0'` ## Without a Framework In a framework-agnostic setup, code against the `WeasyPrint\Contracts\WeasyPrint` interface and provide a mock in your tests: ```php use WeasyPrint\Contracts\WeasyPrint; class InvoiceService { public function __construct( private WeasyPrint $weasyprint, ) {} public function generate(string $html): string { return $this->weasyprint ->prepareSource($html) ->getData(); } } ``` Then in your test: ```php $mock = Mockery::mock(WeasyPrint::class); $mock->shouldReceive('prepareSource') ->with('

Invoice

') ->once() ->andReturnSelf(); $mock->shouldReceive('getData') ->once() ->andReturn('fake-pdf-data'); $service = new InvoiceService($mock); $result = $service->generate('

Invoice

'); expect($result)->toBe('fake-pdf-data'); ``` You can also use the `FakeWeasyPrint` class directly without the facade: ```php use WeasyPrint\Testing\FakeWeasyPrint; $fake = new FakeWeasyPrint(); $service = new InvoiceService($fake); $service->generate('

Invoice

'); $fake->assertSourcePrepared() ->assertBuilt(); ``` ## Integration Testing To verify the full pipeline including the WeasyPrint binary, use the factory directly. Make sure WeasyPrint is installed in your CI environment: ```php use WeasyPrint\WeasyPrintFactory; it('produces valid PDF output', function () { $data = (new WeasyPrintFactory()) ->prepareSource('

Test

') ->getData(); expect($data)->toStartWith('%PDF-'); }); ``` --- --- url: /usage/factory.md description: >- Learn how to create and configure a WeasyPrintFactory instance for PDF generation, with support for dependency injection. --- # The Factory The `WeasyPrintFactory` is the core class for generating PDFs. It serves as the main entry point for all PDF generation operations. ## Instantiating a Factory Create a new instance by directly instantiating the `WeasyPrintFactory` class: ```php use WeasyPrint\WeasyPrintFactory; $factory = new WeasyPrintFactory(); ``` You can optionally pass configuration using the `Config` class for type-safety and clear option hints: ```php use WeasyPrint\Objects\Config; $factory = new WeasyPrintFactory( new Config( timeout: 60, logOutput: false ) ); ``` Alternatively, you can pass an array, which is useful when injecting configuration from a repository (like Laravel's `config()` helper): ```php $factory = new WeasyPrintFactory([ 'timeout' => 60, 'log_output' => false, ]); ``` ::: tip The `Config` class is recommended as it provides type-safety and IDE autocomplete for available options. ::: How to configure the factory ## Using in a Class Once you have a factory instance, you can inject it into your services and use it to prepare sources and generate PDFs: ```php factory = new WeasyPrintFactory(); } public function generateDocument(string $documentId): void { // Use the factory for PDF generation } } ``` ## Dependency Injection For frameworks that support Dependency Injection or Inversion of Control (IoC) – where the framework automatically manages creating and passing objects to your classes – use the `WeasyPrint\Contracts\WeasyPrint` interface instead of the concrete class: ```php singleton( WeasyPrint::class, fn () => new WeasyPrintFactory() ); ``` Check your framework's documentation for how to register singleton or shared services. ## Checking the WeasyPrint Version You can check the installed WeasyPrint binary version using `getWeasyPrintVersion()`: ```php $version = $factory->getWeasyPrintVersion(); // e.g. "68.0" ``` This can be useful for debugging or verifying your environment is set up correctly. --- --- url: /versions.md description: >- Version compatibility table for WeasyPrint for PHP (previously WeasyPrint for Laravel), including supported WeasyPrint, Laravel, and PHP versions. --- # Versions & Compatibility This package aims to support the latest version of WeasyPrint at the bare minimum. It also supports older versions of WeasyPrint, provided their CLI APIs are **identical**. Since WeasyPrint makes CLI API changes only in new major versions, this package releases a new major version each time to reflect the drift. If WeasyPrint has consecutive releases without CLI API changes, this package supports all of them under a single version. For detailed information about changes and upgrade paths: * [Changelog](https://github.com/mikerockett/weasyprint/blob/main/CHANGELOG.md) – Documents all changes between versions * [Upgrade Guide](https://github.com/mikerockett/weasyprint/blob/main/UPGRADING.md) – Documents all upgrade paths ## Supported Versions **Current** means the latest maintained version. Versions in **Maintenance** only get security updates and bug fixes. | Version | Status | WeasyPrint Version | Laravel \* | PHP | Branch | | -------- | ----------- | -------------------------- | ---------------- | ---- | ----------------------------------------------------------- | | **11.x** | **Current** | 67, 68, 69 | 12.x, 13.x | 8.3+ | [11.x](https://github.com/mikerockett/weasyprint/tree/11.x) | | **10.x** | Maintenance | 63, 64, 65, 66, 67\*\*, 68 | 10.x, 11.x, 12.x | 8.2+ | [10.x](https://github.com/mikerockett/weasyprint/tree/10.x) | ::: warning \* Important considerations about Laravel/Illuminate Before v11, the package was **WeasyPrint for Laravel** and required Laravel as a dependency. It now runs independently without any framework requirements, though a Laravel binding is still available for those who want it. The package still requires `illuminate/support` (tied to the versions listed above), which creates a versioning constraint for Laravel users, but doesn't affect framework-agnostic setups unless they use `illuminate/support` themselves. We may introduce integrations for other frameworks like Tempest in the future. ::: ::: info \*\* WeasyPrint 67 support in 10.x While support for WeasyPrint 67 was added in v10, the new CLI flags it introduced were not implemented until v11 of the package was released. ::: ## Unsupported Versions We typically maintain up to two versions at a time, or just the current version if maintenance has aged out and there are no new releases in the pipeline (ex: if WeasyPrint development is paused or delayed for an extended period of time). The versions listed below are **no longer supported** and **should not be used for new projects**. Existing projects using unsupported versions should upgrade to a supported version. | Version | WeasyPrint Version | Laravel | PHP | | ------- | ------------------ | ------------------- | ---- | | `9.x` | 61, 62 | 10.x, 11.x | 8.2+ | | `8.1.x` | 59, 60, 61 | 10.x, 11.x | 8.1+ | | `8.0.x` | 59, 60 | 10.x | 8.1+ | | `7.x` | Unchecked | 10.x | 8.1+ | | `6.x` | Unchecked | 8.47 | 8.0+ | | `5.x` | Unchecked | 8.0 | 8.0+ | | `4.x` | Unchecked | 7.x, 8.x, 9.x, 10.x | 7.3+ | ::: warning Documentation for unsupported versions is not available on this site. Some older versions may have their own documentation in their READMEs, which are accessible via the applicable version branches on GitHub. :::