PHP Client - WordPress Example

Introduction

This document demonstrates how to use the PHP Client to connect JasperReports Server data with the Wordpress CMS. Wordpress is a very popular PHP application that allows plugins and extensions, so that you can write your own code for the content on a page. Using the PHP wrapper, WordPress can interface with the API to exchange information between a JasperReports Server and a blog post.

The example in this document only covers the runReport feature, although the wrapper has much more functionality, covering all endpoints of the API.

Note: There is now a Wordpress plugin available which allows seamlessly embedding highly interactive reports and data visualizations inside your pages and blog posts using the TIBCO JasperReports® IO microservice engine.

Requirements:

  • A webserver
  • PHP >=5.3 PEAR packages required by the PHP Client (see README)
  • WordPress blog (see WordPress Installation)

PHP Script

In order to receive data using the PHP wrapper, you must create and host a .php file that you can make requests with. In this example, jQuery is used to request data from a PHP script, and that data populates a drop down menu, as well as execute reports and return their data.

Let's begin with the PHP script used to generate data from the server, name it runreport.php:

<!--?php
require_once('jasperclient/JasperClient.php');
 
class WPReport {
 
    public $client;
    private $mime_types = array(
            'html' =--> 'text/html',
            'pdf' => 'application/pdf',
            'xls' => 'application/vnd.ms-excel',
            'csv' => 'text/csv',
            'docx' => 'application/vnd.openxmlformats-
   officedocument.wordprocessingml.document',
            'rtf' => 'text/rtf',
            'odt' => 'application/vnd.oasis.opendocument.text',
            'ods' => 'application/vnd.oasis.opendocument.spreadsheet',
            'xlsx' => 'application/vnd.ms-excel'
            );
 
    public function __construct() {
        $this->client = new Jasper\JasperClient('localhost', 8080,
        'jasperadmin', 'jasperadmin', '/jasperserver-pro', 'organization_1');
    }
 
 
    /**
     * run() is to be called via a GET parameter. Using run() will run a
     report specified by URI and FORMAT get calls.
     * Example:
     thisfile.php?func=run&uri=/reports/samples/AllAccounts&format=pdf
     * Calling the file in this manner will return the binary of the
     specified report, in PDF format
     */
    public function run() {
        if(isset($_GET['uri']) && isset($_GET['format'])) {
            $report_data = $this->client->runReport($_GET['uri'], $_GET['format']);
            if ($_GET['format'] !== 'html') {
            echo $this->prepareForDownload($report_data, $_GET['format']);
            }
            else {
                echo $report_data;
            }
        }
    }
 
    /**
     * This function prepares a page with the proper headers to initiate
     a download dialog in modern browsers
     * by using this function we can supply the report binary and users
     can download the file
     */
    private function prepareForDownload($data, $format) {
            header('Cache-Control: must-revalidate');
            header('Pragma: public');
            header('Content-Description: File Transfer');
            header('Content-Disposition: attachment;
     filename=report.'.$format);
            header('Content-Transfer-Encoding: binary');
            header('Content-Length: ' . strlen($data));
            if(isset($this->mime_types[$format])) {
                header('Content-Type: ' . $this->mime_types[$format]);
            } else {
                header('Content-Type: application/octet-stream');
            }
            echo $data;
    }
    /**
     * This function returns the reports vailable at the position 'uri'
     * the data is echoed in JSON format so it can be used by a jQuery
   function
     * to populate a dropdown select HTML element
     * example: thisfile.php?func=getReports&uri=/reports/samples
     */
    public function getReports() {
        if(isset($_GET['uri'])) {
            $result = array();
            $repo = $this->client->getRepository($_GET['uri']);
            foreach($repo as $r) {
                $result[] = array('name' => $r->getName(), 'uri' =>
                $r->getUriString());
            }
            echo json_encode($result);
        }
    }
    /**
     * This function simply json-ifys the array above to populate a
  drop-down menu
     * select HTML element. This way it is easy to change the formats
  available
     */
    public function getTypes() {
        $result = array();
        foreach($this->mime_types as $key => $val) {
            $result[] = array('name' => $key, 'value' => $val);
        }
        echo json_encode($result);
    }
} // WPReport
 
/* If the function exists in our class, and it is requested, then run it */
 
if(isset($_GET['func']) &&
    method_exists('WPReport', $_GET['func'])) {
        $r = new WPReport();
        $r->$_GET['func']();
}
?>

Breaking down the PHP Script

First, the beginning of the file defines variables that are needed by a class. $client will hold the client object through which commands to the Jaspersoft Reports Server can be made. The $mime_types array is used to map file extensions to their respective MIME types. This is used when serving files for download.

The Run Function

public function run() {
        if(isset($_GET['uri']) && isset($_GET['format'])) {
            $report_data = $this->client->runReport($_GET['uri'],
          $_GET['format']);
            if ($_GET['format'] !== 'html') {
            echo $this->prepareForDownload($report_data,
          $_GET['format']);
            }
            else {
                echo $report_data;
            }
        }
    }

This function is runs a report on the server, and serves the data returned. When a URI and format are supplied in the URL as GET parameters, this function uses the client object to request a report from the server. If the report is requested in HTML, it is echoed. If it is any other format but HTML, it is passed to a different function that sends the proper headers along with the binary data so the file can be accepted for download by a browser.

The prepareForDownload Function

The prepareForDownload function is only used to prepare the headers to be sent and echos the data from the server. This way when the file is retrieved, the browser knows how large it is, what to do with it, what to name it, and other data that signify a download dialog box.

The report is displayed. This data is retrieved from the run function.

getReports / getTypes function
public function getReports() {
        if(isset($_GET['uri'])) {
            $result = array();
            $repo = $this->client->getRepository($_GET['uri']);
            foreach($repo as $r) {
                $result[] = array('name' => $r->getName(), 'uri' =>
             $r->getUriString());
            }
            echo json_encode($result);
        }
    }
 
