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

Latex Bundle Laravel Package

bobv/latex-bundle

Symfony bundle that generates .tex files with object-oriented PHP, compiles them to PDF, returns PDF HTTP responses, and caches results to avoid unnecessary regeneration.

View on GitHub
Deep Wiki
Context7

Getting Started

This is a Symfony bundle, not a Laravel package. There is no service provider, no facade, and no config/latex.php published by the package. Your first job is deciding whether to wrap it or reach for barryvdh/laravel-dompdf instead. If you need LaTeX-grade output (math, bibliographies, precise typography), the wrap is worth it.

Step 1 — Runtime prerequisites (do this before touching PHP).

You need a working TeX toolchain on every environment that compiles PDFs:

# Debian/Ubuntu base images
apt-get update && apt-get install -y \
  texlive-latex-base texlive-latex-recommended \
  texlive-latex-extra texlive-fonts-recommended \
  texlive-bibtex-extra

Verify with pdflatex --version inside the same container/user context your queue worker runs as. This is the single most common source of "works on my machine" failures — a pdftoppm-less slim image will compile nothing.

Step 2 — Install the bundle anyway.

composer require bobv/latex-bundle

It will pull Symfony components (symfony/process, symfony/twig-bridge, etc.). Laravel already ships several of these transitively, so check for version conflicts with composer why symfony/process. Note the namespace changed from BobV to Bobv in v3.0.0 — most blog posts and Stack Overflow answers you'll find are stale.

Step 3 — Read the right docs first.

