Giter Club home page Giter Club logo

soluble-jasper's Introduction

soluble-jasper

PHP Version Build Status codecov Scrutinizer Code Quality PHPStan Latest Stable Version Total Downloads License

PDF report generation with jasper reports for PHP.

Docs: https://belgattitude.github.io/soluble-jasper

Features

  • Report generation in PDF (other formats can be supported, open an issue)
  • Datasources for JDBC, JSON and XML (url or filesystem)
  • Support for PSR-7 responses (stream)

Requirements

  • PHP 7.1+
  • PHPJasperBridge (see install)
  • Java

Dependencies

Examples

Creating a new report

<?php declare(strict_types=1);

use Soluble\Japha\Bridge\Adapter as JavaBridgeAdapter;
use Soluble\Jasper\{ReportRunnerFactory, Report, ReportParams};
use Soluble\Jasper\DataSource\JavaSqlConnection;
use Soluble\Jasper\Exporter\PDFExporter;


// Step 1: Get the report runner
// Good practice is to initialize once and get it from a PSR-11 compatible container

$bridgeAdapter = new JavaBridgeAdapter([
    'servlet_address' => 'localhost:8080/JasperReports/servlet.phpjavabridge'    
]);

$reportRunner = ReportRunnerFactory::getBridgedReportRunner($bridgeAdapter);

// Step 2: Define your report parameters

$report = new Report(
     '/path/my_report.jrxml',
     new ReportParams([
            'BookTitle'    => 'Soluble Jasper',
            'BookSubTitle' => 'Generated on JVM with Jasper reports'
     ]),
     new JavaSqlConnection(
         'jdbc:mysql://localhost/my_db?user=user&password=password',
         'com.mysql.jdbc.Driver'
     )
);

// Step 3: Export the report

$pdfExporter = new PDFExporter($report, $reportRunner);

$pdfExporter->saveFile('/path/my_report_output.pdf', [
    'author' => 'John Doe',
    'title' => 'My document'
]);

// Or for PSR7 response

$response = $pdfExporter->getPsr7Response([
    'author' => 'John Doe',
    'title' => 'My document'    
]);

//$exportManager = $reportRunner->getExportManager($report);
//$exportManager->savePdf('/path/my_report_output.pdf');


/*
$pdfExporter = $exportManager->getPdfExporter();
$pdfExporter->saveFile('/path/my_report_output.pdf');

// Both will need to cache the report 
$psr7Response = $pdfExporter->getPsr7Response();
$stream       = $pdfExporter->getStream();
*/

Datasources

Jasper reports supports multiple datasources for filling the report (see JRApi)

JavaSqlConnection

Example using JavaSqlConnection:

<?php declare(strict_types=1);

use Soluble\Jasper\DataSource\JavaSqlConnection;

$dataSource = new JavaSqlConnection(
     'jdbc:mysql://server_host/database?user=user&password=password',
     'com.mysql.jdbc.Driver'
);

!!! tip For convenience you can also use the JdbcDsnFactory to convert database params.

```php
<?php declare(strict_types=1);

use Soluble\Jasper\DataSource\Util\JdbcDsnFactory;

$dbParams = [
    'driver'    => 'mysql', // JDBC driver key.
    'host'      => 'localhost',
    'db'        => 'my_db',
    'user'      => 'user',
    'password'  => 'password',
    // Optional extended options
    'driverOptions'  => [
        'serverTimezone' => 'UTC'
    ]        
];

$dsn = JdbcDsnFactory::createDsnFromParams($dbParams);

// You should get a jdbc formatted dsn:
//   'jdbc:mysql://localhost/my_db?user=user&password=password&serverTimezone=UTC'
// ready to use as $dsn argument for `JdbcDataSource`
```

JsonDataSource

Example using JsonDataSource:

<?php declare(strict_types=1);

use Soluble\Jasper\{ReportRunnerFactory, Report, ReportParams};
use Soluble\Jasper\DataSource\JsonDataSource;
 
$jsonDataSource = new JsonDataSource('<url_or_path>/northwind.json');
/*
$jsonDataSource->setOptions([
    JsonDataSource::PARAM_JSON_DATE_PATTERN   => 'yyyy-MM-dd',
    JsonDataSource::PARAM_JSON_NUMBER_PATTERN => '#,##0.##',
    JsonDataSource::PARAM_JSON_TIMEZONE_ID    => 'Europe/Brussels',
    JsonDataSource::PARAM_JSON_LOCALE_CODE    => 'en_US'
]);
*/

$report = new Report(
                '/path/myreport.jrxml',
                new ReportParams([
                    'LOGO_FILE' => '/path/assets/wave.png',
                    'TITLE'     => 'My Title'            
                ]),  
                $jsonDataSource);

$reportRunner = ReportRunnerFactory::getBridgedReportRunner($this->ba);
$exportManager = $reportRunner->getExportManager($report);

$exportManager->savePdf('/path/my_output.pdf');

XmlDataSource

Example using XmlDataSource:

<?php declare(strict_types=1);

use Soluble\Jasper\{ReportRunnerFactory, Report, ReportParams};
use Soluble\Jasper\DataSource\XmlDataSource;
 
$xmlDataSource = new XmlDataSource('<url_or_path>/northwind.xml');
/*
$xmlDataSource->setOptions([
    XmlDataSource::PARAM_XML_DATE_PATTERN   => 'yyyy-MM-dd',
    XmlDataSource::PARAM_XML_NUMBER_PATTERN => '#,##0.##',
    XmlDataSource::PARAM_XML_TIMEZONE_ID    => 'Europe/Brussels',
    XmlDataSource::PARAM_XML_LOCALE_CODE    => 'en_US'
]);
*/

$report = new Report(
                '/path/myreport.jrxml',
                new ReportParams([
                    'LOGO_FILE' => '/path/assets/wave.png',
                    'TITLE'     => 'My Title'            
                ]),  
                $xmlDataSource);

$reportRunner = ReportRunnerFactory::getBridgedReportRunner($this->ba);
$exportManager = $reportRunner->getExportManager($report);

$exportManager->savePdf('/path/my_output.pdf');

Logging

You can enable any psr/log compatible logger. Here's a basic example with monolog:

<?php

use Soluble\Japha\Bridge\Adapter as JavaBridgeAdapter;
use Soluble\Jasper\{ReportRunnerFactory, Report, ReportParams};
use Monolog\Logger;
use Monolog\Handler\StreamHandler;

$logger = new Logger('soluble-japha-logger');
$logger->pushHandler(new StreamHandler('path/to/your.log', Logger::WARNING));

$bridgeAdapter = new JavaBridgeAdapter([
    'servlet_address' => 'localhost:8080/JasperReports/servlet.phpjavabridge'    
]);

$reportRunner = ReportRunnerFactory::getBridgedReportRunner($bridgeAdapter, $logger);

$report = new Report('/path/my_report.jrxml', new ReportParams());

// Any exception during report compilation, filling or exporting will
// be logged ;)

Exceptions

When running or exporting a report, the following exception can be thrown:

Generally at compile time:

Exception Description
ReportFileNotFoundException When the report file cannot be opened (PHP or Java side, check perms)
BrokenXMLReportFileException When the report JRXML file cannot be parsed (xml error)
ReportCompileException Compilation error, generally an invalid expression or missing resource
JavaProxiedException Exception on the Java side, and call $e->getJvmStackTrace() for debug
RuntimeException Normally never thrown, see exception message

At filling time:

Exception Description
BrokenJsonDataSourceException When the json datasource cannot be parsed
JavaProxiedException Exception on the Java side, and call $e->getJvmStackTrace() for debug

Installation

This project requires a java server (or service) running on the same machine that will expose the jasper API to the php side (network bridge).

Check the installation example below or a more complex doc here.

JasperBridge

Build a war file

# Example based on php-java-bridge master
$ git clone https://github.com/belgattitude/php-java-bridge.git
$ cd php-java-bridge
$ ./gradlew war -I init-scripts/init.jasperreports.gradle -I init-scripts/init.mysql.gradle 

Deploy on Tomcat (example on ubuntu sudo apt install tomcat8)

$ sudo cp ./build/libs/JavaBridgeTemplate.war /var/lib/tomcat8/webapps/JasperReports.war

Wait few seconds and point your browser to http://localhost:8080/JasperReports, you should see the php-java-bridge dashboard page.

The bridge address can be used in the japha bridge adapter:

<?php declare(strict_types=1);

use Soluble\Japha\Bridge\Adapter;

$ba = new Adapter([
    'driver' => 'Pjb62',
    'servlet_address' => 'localhost:8080/JasperReports/servlet.phpjavabridge'    
]);

// This should print your JVM version
echo $ba->javaClass('java.lang.System')->getProperty('java.version');

If you encounter permissions problems (i.e. the pdf are created under tomcat8 user), just add your user to the tomcat group:

$ sudo usermod -a -G <tomcat group name> <username>

Benchmarks

Early benchmarks for common operation (run on a laptop for now, will do soon on digitalocean). See tests/bench/simple_benchmarks.php.

Jasper compile time and filling (internal)

Benchmark name x1 x5 x10 Average Memory
00_report_mini.jrxml (compile) 43.03ms 179.05ms 347.55ms 35.60ms 18.97Kb
00_report_mini.jrxml (fill) 3.19ms 9.15ms 18.58ms 1.93ms 14.27Kb
01_report_default.jrxml (compile) 39.24ms 192.41ms 338.65ms 35.64ms 0.31Kb
01_report_default.jrxml (fill) 3.70ms 11.22ms 22.75ms 2.35ms 0.44Kb

PDF exports

Benchmark name x1 x5 x10 Average Memory
00_report_mini.jrxml (text-only) 38.74ms 3.76ms 8.58ms 3.19ms 0.79Kb
01_report_default.jrxml (text+png) 318.68ms 1,365.02ms 2,709.56ms 274.58ms 0.75Kb
06_report_barcodes.jrxml (barcodes) 123.81ms 323.71ms 630.51ms 67.38ms 0.75Kb
  • Connection time: 3 ms

Coding standards and interop

soluble-jasper's People

Contributors

belgattitude avatar nicolascarpi avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

Forkers

snyffo

soluble-jasper's Issues

Can we use "WebService" data source?

I want to use WebService data source in our report. I've already tried with your jasper-bridge and it throw error. Can you help me?

Filling report 'EditingSchedule.v2.jrxml' failed with 'JavaProxiedException' (Error filling report "reports/location/EditingSchedule.v2.jrxml". [net.sf.jasperreports.engine.fill.JRExpressionEvalException]: Invoke failed: [[c:JasperFillManager]]->fillReport((o:JasperReport)[o:JasperReport], (i:Map)[o:HashMap], (i:JRDataSource)[o:JREmptyDataSource]). Cause: net.sf.jasperreports.engine.fill.JRExpressionEvalException: Error evaluating expression for source text: ((net.sf.jasperreports.engine.data.JsonDataSource)$P{REPORT_DATA_SOURCE}).subDataSource("schedules") VM: 1.8.0_191@http://java.oracle.com/ (net.sf.jasperreports.engine.fill.JRExpressionEvalException: Error evaluating expression for source text: ((net.sf.jasperreports.engine.data.JsonDataSource)$P{REPORT_DATA_SOURCE}).subDataSource("schedules") VM: 1.8.0_191@http://java.oracle.com/))  

and thank you for your hard work in this project.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.