    public function getTypes() {
        $result = array();
        foreach($this->mime_types as $key => $val) {
            $result[] = array('name' => $key, 'value' => $val);
        }
        echo json_encode($result);
    }

These two functions are used to prepare data for the jQuery script to populate the drop-down menus. The first function (getReports) uses getRepository to request all the reports' resourceDescriptors as 'uri' (defined by a GET variable). Then it takes this data, maps the name and URI to each other, and encodes it in a JSON format that can be easily consumed by JavaScript.

The getTypes function does the same, except it only uses the data in the $mime_types array to supply the second drop-down menu item with the types that can be taken. This data could easily be hard-coded into the HTML, but for simplicity this function is used.

Outside the WPReport class
if(isset($_GET['func']) &&
    method_exists('WPReport', $_GET['func'])) {
        $r = new WPReport();
        $r->$_GET['func']();
}

These final lines of code interpret the GET data when the page is requested. It executes the function determined by the GET parameter func and runs the corresponding function. This way we don't have to maintain separate files for each task.

JavaScript Code

This specific example uses JavaScript to improve the user experience when using the report generator. It also prevents the page from reloading when requesting different reports. Coupling the JavaScript with an iframe we can serve the data generated by the prepareForDownload function without reloading the page.

jQuery(function(){
 
    // Manage AJAX loading image
    jQuery('#loading').hide();
    jQuery('#loading').bind( "ajaxStart", function(){ jQuery(this).show(); })
                      .bind( "ajaxStop" , function(){ jQuery(this).hide(); });
 
    // populate the dropdown box for the names of the reports
    jQuery.getJSON("http://localhost/runreport.php?func=getReports&uri=/reports/samples"
                  ,function(data){
                       var sel = jQuery("#reportList").empty();
                       jQuery.each(data
                                  ,function(){
                                       sel.append(jQuery("<option>")
                                          .val(this.uri).text(this.name)); }); });
    // populate the dropdown for types of export
    jQuery.getJSON("http://localhost/runreport.php?func=getTypes"
                  ,function(data){
                       var sel = jQuery("#exportList").empty();
                       jQuery.each(data
                                  ,function(){
                                       sel.append(jQuery("</option><option>")
                                          .val(this.name) .text(this.name)); }); });
    // on 'submit' get the report. display html in div, other formats activate hidden
    // iframe to trigger download
    jQuery('#repsub').on('click', function(event) {
        if (jQuery('#exportList').val() !== 'html') {
            document.getElementById("hFrame").src
             = 'http://localhost/ runreport.php?func=run&uri='
              +jQuery('#reportList').val()
              +' &format='
              +jQuery('#exportList').val();
        }
        else {
            jQuery('#displayReport').load('/wordpress/wp-content/plugins/jasper/runreport.php?func=run&uri='
                                          +jQuery('#reportList').val()+ '&format='+jQuery('#exportList').val());
        }
    });
});

Ajax

A loading indicator is created and bound to ajaxStart, so it is displayed whenever Ajax requests are being made. It is also set to hide when Ajax requests stop being made.

The first getJSON function is used to populate the list of reports. It requests the data in JSON format from our PHP script. As you can see in the URL, it defines the function that is called, as well as the URI we wish to request reports from. An example of the data this returns is:

[{"name":"AllAccounts","uri":"\/reports\/samples\/AllAccounts"},
{"name":"Cascading_multi_select_report","uri":"\/reports\/samples\/Cascading_multi_select_report"},
{"name":"Department","uri":"\/reports\/samples\/Department"},
{"name":"EmployeeAccounts","uri":"\/reports\/samples\/EmployeeAccounts"},
{"name":"Employees","uri":"\/reports\/samples\/Employees"},
{"name":"FlashChartReport","uri":"\/reports\/samples\/FlashChartReport"},
{"name":"FlashMapReport","uri":"\/reports\/samples\/FlashMapReport"},
{"name":"FlashWidgetReport","uri":"\/reports\/samples\/FlashWidgetReport"},
{"name":"Freight","uri":"\/reports\/samples\/Freight"},
{"name":"OpenFlashChartsReport","uri":"\/reports\/samples\/OpenFlashChartsReport"},
{"name":"PermissionsOfUsersWithARoleSharedByLoggedIn","uri":"\/reports\/samples\/PermissionsOfUsersWithARoleSharedByLoggedIn"},
{"name":"SalesByMonth","uri":"\/reports\/samples\/SalesByMonth"},
{"name":"StandardChartsAegeanReport","uri":"\/reports\/samples\/StandardChartsAegeanReport"},
{"name":"StandardChartsEyeCandyReport","uri":"\/reports\/samples\/StandardChartsEyeCandyReport"},
{"name":"StandardChartsReport","uri":"\/reports\/samples\/StandardChartsReport"}] 

Luckily, this data makes more sense to JavaScript/jQuery than it does to a person. This data is basically a listing of report names and their URIs that can be used to set the name and value attributes of the element.

Data is transferred from the PHP script to the second drop down menu in the same way as shown in the next getJSON function.

jQuery('#repsub').on('click', function(event) {
        if (jQuery('#exportList').val() !== 'html') {
            document.getElementById("hFrame").src = 'http://localhost
          /runreport.php?func=run&uri='+jQuery('#reportList').val()+'&format=
          '+jQuery('#exportList').val();
        } else {
            jQuery('#displayReport').load('http://localhost/runreport.php
          ?func=run&uri='+jQuery('#reportList').val()+'&format'
          +jQuery('#exportList').val());
        }
});

This final function is bound to the Submit button. When it is clicked, two things can occur. The values chosen in the drop-down menus are taken using the .val() function and are used to fill in the GET arguments for the PHP script's URI and format options. Thus, if the report type is HTML, when the button is pressed, a DIV element is filled with the HTML produced by the script. Otherwise, we set the SRC attribute of a hidden iframe (id = hFrame) to the script. This is necessary because the headers must be the first thing served if a download dialog box is displayed. So by loading it through an iframe we are not bogged down by previously-loaded blog data.

Sample Blog Post

We now need a user-facing form in HTML that incorporates the previous two scripts. To do this, add a new post with some HTML. If you are having trouble writing HTML in your posts, you might want to disable WordPress's visual text editor (Admin Panel > Users > Your Profile > Disable visual editor).

Use the following code in your post:

<div id="reportBox">
    <h3 class="widget-title">View My Reports</h3>
    <label for="reportList"> Report name: </label>
    <select id="reportList" style="width:150px;">
        <!-- populated by jquery -->
    </select>
    <label for="exportList"> Download as: </label> <br>
    <select id="exportList">
        <!-- populated by jquery -->
    </select>
    <input name="submit" id="repsub" type="submit" value="submit" />
    <label for="repsub" id="loading" >
        <img src="http://localhost/ajax-loader.gif" /> 
    </label>
    <div id="displayReport"></div>
    <iframe style="display:none" id="hFrame"></iframe>
</div>
 
<!-- Scripts Below -->
 
<script type="application/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.js" />
<script src="http://localhost/script.js" type="application/javascript" />

Loading the JavaScript, the menus are populated, and the Submit button becomes active.

Hosting

The JavaScript file can be hosted anywhere accessible to the browser attempting to use it. The PHP script must be accessible to the browser using the site, as well as the server hosting the WordPress blog. In this example we use full paths to define the location of these scripts. However, it's fine to use relative paths in the correct context. The PHP client must be accessible to the PHP script so it can be included properly. To make that happen, you might need to adjust the require_once() function to match your environment.

Feedback
randomness