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

Jasper Report Bundle Laravel Package

mesd/jasper-report-bundle

A Symfony bundle that integrates JasperReports, letting you compile .jrxml report templates and generate PDF, Excel, HTML, CSV, and other outputs directly from your Symfony application through the bundled JasperReports library.

View on GitHub
Deep Wiki
Context7

Getting Started

1. Install the bundle

composer require mesd/jasper-report-bundle

Register it (Symfony 3 style — this bundle predates Flex recipes):

// app/AppKernel.php
$bundles = [
    // ...
    new MESD\JasperReportBundle\MESDJasperReportBundle(),
];

2. Install Java + JasperStarter on the host

This bundle is a thin Symfony service wrapper; all real work is done by JasperStarter shelling out to Java and JasperReports. Nothing works until both are on the machine that runs PHP:

java -version                 # JRE 8 is the safe bet for this era of JasperReports
which jasperstarter           # or the phar / .bat equivalent

3. Configure it

The bundle exposes a config tree (roughly) for:

# app/config/config.yml
mesd_jasper_report:
    jasperstarter_path: /usr/local/bin/jasperstarter
    java_path: /usr/bin/java
    # working/output directory, must be writable by the web user
    output_path: "%kernel.root_dir%/../var/jasper"

Open vendor/mesd/jasper-report-bundle/DependencyInjection/Configuration.php first — it is the single source of truth for available keys, and the README is sparse enough that reading ~200 lines of bundle source will save you an hour.

4. First use case: render a PDF from a controller

Compile .jrxml → .jasper once, then generate:

public function invoiceAction($id, ReportService $jasper)
{
    $jasper->compile($this->getParameter('reports_dir').'/invoice.jrxml');

    $path = $jasper->generate('invoice', 'pdf', [
        'db'   => ['driver' => 'mysql', 'url' => 'jdbc:mysql://localhost/app',
                   'user' => 'app', 'password' => '...'],
        'params' => ['INVOICE_ID' => $id],
    ]);

    return new BinaryFileResponse($path);
}

Implementation Patterns

Compile at deploy, generate at request. compile() is slow (JVM startup + compile) and .jrxml rarely changes. Bake a app/console command or a Composer post-install hook that compiles every .jrxml in reports/ into the output dir, then treat the .jasper files as build artifacts. Never compile in a hot request path.

Cache the compiled artifact, not the output. Jasper output is user/parameter specific; the .jasper is not. Store .jasper in a persistent writable dir outside var/cache, since cache:clear will nuke it if you put it there.

Data sources — pick one and be consistent:

  • JDBC (driver/url/user/password): fastest, but puts DB credentials on the command line (see Gotchas). Best when the report already has a $P{REPORT_CONNECTION} or a query in the .jrxml.
  • JSON/XML/CSV file: write your Doctrine result to a temp JSON file and hand it to JasperStarter. Slower but keeps the report dumb and testable — you can generate the data without a DB.
  • Parameters + empty datasource: for reports that just render a header/footer/subreport, or use a REPORT_CONNECTION you supply yourself.

Stream, don't accumulate. BinaryFileResponse + ->deleteFileAfterSend(true) on the generated path is the pattern for downloads; the bundle writes to a real file, not a stream, so clean up yourself if you don't use the delete-after-send flag.

Async for anything large. A 30-page XLSX report ties up a PHP-FPM worker for the entire JVM lifecycle. Wrap generation in a Symfony command dispatched via Messenger/Enqueue, write the result to S3 or a var/reports/ bucket, and email or poll for the link. The bundle itself has no async story — you build it.

Organize reports by domain. A flat reports/ dir with 40 .jrxml files becomes unreadable. Use reports/invoice/, reports/fulfillment/ and pass the base name with a subpath to generate().

Testing. Since the bundle is just a service, mock it in unit tests ($this->createMock(ReportService::class)) and assert on the arguments passed to generate(). Integration-test the real JVM path in a single, tagged, slow test group — not in CI on every commit.

Decorate, don't fork. If you need to post-process the output (watermarking, merging PDFs, adding metadata), decorate the bundle's service rather than editing vendor code. The service ID is stable and the wrapper is small enough to wrap cleanly.

Gotchas and Tips

The 2018 release is the biggest gotcha. The last tag is from Feb 2018, which means it targets Symfony 3.x/4.0 and PHP 7.0/7.1. On Symfony 5+/PHP 8 you'll likely need roave/backward-compatibility-check-style triage: Configuration tree API changes, Definition autowiring changes, and controller.service_arguments assumptions. Expect to either pin Symfony 4.4 or maintain a fork. With zero dependents on Packagist, you are the community — budget for that.

Java on the command line is a security surface. JasperStarter takes DB credentials as --db-user/--db-password. Those are visible to any user running ps aux. Mitigate by passing a REPORT_CONNECTION/REPORT_PARAMETERS via a properties file, or by having PHP build the dataset and Jasper read a temp JSON instead.

Escape and validate every path and parameter. The bundle shells out. Report names, output paths, and parameter values that reach the command line must be whitelisted, not just escaped. Never interpolate user input into the report name.

Fonts and encoding. PDFs with accented characters, CJK, or non-Latin scripts will silently render as boxes if the font isn't embedded in the .jrxml. Set the pdfFontName/pdfEncoding in Jaspersoft Studio and ship the .ttf on the server's font path. This is the #1 "works on my machine" issue.

Writable output dir. The web user (www-data/nginx) must be able to write the output path. The bundled commands often assume the CLI user's permissions; test both paths.

JVM memory. Default heap is small. For large reports, set JAVA_TOOL_OPTIONS=-Xmx512m (or the bundle's equivalent java-args config) in the web server environment, not in code — otherwise the process quietly OOMs and you get a generic "generation failed."

Timeouts and orphans. A hung Java process outlives the PHP request. Run generation under timeout, and log the exact command line the bundle builds (enable a debug log level, or strace -f -e execve) so you can reproduce failures manually — that's the fastest debugging loop with this package.

Locale. JasperStarter inherits the shell's locale; number and date formatting in the report can differ between your dev box and prod. Set LC_ALL/LANG explicitly in the environment.

Version-pin everything. Pin both the bundle and JasperStarter. A JasperStarter upgrade can change CLI flags out from under the bundle, and a JasperReports upgrade can reject .jrxml compiled against an older schema.

Extension points. The useful ones are the service definition override (config file in app/config/services.yml), a custom Symfony Command for compilation, and a decorator around the report service for logging/output handling. There's no event dispatcher or plugin system — don't look for one.

When to skip the bundle. If you only need one or two reports, calling jasperstarter via Symfony\Component\Process directly is ~20 lines and eliminates an unmaintained dependency. The bundle earns its keep when you want the DI wiring, config tree, and a consistent service across many reports — not before.

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.
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle
adachsoft/api-version-bundle
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager