Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Terms Module Snappy Bundle Laravel Package

rich-id/terms-module-snappy-bundle

A Laravel module from rich-id that bundles terms and conditions handling with Snappy PDF support, so you can manage, render, and serve policy documents from a single package. Note: minimal adoption and metadata; review the source before use. (219 characters)

View on GitHub
Deep Wiki
Context7

Getting Started

This is a first-party-style bundle (0 stars, 0 dependents, single tagged release v1.0.0 — "Initial version of Snappy Generator") that plugs the Snappy PDF engine — the PHP wrapper around the wkhtmltopdf binary — into the rich-id/terms-module renderer pipeline. The release note tells you two things and nothing more: the package owns a generator abstraction (expect a class named something like SnappyGenerator rather than SnappyDriver), and v1.0.0 is the first cut, not a stabilisation. Semver 1.0.0 on an initial version is a packaging decision, not a maturity signal — read src/ before writing code.

Minimum path:

  1. Install the binary first, the package second. Snappy shells out to wkhtmltopdf; there is no pure-PHP fallback. On Debian/Ubuntu: apt-get install wkhtmltopdf; on macOS: brew install --cask wkhtmltopdf. Confirm with wkhtmltopdf --version and record the exact version in your Dockerfile — pagination changes between 0.12.5 and 0.12.6.
  2. composer require rich-id/terms-module-snappy-bundle and check composer.json constraints against your PHP/Laravel version manually (composer why-not rich-id/terms-module-snappy-bundle). An initial 1.0.0 will target the Laravel version current at the time of writing, not yours — verify before assuming it boots on 11/12.
  3. Publish config: php artisan vendor:publish --provider="RichId\TermsModuleSnappy\...ServiceProvider" (or --tag=terms-snappy). You are looking for binary_path, an options array, and a key that names/selects the generator. If vendor:publish lists nothing, the package may ship config inline-only — read the provider's register() to find the merge key.
  4. Register the generator. If the bundle is not auto-discovered, add the provider to config/app.php (Laravel ≤10) or bootstrap/providers.php (Laravel 11+), and check whether config/terms.php in the core module needs 'renderer' => 'snappy' or a Manager::extend('snappy', ...) call. The word "Generator" in the release note suggests it implements a generator contract rather than a renderer one — confirm which interface you actually have to satisfy before wiring anything.
  5. First use case: render an existing terms document to PDF for a preview endpoint — response()->streamDownload(fn () => $pdf, 'terms.pdf', ['Content-Type' => 'application/pdf']), with inline instead of attachment for an in-browser preview. This is the smallest end-to-end slice that exercises binary path, generator resolution, template rendering, and HTTP response at once.

Where to look first: the provider's register()/boot() (what it binds and under what key), the generator class (what options it forwards to Snappy, and whether options are per-call or per-constructor), and the core terms-module generator/renderer interface (what you actually have to satisfy). Because there is exactly one release note line and no changelog history, src/ is the only documentation that exists.

Implementation Patterns

Keep Snappy as transport, not as a template engine. Let the terms module own documents, revisions, and Blade/HTML templates; let this bundle own only "HTML string in, PDF bytes out." That boundary is what makes it replaceable later — and with a 1.0.0 initial release, replaceability is the main thing you are buying.

Profile-based options. Snappy's option array is where all the real behaviour lives (--page-size, margins, --header-html, --footer-html, --enable-local-file-access, --dpi, --disable-smart-shrinking). Define named profiles in config (terms, letter, receipt) and select one per document type rather than mutating a global array at call time. On a first release, expect the config to expose a single flat options array; wrapping it in profiles yourself is cheap insurance against upstream changing that shape.

Render Blade to a string, then hand it over. view('terms.pdf.document', $data)->render() produces the HTML; the generator converts it. This keeps CSS and assets inside your app, avoids giving Snappy filesystem paths, and makes the HTML unit-testable without invoking a binary.

