
This chapter is a brief introduction to creating a new report in the CiviReport system. You can use the same programming techniques to extend an existing report template. These tasks call for a strong grasp of PHP. More details are available in the wiki page on customizing reports:
http://wiki.civicrm.org/confluence/display/CRMDOC/CiviReport+structure+and+customization.
This section creates a custom report listing all contacts' Display Name, First Name and Last Name. Note that we'll be talking about both Smarty templates (.tpl files) and PHP report templates--be careful not to confuse the two.
Replacing an existing report with your own version is not recommended because you may need the original too, and because an upgrade of CiviCRM will overwrite your changes with the CiviCRM version. In this section, therefore, we'll create a new Smarty template and a new PHP template for the report. You can also copy a template and report to a new location and edit them to create your custom report.
All reports are located under CRM/Report/Form/ and grouped by component.
Create a new Smarty template and a new PHP template for the report. Because this example creates a report about contacts, we'll create a new report template named Contact.php and a Smarty template named Contact.tpl, both in a custom directory (the Contact.php in the custom directory for php scripts, the Contact.tpl in the custom directory for templates). The paths will look like:
PHP_CUSTOM_PATH/CRM/Report/Form/Contact/Contact.php TPL_CUSTOM_PATH/CRM/Report/Form/Contact/Contact.tpl
Add a base class named CRM_Report_Form_Contact_Contact in Contact.php, Your class must inherit the form class used for the report framework. So Contact.php looks like:
<?php
require_once 'CRM/Report/Form.php';
class CRM_Report_Form_Contact_Contact extends CRM_Report_Form {
}
Your Smarty template file must include the report framework template. Thus, Contact.tpl is:
{include file="CRM/Report/Form.tpl"}
Register your report template in CiviCRM. Go to: Administer -> CiviReport -> Register Report. Enter the details shown in the following screenshot.
In a constructor, create an array to hold a contact, which in turn hold an array specifying two fields you want to display.
function __construct( ) {
$this->_columns = array( 'civicrm_contact' =>
array(
'dao' => 'CRM_Contact_DAO_Contact',
'fields' => array( 'first_name' => array( 'title' => ts( 'First Name' ) ), 'last_name' => array( 'title' => ts( 'Last Name' ) ),
) ) );
parent::__construct( );
}Build the display by issuing a SELECT against the database. You can create column headers and fill in each field in the display with the results returned by the SELECT.
function preProcess( ) {
parent::preProcess( );
}
// build select query based on display columns selected
function select( ) {
$select = $this->_columnHeaders = array( );
foreach ( $this->_columns as $tableName => $table ) {
if ( array_key_exists('fields', $table) ) {
foreach ( $table['fields'] as $fieldName => $field ) {
if ( CRM_Utils_Array::value( 'required', $field ) ||
CRM_Utils_Array::value( $fieldName, $this->_params['fields'] )) { $select[] = "{$field['dbAlias']} as {$tableName}_{$fieldName}"; // initializing columns as well
$this->_columnHeaders["{$tableName}_{$fieldName}"]['type'] =
CRM_Utils_Array::value( 'type', $field );
$this->_columnHeaders["{$tableName}_{$fieldName}"]['title'] = $field['title'];
}
}
}
}
$this->_select = "SELECT " . implode( ', ', $select ) . " ";
}
function from( ) {
$this->_from = "FROM civicrm_contact {$this->_aliases['civicrm_contact']}";
}Your custom report template is ready. Press the Preview button to see the results.
After you've installed and tested your report, add it to the CiviCRM wiki as a patch to the project so that it can be used by others in the community.
Custom reports are made of a PHP class and the template. Once we have that, we can go ahead and package it.
You need to prepare the info file as described in the Extensions Framework Chapter.
<?xml version="1.0" encoding="UTF-8" ?>⁞Then once you have the info file, you can start putting the extension package together. We'll choose " org.civicrm.report.grant " to be the unique identifier of the extension, so we need to give the same name to the directory that will contain our extension. Once you've created that, put the info.xml file in it.
<extension key="org.civicrm.report.grant" type="report">
<callback>Grant</callback>
<name>Grant Report</name>
<description>Grant Report allows you to see the summary of grants that
have been admitted to your consitutents by your organisation. </description>
<url>http://civicrm.org</url>
<license>AGPL</license>
<maintainer>CiviCRM Core Team <noreply@civicrm.org></maintainer>
<releaseDate>2010-09-01</releaseDate>
<version>1.0</version>
<develStage>stable</develStage>
<compatibility><ver>3.3</ver></compatibility>
<comments>For support, please contact project team on the forums. (http://forum.civicrm.org)</comments> </extension>
Report needs some additional information compared with custom search and we need to define it somewhere. Therefore, we'll create another XML file called report.xml. That will simply provide the extension framework with all the necessary information needed for adding it to the system. Here's how it looks:
<?xml version="1.0" encoding="UTF-8" ?>
<report_template key="org.civicrm.report.grant">
<report_url>grant/summary</report_url>
<component>CiviGrant</component>
</report_template>Attributes explained:
We should have following directory structure containing following files:
org.civicrm.report.grant/
|-- Grant.php
|-- info.xml
|-- report_template.xml
`-- templates
`-- Grant.tplLooks similar to what you have on your sandbox? Then the last thing required is to put it in the archive - "zip" it and call the file after the key defined at the beginning: org.civicrm.report.grant.zip. Congratulations, you have now packaged your first custom report.