preload
Jan 31

I needed to add Excel capability to some of my reports in Recess! so I decided a plugin would be the best way to go. There isn’t too much documentation on plugins so far, so I hope this can help a little. This may not be the best way to go, but it can at least be a guide to get started. I chose PHPExcel to be the engine I use to generate the Excel files. Its easy to generate several different versions of files, and csv and pdf, and I like the library.

The entire plugin is downloaded here.

The Recess! way to do this is create a View that Recess can use to display data. The views are called from the controller, so I want to use the view as follows:

 PHP |  copy code |? 
1
/*
2
 * !RespondsWith Layouts, ExcelView
3
 */

The first thing I had to do was create the plugin directory structure and copy the PHPExcel files in. I copied the PHPExcel Classes/ directory into plugins/ryanday/PHPExcel/. Because the Library::import() method assumes FILE.class.php, I had to link PHPExcel.class.php to the actual PHPExcel.php file for things to function smoothly. There may be a way around that, but I figure its part of Recess!izing the library. This is probably a little confusing, so this is what the directory looks like:

  • Classes/
  • ExcelView.class.php
  • PHPExcelPlugin.class.php
    Classes/

  • PHPExcel/
  • PHPExcel.class.php -> PHPExcel.php
  • PHPExcel.php

Please download a copy of the plugin to make it a little more clear.

I started by viewing thebeeline’s post about plugins to get a jumping off point. Then I created the plugin file, PHPExcelPlugin.class.php

 PHP |  copy code |? 
01
<?php
02
Library::import('recess.framework.Plugin');
03
Library::import('ryanday.PHPExcel.Classes.PHPExcel');
04
Library::import('ryanday.PHPExcel.ExcelView');    // This will let us create our own view
05
 
06
class PHPExcelPlugin extends Plugin {
07
 
08
        function init(Application $app) {
09
                MimeTypes::register('xls','application/vnd.ms-excel');
10
        }
11
 
12
};
13

In the init() function I register a new MimeType, ‘xls’. When Recess! can’t find a layout to display data, it will pass registered mimetypes to all the views, so we have to register the ‘xls’ mimetype so our plugin can respond. Recess! will automatically create the headers for xls, and the applications type. Next we create the actual view.

 PHP |  copy code |? 
01
<?php
02
Library::import('recess.framework.AbstractView');
03
 
04
class ExcelView extends AbstractView {
05
        //  This is were we respond to the MimeType we previously registered
06
	public function canRespondWith(Response $response) {
07
		return 'xls' === $response->request->accepts->format();
08
	}
09
 
10
        /*  Most views render the model in a specific way, a spreadsheet is a little different
11
         * though. I require the xls property to be a two dimensional array containing
12
         * the data to be displayed.
13
         */
14
	protected function render(Response $response) {
15
		$objPHPExcel = new PHPExcel();
16
		require_once PHPEXCEL_ROOT . 'PHPExcel/IOFactory.php';
17
		require_once PHPEXCEL_ROOT . 'PHPExcel/Writer/Excel5.php';
18
		$objPHPExcel->setActiveSheetIndex(0);
19
 
20
                /*
21
                 * The following is loosely based on the JsonView code. If we have a model
22
                 * with the xls property set, we create the spreadsheet from that array
23
                 */
24
		$response = clone $response;
25
		foreach($response->data as $key => $value) {
26
			if($value instanceof Model) {
27
				if( isset($value->xls) ) {
28
					foreach($value->xls as $rowId=>$row) {
29
						foreach($row as $colId=>$cell) {
30
							$objPHPExcel->getActiveSheet()->setCellValueByColumnAndRow($colId, $rowId+1, $cell);
31
						}
32
					}
33
				}
34
			}
35
			if($value instanceof Form) {
36
				unset($response->data[$key]);
37
			}
38
			if(substr($key,0,1) == '_') {
39
				unset($response->data[$key]);
40
			}
41
		}
42
 
43
		if(isset($response->data['application'])) unset ($response->data['application']);
44
		if(isset($response->data['controller'])) unset ($response->data['controller']);
45
 
46
                /* I have gone through the docs and can't get ExcelWriter to dump to stdout,
47
                 * this way is a little hack I think, but it works.
48
                 */
49
		$objWriter = PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel5');
50
		$tempfile = tempnam('/tmp', 'recessxls');
51
		$objWriter->save($tempfile);
52
 
53
                // We don't have to mess with headers, Recess! will do that based 
54
                // on the registered Mimetype
55
		readfile($tempfile);
56
	}
57
};
58

So now all our plugins files are setup, and we have to import the plugins into our application. In your app/YourApp/YourAppApplication.class.php add the following lines

 PHP |  copy code |? 
1
Library::import('ryanday.PHPExcel.PHPExcelPlugin');   // Add this import
2
 
3
class YourAppApplication extends Application {
4
   ...
5
   $this->plugins = array(new PHPExcelPlugin());   // instantiate the class to import the library
6
   $this->plugins[0]->init($this);                    // Important!!
7
}

Note the init() call! The MimeType is verified before the plugin is initialized by the Controller. That means the MimeType won’t be registered when the controller looks for it. So we do it ourselves. Finally, in our controller, we create a little example.

 PHP |  copy code |? 
01
/**
02
 * !RespondsWith Layouts, Excel
03
 * !Prefix mainModel/
04
 */
05
class MainModelController extends Controller {
06
 
07
. . .
08
 
09
       /** !Route GET, $id */
10
        function details($id) {
11
                $this->mainModel->id = $id;
12
                if($this->mainModel->exists()) {
13
                        $this->mainModel->xls = array(array("col1","col2","col3"),
14
                                        array("newrow","newcol","keepgoing"),
15
                                        array("lastrow","k","lastcol"));
16
                        return $this->ok('details');
17
                } else {
18
                        return $this->forwardNotFound($this->urlTo('index'));
19
                }
20
        }
21

Now when you visit that particular route, you will get an Excel spreadsheet with the data set in $this->mainModel->xls.

This is just a basic intro on how to create a View plugin. Please comment with any updates, or better way to explain things! This works for me so far, but it hasn’t been tested along a wide distribution of sites.

3 Responses to “Recess Framework Plugins”

  1. Recess Framework Plugins | Coder Online Says:

    [...] Continued here: Recess Framework Plugins [...]

  2. Christine Fürst Says:

    Thanks for this Recess Plugin example.

    Nice to see that belines’s helpful answer to my question about plugins got you inspired to write this plugin. I am still learning and this helps me a lot to get a better understanding of the framework.

    :-)

  3. Laurice Zellous Says:

    Wonderful! It’s was very effective for me. I have used a long time to looking for the best method to learning php easily and now I think I have got something here .BTW, there is another article out there which is also help me much more : http://learning-php-simple.learnmoreskills.com. Hopes you will be interested in it too.

Leave a Reply