I had originally developed a line printer type reporting system
[Gtk_TextReport]
to do this, which had a crude interface to design text reports.
Unfortunatly as we came to production, this never really delivered on
it's promise. (it was designed to mimic the old DOS application they
where using). So I had to explore alternatives.
FPDF
[www.fpdf.org]
is quite a nice library for creating PDFs, however, the thought of
hardcoding up all the locations in PHP, for all the text on both
applications horrified me.
My first idea was to consider writing a HTML to PDF generator, based off of Flexy's
[HTML_Template_Flexy]
's tokenizer, which is extremely good at parsing loose HTML and XML.
but after spending half a day looking at this, and the issues, decided
that it was just too messy. The amount of data that I needed to overlay
as extra attributes pretty much exceeded the amount of HTML. The other
snag is that the Tokenizer in Flexy is designed to be used cached
parser, as it is by the Flexy compiler (it's a bit slow for large html
files).
So Idea no.2 was to use SVG, Something I'd been thinking of using for a number of projects (mostly with PHP-GtkCanvas), What it needed was to have some kind of markup language, similar to Flexy, eg {xxxx} reads variable $page->xxxx, and {xxxx()} calls
$page->xxx(), The resulting package
[XML_SvgToPdf] was reasonably simple, taking about 2 days to write
It uses
[XML_Tree_Morph], a simple wrapper for
XML_Tree, to morph the XML in an svg file into an object type based on the tag, eg. <tspan ...> gets mapped to XML_SvgToPdf_Tspan, when the parser finds the closing XML tag, the XML_Tree_Node for that element is sent to the fromNode($node) method of the XML_SvgToPdf_* classes (most of which are handled by the base class). These just flatten out the attributes into object properties, copy the children, and parse the style tag.
To convert it to PDF, you then just implement a toPDF method in each of the classes, and send it the $pdf (from FPDF), and $data - what data you want to replace the {xxxx} tags with.
To get the 'dynamic looping' eg. for the mailing list I needed 3 columns and 7 rows, I created
- A text item on the SVG with
dynamic=name_of_var_to_use
rows=3
cols=7 - A rectangle, that had the sodipodi flag (not printable - under item properties)
- make these, and the text {xxxx} into a group.
the parser then checked every group looking for xxx=yyy text, if it found it, it was flagged as dynamic.
The result has been so effective, I have started replacing all the old 'text' based reports with stylish PDF's.