Slides for my speech on Drupal Camp Kyiv 2013.
Idea is to introduce to the Drupal programmers/users the alternative way of building reports, including complicated ones.
Showcase is about the Forena Reports Drupal custom module.
3. Introducton
Forena: one of hidden gems
Could be an alternative for Views
Version 7.x
Session outcome for visitors
4. The Forena Reports module
Allows to generate reports when you have SQL to get data
from DB;
Actually, this might be not only Drupal DB;
… and even not only database;
Report consists from 2 parts — SQL and kind of extended
HTML;
Included nice sample reports in the package;
Have a several video screencasts in English;
About ¾ of potentially custom reports can be done with
Forena
8. Need more?
1) Field modifiers:
<frx:field id="date"
format="iso_date"
format-string="Y-m-d"/>
<frx:field id="total_cost"
format="php"
format-string="return
RcnFormats::currency_format($value);"/>
2) Parameters;
3) Formatters
9. Need more?
1) Field modifiers;
2) Parameters in SQL:
... WHERE j.job_id_pk = :job_id
3) Formatters
10. Need more?
1) Field modifiers;
2) Parameters in SQL;
3) Formatters:
natively provided export to popular formats like
CSV, XML, … :
<frx:docgen>
<frx:doc type="..."/>
</frx:docgen>
11. RCN2: a few words about the
applied project
Intranet ERP system;
Complex business logic;
Shared database with a few other systems;
Reporting is one of crucial parts;
12. RCN2: Postgres related info
Datasets aren't huge but diversed — there's
many specialized heavily linked tables;
Active usage of Postgres-specific features;
14. Real life report SQLs – 1/3
Your SQL can be complicated: i.e. some kinky WITH()
--ACCESS=can access reports
WITH base_model_info as (
SELECT m.model_desc base_model
,m.model_id_pk estimate_model_id
,mc.model_component_id_pk model_component_id_pk
FROM model_components mc JOIN models m
ON(mc.model_id_fk = m.model_id_pk)
WHERE model_component_type = 'Base'
)
SELECT
c.composite_id_pk Composite_ID
,c.composite_desc Composite_Description
,bmi.base_model Base_Model
...
15. Real life report SQLs – 2/3
Mighty WHEN-THEN-ELSE, JOINS and GROUP BY's
... FROM v_job_latest_status
INNER JOIN v_jobs_no_contract_value j ON v_job_latest_status.job_id_fk =
j.job_id_pk
LEFT JOIN v_jobmst jm ON j.rdms_job_number = jm.job_number
LEFT JOIN (
SELECT job_id,
SUM(
COALESCE(amount, 0) *
CASE
WHEN amount_key_name = 'debit_nett_amount' OR
amount_key_name = 'amount_excl_gst'
THEN 1
WHEN amount_key_name = 'credit_nett_amount' OR
amount_key_name = 'credit_net_amount' THEN -1
ELSE 0
END
) AS expenditure
FROM v_job_order_expenditure
GROUP BY job_id
) AS e ON e.job_id = j.job_id_pk
LEFT JOIN ( ...
16. Real life report SQLs – 3/3
Brutal UNION and all that jazz together
... from v_cost_report
where group_id = :gl_group
union
select cast(category_id as text) as ordering , 'header' as
rowtype, null as job_number, null as supplier_name,
null as invoice_number, null as invoice_date, category_name as
transaction_description, cast(null as numeric) as amount
from v_cost_report
where group_id = :gl_group
and effective_date > :from_date
and effective_date < :to_date
union
select category_id||'-z' as ordering , 'cat total' as
rowtype,null as job_number, null as supplier_name, ...