Skip the README (it's thin and still references "Symfony2"). Go straight to src/Resources/doc/documentation.md in the repo, then the UPGRADE.md. The table of contents is the only real map of the API surface.

Step 4 — Build a thin bridge, not an integration.

Do not try to boot the bundle's DI extension. Instantiate the core classes directly in a Laravel service provider:

// app/Providers/LatexServiceProvider.php
public function register(): void
{
    $this->app->singleton(LatexGenerator::class, function () {
        return new LatexGenerator(
            // build the Twig Environment yourself (see Gotchas)
            $this->app->make(\Twig\Environment::class),
            new ProcessBuilder(), // Symfony\Component\Process
            config('latex.paths')
        );
    });
}

First use case — invoice/receipt PDF. Build a LatexElement tree or a Twig .tex.twig template, render, compile to PDF, return a response()->streamDownload(). That's your 30-minute proof of concept; if it takes longer, the toolchain is the problem, not the PHP.

Implementation Patterns

Pattern: Service-layer wrapper around the generator.

Never let controllers touch LatexGenerator directly. Wrap it so tests can swap in a fake and so you have one place to change when the bundle makes a breaking release (they happen — v3 renamed the root namespace).

final class PdfRenderer
{
    public function __construct(private LatexGenerator $generator) {}

    public function render(LatexInterface $doc, string $filename): StreamedResponse
    {
        $pdf = $this->generator->generatePdf($doc); // returns a response/stream per the bundle API

        return response()->streamDownload(
            fn () => print($pdf->getContent()),
            $filename,
            ['Content-Type' => 'application/pdf']
        );
    }
}

Pattern: Always queue PDF generation.

LaTeX compilation is 0.5–5 seconds and shells out. Do it in a job, store the file on a disk, then notify or email a signed URL. This also sidesteps PHP-FPM timeouts and gives you natural retry semantics when pdflatex fails on a bad template.

class GenerateInvoicePdf implements ShouldQueue
{
    public int $timeout = 120;
    public int $tries = 2; // LaTeX rarely succeeds on retry, but transients happen

    public function handle(PdfRenderer $renderer): void { /* ... */ }
}

Pattern: Cache on content hash, not document ID.

The bundle has a "basic caching system," but it's keyed the way Symfony's is. In Laravel you're better off hashing the rendered .tex source plus the template mtime and keying your own cache (file/Redis) on that. You get correct invalidation for free when the template or data changes.

Pattern: Two template strategies, pick one per project.

  1. OOP builder — LatexGenerator + LatexElement subclasses for structured documents with reusable blocks (headers, signature blocks, tables). Good when the document is assembled from many optional parts.
  2. Twig .tex.twig — better when a designer or LaTeX-savvy colleague maintains the template. You render it with real Twig and hand the source to the compiler. Note: this requires wiring a Twig Environment yourself, since Laravel gives you Blade.

Twig bridge, if you go that route:

$twig = new \Twig\Environment(
    new \Twig\Loader\FilesystemLoader(resource_path('latex'))
);
$twig->addExtension(new \Bobv\LatexBundle\Twig\LatexExtension(/* escaping config */));

The bundle's Twig filters escape LaTeX special characters (\, %, $, &, _, #, {, }) — use them on every interpolated variable. Do not hand-escape.

Pattern: Store the generated .tex alongside the PDF in dev. When a compile fails, the error output from pdflatex is often truncated or unhelpful. Having the exact source that failed is the fastest path to a fix.

Gotchas and Tips

  • It is not a Laravel package and does not pretend to be. Dependents count is 0, stars are 23. You are an early adopter on an unusual path. Budget for reading source in vendor/bobv/latex-bundle/src when docs fall short.
  • Symfony DI extension is unusable from Laravel. You'll get LogicException: Bundle "BobvLatexBundle" not registered style errors the moment you try to load the bundle's services through Laravel's container. Don't fight it — instantiate classes manually.
  • The Process component is the coupling point. The bundle shells out via symfony/process. This usually coexists fine with Laravel (Laravel uses it too), but pin versions and test after Laravel upgrades.
  • No binary = silent-looking failures. A missing pdflatex returns a LatexGeneratorException with a shell exit code, not a clear "not installed" message. Assert the binary on boot: Process::fromShellCommandline('pdflatex --version')->mustRun(); in a health check.
  • shell_exec / proc_open must be enabled. Shared hosts and some hardened PHP images disable these. Check php -i | grep disable_functions before promising a feature.
  • Escaping is a real category of bug. Unescaped & in an address or _ in a filename will abort the compile with a cryptic LaTeX error. If you use the OOP builder, ensure you're using the escaped-text element (added in v2.5.1) for all user-supplied strings.
  • Transliteration needs explicit opt-in. Since v2.7.0, Unicode handling requires symfony/string plus escaping.use_symfony_string: true. Since you're not loading the bundle config, wire whatever escaping config the LatexExtension takes directly in your Twig setup — otherwise accented names and em-dashes become ?.
  • The main namespace moved from BobV to Bobv in v3. Old tutorials are wrong. Follow UPGRADE.md.
  • Bibliography is supported but under-documented. You need bibtex (or configured alternative) on the box and a .bib file in the working directory. The v2.5.0 release notes are the only real reference.
  • Symfony 7.1+ / PHP 8.4 compatibility exists as of v5.3.0 and v5.2.0 — but those packages target Symfony's container, not Laravel's. The classes work; the bundle wiring does not. Test the actual classes you instantiate against your PHP version.
  • Debugging recipe that actually works: catch the exception, dump the generated .tex to storage/app/latex-debug/, and run pdflatex -interaction=nonstopmode file.tex by hand. The last 20 lines before the ! are the real error. The bundle's "improve error parsing" change in v5.3.0 helps but does not replace this.
  • Extension point is the element layer. Rather than editing vendor code, subclass the base LatexElement classes for your reusable blocks (letterhead, footer with page numbers, signature grid) and compose them into documents. That's the intended pattern and survives upgrades.
  • Don't use this for simple PDFs. A one-page invoice with a logo and a table is Dompdf territory and 10× the operational cost here. Reserve LaTeX for documents where the output quality is the product.
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.
steadrun/laravel-monitor
labyrinthe/connect-laravel
elmogy/layan
drewdan/sentinel-client
dskripchenko/laravel-llm
fatryst/nuonuo
stevenay/myanfont
gmostafa/php-graphql-client
xeviant/paystack
snowsoft/faker
meditationsteps/blogetc
animalyoung/laravel-influxdb
onix-solutions/sms-telera
lonely-lights/prosetta
oxygen/data
oxygen/core
jengo/base
xiloryx/log-collector
a21ns1g4ts/filament-stripe
la-php/laravel-admin