Stream vs. persist. Two distinct patterns:

  • On-demand: stream the response and never store the bytes. Simplest, but every request pays the wkhtmltopdf subprocess cost (~200ms–2s).
  • Cached artifact: store on a disk keyed by document_id . updated_at . hash(options), serve from storage, and bust the cache on document save. This is what you want for anything user-facing at scale — and it also insulates you from the generator's API changing under a patch release.

Queue it when it's big. Snappy is synchronous and blocking. Multi-page documents with remote assets belong in a job; return a "generating" state and notify or email the artifact. Never call it inside a request that also does DB writes you care about — a hung render will hold the transaction.

Test against the contract, not the bytes. In CI, bind a fake generator at the terms-module interface and assert on the HTML and options passed in. Snapshot-testing PDF bytes is brittle across binary versions; if you must run the real binary, pin it in the test image and assert page count via pdfinfo, not file hash.

Integration tip: if your app already has barryvdh/laravel-snappy, check for a duplicate Knp\Snappy\Pdf binding before installing — two packages registering the same service is a classic silent-override bug here, and with a single-release dependency you have no upstream issue tracker to confirm which one wins.

Gotchas and Tips

  • wkhtmltopdf is unmaintained and its QtWebKit engine is ancient. No flexbox, no grid, patchy CSS3, unreliable webfonts. Write PDF templates with tables and floats, and keep a browser-side reference: if headless Chrome renders it correctly and Snappy doesn't, it's CSS support, not your code.
  • --enable-local-file-access is mandatory on newer builds for local CSS and images. Without it, assets fail silently into blank space — no exception, no log line. Prefer absolute URLs from asset() or Storage::url() over relative paths.
  • Fonts. Headless hosts without fontconfig and a font set will substitute glyphs and break every layout measurement. Install your fonts in the image explicitly.
  • Headless Qt quirks. Some builds need QT_QPA_PLATFORM=offscreen or xvfb-run; use a distro-patched wkhtmltopdf package rather than a raw static download where you can.
  • Timeouts. Snappy will hang on unreachable remote CSS/fonts indefinitely. Set an explicit timeout in the options and forbid remote <link>/@import in terms templates.
  • Generator resolution order. If the terms module's manager caches resolved generators, Manager::extend('snappy', ...) must run in a provider that boots before the first resolution. Symptom: "driver/generator not supported" intermittently, depending on which request path triggers it first. First releases commonly get this boot ordering wrong — if the bundled provider is deferred, force it non-deferred.
  • Debug by dumping the intermediate HTML. Write it to storage/app/debug/{id}.html, open it in Chrome, and print with --print-to-pdf. That isolates "my HTML is wrong" from "Snappy can't render my HTML" in seconds. With no upstream docs, this is also the fastest way to reverse-engineer what options the generator actually forwards.
  • Sanitize author-supplied content. Terms documents are often written by non-developers in a WYSIWYG. Sanitize before rendering — injected remote URLs in <img src> are an SSRF vector through the generator's network access, and stray <script> behaves inconsistently between QtWebKit versions.
  • Treat it as unmaintained until proven otherwise. One release, one line of release notes, zero dependents, no community triage, no changelog to diff against. Pin the exact version ("1.0.0", not ^1.0), fork it into your VCS if you need a fix, and don't build a roadmap on upstream responsiveness. If a v1.0.1 appears, read the diff before updating — an initial-version package has no compatibility promises to lean on.
  • The exit hatch. Because everything worthwhile lives behind the terms-module generator contract, the clean long-term move is a second implementation — spatie/browsershot for Chrome-quality output, or dompdf for trivial documents — and keep this bundle only for legacy templates. Design your call sites so swapping the generator is a config change, not a refactor.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
robertmarney/lara-hierarchial-collections
simonschaufi/rule-doc-generator
emissaoja/emissaoja
blackbricksoftware/gravityforms-civicrm-form-processor
al-rahabi/fancy-crud
jinas/dhivatar-component
mltstephane/laravel-quality
bernskiold/laravel-talentlms
bernskioldmedia/laravel-form-architect