views:

76

answers:

1

I have the need to create an arbitrary amount of reports in many different file formats. Most of the formats I am able to use Smarty to template the output. However, outputting to Excel and PDF complicate things and require the use of FPDF or TCPDF and PHPExcel.

I am trying to figure out the best way to organize my classes via one or more design patterns (if possible).

Output formats: Text - Smarty Text (w/PCL formatting) - Smarty CSV - Smarty HTML - Smarty Excel - PHPExcel PDF - FPDF / TCPDF

These formats need to be able to be in memory for streaming or written to file for later use.

The only thing that is consistent across all reports is that they need data and up until the addition of PDF and Excel support, a template. Currently I have a Report class that has an abstract method called getData(). Each subclass (e.g. SpecificReport) gets the data it needs and stores it in a class property for binding to a template etc.

Each report needs to be available in all formats.

The Report class handles the output at the moment, but adding support for Excel and PDF is making that impossible. There is a lot more than just binding the data to a template like with Smarty. Each report requires specific code. I suppose I could just overload those methods in each report subclass.

Has anyone encountered a similar task? Any advice is welcome.

A: 

Sounds like you could use the Two Step View pattern.

Essentially, your reports get rendered in two passes. The first pass executes the report logic against your model to generate a sort of proto-report object. The first pass proto-report has all the information that goes on the report, organized and grouped as the report needs it.

Once this is complete, the proto-report is fed into a template that renders it to a particular format (pdf, xls, csv, whatever). This second pass generates the report's bytes, which can be stored to a file or sent out over the wire.

Ryan Michela
I think this is a good pattern / idea. The hardest part will be creating the intermediate stage for the Excel and PDF formats. I will essentially have to create a tag scheme and interpreter for those tags if I want to make an ExcelWriter type class that writes any template to an Excel file or stream. I think this pattern is what I was thinking initially, but was deterred by what I just mentioned. Maybe I just wanted it to be easier. =)
Chris Kloberdanz
Don't use a tag scheme and interpreter. Make your intermediate report a graph of objects. Then have your renderers read that graph of objects and translate them into a report.
Ryan Michela
in PofEAA Fowler says that this pattern doesn't work well when there is little commonality between the screens (reports, in our case). Does that apply here? The report data is all the same, but I am having trouble envisioning an intermediate state (object graph) that can be used to create completely separate outputs without using code specific to that report. The proto-report object seems like it could be sufficiently different between PDF and Excel formats. I really do like this idea, I am just trying to wrap my head around how it can work for me.
Chris Kloberdanz
I guess it depends just how much diference there is between the PDF and Excel versions of the same report, although with some creativity, I think it can be done.For example, I had to make an Excel and a Crystal Reports version of the same report. The Crystal version had grouping, headers, sorting and summary rows. The Excel version had every column of every data row in a giant grid for use as a source for pivot tables.Visually, the reports were wildly different, but in an abstract sense, they were nearly the same.
Ryan Michela
I think it's definitely something worth thinking out and trying. I'll have to put on my best thinking cap. Thanks!
Chris Kloberdanz
The builder pattern also has some potential here, I think.
Chris Kloberdanz