Writing a module for Kohana3

Posted on December 20, 2010

In this tutorial we will cover how to build a module from scratch in Kohana 3. If you aren’t familiar with the Kohana framework then I recommend you read the beginners introduction to Kohana.

The Plan

We will be building a module that replaces Kohana’s own view layer (Kohana_View). It will use the PHP template library Twig. We want our own view layer to be API compatible with Kohana’s view layer. This will ensure that other modules work out of the box and that the only code the developer will need to alter in their application are the templates (so that they are Twig compatible). No code in any controller will need to be modified.

Because Kohana follows HMVC (see beginners introduction to Kohana) we will be calling our class View. This means that all calls in the application to the class of View will be to the View class in our module, not Kohana’s own View class.

Directory Structure

Enabling The Module

The name of any Kohana module is the same name as the directory inside the modules directory. So in this case it is twig. To activate any module, we must add it to the array passed to Kohana::modules in application/bootstrap.php.

application/bootstrap.php – line 88

Kohana::modules(array(
	'twig' => MODPATH.'twig',
	// 'auth'       => MODPATH.'auth',       // Basic authentication
	// 'cache'      => MODPATH.'cache',      // Caching with multiple backends
	// 'codebench'  => MODPATH.'codebench',  // Benchmarking tool
	// 'database'   => MODPATH.'database',   // Database access
	// 'image'      => MODPATH.'image',      // Image manipulation
	// 'orm'        => MODPATH.'orm',        // Object Relationship Mapping
	// 'oauth'      => MODPATH.'oauth',      // OAuth authentication
	// 'pagination' => MODPATH.'pagination', // Paging of results
	// 'unittest'   => MODPATH.'unittest',   // Unit testing
	// 'userguide'  => MODPATH.'userguide',  // User guide and API documentation
	));

Twig

We will be using Fabien Potencier’s Twig project as a replacement templating engine for Kohana. The Twig files themselves will be stored in modules/twig/Twig/. If you are familiar with git you could create a git submodule of Twig so you can update Twig independently from our twig Kohana module. However for the sake of this tutorial it is easier just to download the tarball and extract it.

Rather than including all Twig files explicitly (using include or require statements) we will use Twig’s own autoloader. We could call it either in application/bootstrap.php or modules/twig/init.php. Since the autoloader is specific to the twig module (and not to the application) it is better to put it in modules/twig/init.php. Every init.php file in every enabled module is called automatically every request by Kohana.

modules/twig/init.php

require 'Twig/Autoloader.php';

Twig_Autoloader::register();

Configuration

Each developer that uses our twig module will have a different template directory and will want to pass different options to the Twig library when it’s instantiated (such as whether Twig runs in debug mode). Rather than hard coding these options into our module (which would force every developer using it to alter module code) we can use Kohana’s configuration system.

Because the configuration for our module is application specific, create application/config/twig.php

application/config/twig.php

// http://www.twig-project.org/book/03-Twig-for-Developers

return array(

	//Edit these per app.
	'template_dir' => 'C:/wamp/www/kohanaresources/application/views/',
	'cache_dir' => 'C:/wamp/www/kohanaresources/application/cache/',

	//Set to false in production application
	'auto_reload' => true,
	'debug' => true,

	//Misc settings. Don't touch unless you know what your doing.
	'trim_blocks' => false,
	'charset' => 'utf8',
	'base_template_class' => 'Twig_Template',
	'strict_variables' => false,

);

To access these array parameters that the developer sets, its a simple matter of:

Kohana::config('twig.template_dir');

The View Class

modules/twig/classes/view.php is going to contain our class, View. It will handle the rendering of the template using Twig. As discussed above, we want our View class to have the same API as Kohana_View, so we will copy system/classes/kohana/view.php and make a small alteration to it. Most of the methods in Kohana_View provide different ways to set variables to the instance of Kohana_View. For example all three of these essentially do the same thing:

$v = new View('some/template');

$v->website = 'Query7';
$v->set('website', 'Query7');
$v->bind('website', 'Query7');

All loading and parsing of the template file is done in View::capture(). This is the only method from the original Kohana_View class that we will need to alter. Here is our new method in full:

modules/twig/classes/view.php – View::capture

protected static function capture($kohana_view_filename, array $kohana_view_data)
{
	if (isset(View::$_global_data))
	{
		$data = array_merge($kohana_view_data, View::$_global_data);
	}
	else
	{
		$data = $kohana_view_data;
	}

	$loader = new Twig_Loader_Filesystem(Kohana::config('twig.template_dir'));

	$twig = new Twig_Environment($loader, array(

		'cache' => Kohana::config('twig.cache_dir'),
		'debug' => Kohana::config('twig.debug'),

		'auto_reload' => Kohana::config('twig.auto_reload'),
		'trim_blocks' => Kohana::config('twig.trim_blocks'),
		'charset' => Kohana::config('twig.charset'),
		'base_template_class' => Kohana::config('twig.base_template_class'),
		'strict_variables' => Kohan::config('twig.strict_variables')
	));

	$template = $twig->loadTemplate($kohana_view_filename);

	return $template->render($data);
}

Our function first combines all data to be passed to the template in a single array, $data. It then instantiates Twig_Loader_Filesystem and passes the location of the template directory to it. Twig_Enviroment is then instantiated and the different configuration options are passed there. Finally the template is loaded and rendered.

Example of twig in use

some method in a controller

$v = new View('colors.html');

$v->colors = array('red','blue','yellow','purple');

$this->request->response = $v->render();

colors.html

{% for c in colors %}
    {{ c }},
{% endfor %}

output

red,blue,yellow,purple,

Finishing Up

After you have finished any Kohana module you should write the necessary documentation and tests. Kohana has it’s own module that integrates PHPUnit with the Kohana framework. The majority of Kohana modules are open source on Github, with repositories named kohana-*modulename*. Finally you will want to promote your module. Announcing it on the Kohana forum and on Twitter are good ways to get it some attention.

If you have any questions or feedback please leave them in the comments below.

Leave a Reply

You must be logged in to post a comment.