Question

I'm planning to use Mustache templates along with Kohana in my next project. So what I'm trying to do is to make Kohana seamlessly use Mustache whenever rendering a view. For example, I would have this file in my views folder:

myview.mustache

Then I can do in my application:

$view = View::factory('myview');
echo $view->render();

Just like I would do with a regular view. Does Kohana allow this kind of thing? If not, is there any way I could implement it myself using a module? (If so, what would be the best approach?)


PS: I had a look at Kostache but it uses a custom syntax, which for me is the same as using Mustache PHP directly. I'm looking to do it using Kohana's syntax.


Edit:

For information, this is how I ended up doing it, based on @erisco's answer.

The full module is now available on GitHub: Kohana-Mustache

In APPPATH/classes/view.php:

<?php defined('SYSPATH') or die('No direct script access.');

class View extends Kohana_View {

    public function set_filename($file) {
        $mustacheFile = Kohana::find_file('views', $file, 'mustache');
        // If there's no mustache file by that name, do the default:
        if ($mustacheFile === false) return Kohana_View::set_filename($file);

        $this->_file = $mustacheFile;

        return $this;
    }


    protected static function capture($kohana_view_filename, array $kohana_view_data) {
        $extension = pathinfo($kohana_view_filename, PATHINFO_EXTENSION);
        // If it's not a mustache file, do the default:
        if ($extension != 'mustache') return Kohana_View::capture($kohana_view_filename, $kohana_view_data);

        $m = new Mustache;
        $fileContent = file_get_contents($kohana_view_filename);
        return $m->render($fileContent, Arr::merge(View::$_global_data, $kohana_view_data));
    }

}
Was it helpful?

Solution

Yes, you can. Since Kohana does some trickery with autoloading, what they dubbed "Cascading Filesystem", you can effectively redefine the functionality of core classes. This is something that Code Igniter also does, if you are familiar.

Particularly, this is the View::factory method you are referring to. Source.

public static function factory($file = NULL, array $data = NULL)
{
    return new View($file, $data);
}

As you can see, this returns an instance of View. Initially, View is not defined, so PHP goes looking for it using autoloading. This is when you can take advantage of the cascading filesystem feature by defining your own View class, which must be in the file APPPATH/View.php where APPPATH is a constant defined in index.php. The specific rules are defined here.

So, since we can define our own View class, we are good to go. Specifically, we need to override View::capture, which is called by $view->render() to capture the inclusion of the template.

Take a look at the default implementation to get an idea of what to do and what is available. I've outlined the general idea.

class View
{
    /**
     * Captures the output that is generated when a view is included.
     * The view data will be extracted to make local variables. This method
     * is static to prevent object scope resolution.
     *
     *     $output = View::capture($file, $data);
     *
     * @param   string  filename
     * @param   array   variables
     * @return  string
     */
    protected static function capture($kohana_view_filename, array $kohana_view_data)
    {
            // there 
            $basename = $kohana_view_filename;

            // assuming this is a mustache file, construct the full file path
            $mustachePath = $some_prefix . $basename . ".mustache";

            if (is_file($mustachePath))
            {
                // the template is a mustache template, so use whatever our custom
                // rendering technique is
            }
            else
            {
                // it is some other template, use the default
                parent::capture($basename, $kohana_view_data);
            }

        }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top