Merge branch 'feature/mustache-2.0'
This commit is contained in:
commit
ca8d4c86df
|
@ -0,0 +1 @@
|
|||
*.swp
|
157
README.markdown
157
README.markdown
|
@ -2,147 +2,56 @@
|
|||
|
||||
Kostache is a [Kohana 3](https://github.com/kohana/kohana) module for using [Mustache](http://defunkt.github.com/mustache/) templates in your application.
|
||||
|
||||
Mustache is a logic-less template class. It is impossible to embed logic into mustache files.
|
||||
## Usage
|
||||
|
||||
## Example
|
||||
To use, simply create a POPO (Plain Old PHP Object) like so:
|
||||
|
||||
Did you know the pagination view in Kohana is terrible? We are going to fix it:
|
||||
```php
|
||||
<?php
|
||||
|
||||
### How it exists now:
|
||||
class View_Test
|
||||
{
|
||||
public $hello = 'world';
|
||||
|
||||
<p class="pagination">
|
||||
|
||||
<?php if ($first_page !== FALSE): ?>
|
||||
<a href="<?php echo $page->url($first_page) ?>" rel="first"><?php echo __('First') ?></a>
|
||||
<?php else: ?>
|
||||
<?php echo __('First') ?>
|
||||
<?php endif ?>
|
||||
|
||||
<?php if ($previous_page !== FALSE): ?>
|
||||
<a href="<?php echo $page->url($previous_page) ?>" rel="prev"><?php echo __('Previous') ?></a>
|
||||
<?php else: ?>
|
||||
<?php echo __('Previous') ?>
|
||||
<?php endif ?>
|
||||
|
||||
<?php for ($i = 1; $i <= $total_pages; $i++): ?>
|
||||
|
||||
<?php if ($i == $current_page): ?>
|
||||
<strong><?php echo $i ?></strong>
|
||||
<?php else: ?>
|
||||
<a href="<?php echo $page->url($i) ?>"><?php echo $i ?></a>
|
||||
<?php endif ?>
|
||||
|
||||
<?php endfor ?>
|
||||
|
||||
<?php if ($next_page !== FALSE): ?>
|
||||
<a href="<?php echo $page->url($next_page) ?>" rel="next"><?php echo __('Next') ?></a>
|
||||
<?php else: ?>
|
||||
<?php echo __('Next') ?>
|
||||
<?php endif ?>
|
||||
|
||||
<?php if ($last_page !== FALSE): ?>
|
||||
<a href="<?php echo $page->url($last_page) ?>" rel="last"><?php echo __('Last') ?></a>
|
||||
<?php else: ?>
|
||||
<?php echo __('Last') ?>
|
||||
<?php endif ?>
|
||||
|
||||
</p><!-- .pagination -->
|
||||
|
||||
Wow, look at all that logic in there! How do you plan on effectively maintaining that?!?
|
||||
|
||||
### Our new View Class (classes/view/pagination/basic.php)
|
||||
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
|
||||
class View_Pagination_Basic extends kostache {
|
||||
|
||||
protected $pagination;
|
||||
|
||||
protected function items()
|
||||
{
|
||||
$items = array();
|
||||
|
||||
// First.
|
||||
$first['title'] = 'first';
|
||||
$first['name'] = __('first');
|
||||
$first['url'] = ($this->pagination->first_page !== FALSE) ? $this->pagination->url($this->pagination->first_page) : FALSE;
|
||||
$items[] = $first;
|
||||
|
||||
// Prev.
|
||||
$prev['title'] = 'prev';
|
||||
$prev['name'] = __('previous');
|
||||
$prev['url'] = ($this->pagination->previous_page !== FALSE) ? $this->pagination->url($this->pagination->previous_page) : FALSE;
|
||||
$items[] = $prev;
|
||||
|
||||
// Numbers.
|
||||
for ($i=1; $i<=$this->pagination->total_pages; $i++)
|
||||
{
|
||||
$item = array();
|
||||
|
||||
$item['num'] = TRUE;
|
||||
$item['name'] = $i;
|
||||
$item['url'] = ($i != $this->pagination->current_page) ? $this->pagination->url($i) : FALSE;
|
||||
|
||||
$items[] = $item;
|
||||
}
|
||||
|
||||
// Next.
|
||||
$next['title'] = 'next';
|
||||
$next['name'] = __('next');
|
||||
$next['url'] = ($this->pagination->next_page !== FALSE) ? $this->pagination->url($this->pagination->next_page) : FALSE;
|
||||
$items[] = $next;
|
||||
|
||||
// Last.
|
||||
$last['title'] = 'last';
|
||||
$last['name'] = __('last');
|
||||
$last['url'] = ($this->pagination->last_page !== FALSE) ? $this->pagination->url($this->pagination->last_page) : FALSE;
|
||||
$items[] = $last;
|
||||
|
||||
return $items;
|
||||
}
|
||||
public function testing()
|
||||
{
|
||||
return 'foobar';
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Yum, logic in a class, where it belongs :)
|
||||
And create a mustache renderer. The parameter to the engine method is the template name to use.
|
||||
|
||||
### Our mustache template (templates/pagination/basic.mustache)
|
||||
```php
|
||||
<?php
|
||||
|
||||
<p class="pagination">
|
||||
{{#items}}
|
||||
{{#url}}<a href="{{url}}" {{#title}}rel="{{rel}}"{{/title}}>{{/url}}
|
||||
{{#num}}<strong>{{/num}}{{name}}{{#num}}</strong>{{/num}}
|
||||
{{#url}}</a>{{/url}}
|
||||
{{/items}}
|
||||
</p>
|
||||
$renderer = Kostache::factory();
|
||||
```
|
||||
|
||||
Holy cow, that's more maintainable :)
|
||||
And render it:
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
$this->response->body($renderer->render(new View_Test));
|
||||
```
|
||||
|
||||
## Templates
|
||||
|
||||
Templates should go in the `templates/` directory in your cascading file system. They should have a .mustache extension.
|
||||
|
||||
## Partials
|
||||
|
||||
To use a partial in your template you use the greater than sign (>) and the name, e.g. {{>header}}.
|
||||
Partials are loaded automatically based on the name used in the template. So if you reference `{{>foobar}}` in your template, it will look for that partial in `templates/partials/foobar.mustache`.
|
||||
|
||||
You must define partials within the $_partials array in your view class. The key is the name that you use in your template and the value is a path to your partial file.
|
||||
# Layouts
|
||||
|
||||
protected $_partials = array(
|
||||
'header' => 'header', // Loads templates/header.mustache
|
||||
'footer' => 'footer/default', // Loads templates/footer/default.mustache
|
||||
);
|
||||
KOstache supports layouts. To use, just add a `templates/layout.mustache` file (a simple one is already provided), and use `Kostache_Layout` for your renderer instead of `Kostache`. You'll probably want to put a `$title` property in your view class. The layout should include a `{{>content}}` partial to render the body of the page.
|
||||
|
||||
## Using the Kostache_Layout class
|
||||
|
||||
Kostache comes with a Kostache_Layout class instead of a template controller. This allows your layouts to be more OOP and self contained, and they do not rely on your controllers so much.
|
||||
|
||||
To use it, have your view extend the Kostache_Layout class. You can then specify your own layout file by placing it in templates/layout.mustache. At a minimum, it needs to have a {{>content}} partial defined in it.
|
||||
|
||||
If you have a view that extends the Kostache_Layout class, but wish to render only the template and not the entire layout, you can set the public $render_layout property to FALSE. This is useful if you want to use the same view class for external requests and HMVC requests.
|
||||
|
||||
$view = new View_Post_List;
|
||||
if ($this->request !== Request::instance) // Is internal request
|
||||
{
|
||||
$view->render_layout = FALSE;
|
||||
}
|
||||
# Additional Information
|
||||
|
||||
For specific usage and documentation, see:
|
||||
|
||||
[PHP Mustache](http://github.com/bobthecow/mustache.php)
|
||||
|
||||
[Original Mustache](http://defunkt.github.com/mustache/)
|
||||
[Original Mustache](http://defunkt.github.com/mustache/)
|
||||
|
|
|
@ -5,267 +5,46 @@
|
|||
* @package Kostache
|
||||
* @category Base
|
||||
* @author Jeremy Bush <jeremy.bush@kohanaframework.org>
|
||||
* @author Woody Gilk <woody.gilk@kohanaframework.org>
|
||||
* @copyright (c) 2010-2012 Jeremy Bush
|
||||
* @copyright (c) 2011-2012 Woody Gilk
|
||||
* @license MIT
|
||||
*/
|
||||
abstract class Kohana_Kostache {
|
||||
class Kohana_Kostache {
|
||||
|
||||
const VERSION = '3.0.0';
|
||||
const VERSION = '4.0.0';
|
||||
|
||||
/**
|
||||
* Factory method for Kostache views. Accepts a template path and an
|
||||
* optional array of partial paths.
|
||||
*
|
||||
* @param string template path
|
||||
* @param array partial paths
|
||||
* @return Kostache
|
||||
* @throws Kohana_Exception if the view class does not exist
|
||||
*/
|
||||
public static function factory($path, array $partials = NULL)
|
||||
protected $_engine;
|
||||
|
||||
public static function factory()
|
||||
{
|
||||
$class = 'View_'.str_replace('/', '_', $path);
|
||||
$m = new Mustache_Engine(
|
||||
array(
|
||||
'loader' => new Mustache_Loader_Kohana(),
|
||||
'partials_loader' => new Mustache_Loader_Kohana('templates/partials'),
|
||||
'escape' => function($value) {
|
||||
return html::chars($value);
|
||||
},
|
||||
'cache' => APPPATH.'cache/mustache',
|
||||
)
|
||||
);
|
||||
|
||||
if ( ! class_exists($class))
|
||||
{
|
||||
throw new Kohana_Exception('View class does not exist: :class', array(
|
||||
':class' => $class,
|
||||
));
|
||||
}
|
||||
|
||||
return new $class(NULL, $partials);
|
||||
$class = get_called_class();
|
||||
return new $class($m);
|
||||
}
|
||||
|
||||
/**
|
||||
* @var string Mustache template
|
||||
*/
|
||||
protected $_template;
|
||||
|
||||
/**
|
||||
* @var array Mustache partials
|
||||
*/
|
||||
protected $_partials = array();
|
||||
|
||||
/**
|
||||
* Loads the template and partial paths.
|
||||
*
|
||||
* @param string template path
|
||||
* @param array partial paths
|
||||
* @return void
|
||||
* @uses Kostache::template
|
||||
* @uses Kostache::partial
|
||||
*/
|
||||
public function __construct($template = NULL, array $partials = NULL)
|
||||
public function __construct($engine)
|
||||
{
|
||||
if ( ! $template)
|
||||
{
|
||||
if ($this->_template)
|
||||
{
|
||||
// Load the template defined in the view
|
||||
$template = $this->_template;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Detect the template for this class
|
||||
$template = $this->_detect_template();
|
||||
}
|
||||
}
|
||||
|
||||
// Load the template
|
||||
$this->template($template);
|
||||
|
||||
if ($this->_partials)
|
||||
{
|
||||
foreach ($this->_partials as $name => $path)
|
||||
{
|
||||
// Load the partials defined in the view
|
||||
$this->partial($name, $path);
|
||||
}
|
||||
}
|
||||
|
||||
if ($partials)
|
||||
{
|
||||
foreach ($partials as $name => $path)
|
||||
{
|
||||
// Load the partial
|
||||
$this->partial($name, $path);
|
||||
}
|
||||
}
|
||||
$this->_engine = $engine;
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic method, returns the output of [Kostache::render].
|
||||
*
|
||||
* @return string
|
||||
* @uses Kostache::render
|
||||
*/
|
||||
public function __toString()
|
||||
public function render($class, $template = NULL)
|
||||
{
|
||||
try
|
||||
if ($template == NULL)
|
||||
{
|
||||
return $this->render();
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
ob_start();
|
||||
|
||||
// Render the exception
|
||||
Kohana_Exception::handler($e);
|
||||
|
||||
return (string) ob_get_clean();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a new template from a path.
|
||||
*
|
||||
* @return Kostache
|
||||
*/
|
||||
public function template($path)
|
||||
{
|
||||
$this->_template = $this->_load($path);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a new partial from a path. If the path is empty, the partial will
|
||||
* be removed.
|
||||
*
|
||||
* @param string partial name
|
||||
* @param mixed partial path, FALSE to remove the partial
|
||||
* @return Kostache
|
||||
*/
|
||||
public function partial($name, $path)
|
||||
{
|
||||
if ( ! $path)
|
||||
{
|
||||
unset($this->_partials[$name]);
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->_partials[$name] = $this->_load($path);
|
||||
$template = explode('_', get_class($class));
|
||||
array_shift($template);
|
||||
$template = implode('/', $template);
|
||||
}
|
||||
|
||||
return $this;
|
||||
return $this->_engine->loadTemplate($template)->render($class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns a variable by name.
|
||||
*
|
||||
* // This value can be accessed as {{foo}} within the template
|
||||
* $view->set('foo', 'my value');
|
||||
*
|
||||
* You can also use an array to set several values at once:
|
||||
*
|
||||
* // Create the values {{food}} and {{beverage}} in the template
|
||||
* $view->set(array('food' => 'bread', 'beverage' => 'water'));
|
||||
*
|
||||
* @param string variable name or an array of variables
|
||||
* @param mixed value
|
||||
* @return $this
|
||||
*/
|
||||
public function set($key, $value = NULL)
|
||||
{
|
||||
if (is_array($key))
|
||||
{
|
||||
foreach ($key as $name => $value)
|
||||
{
|
||||
$this->{$name} = $value;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->{$key} = $value;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns a value by reference. The benefit of binding is that values can
|
||||
* be altered without re-setting them. It is also possible to bind variables
|
||||
* before they have values. Assigned values will be available as a
|
||||
* variable within the template file:
|
||||
*
|
||||
* // This reference can be accessed as {{ref}} within the template
|
||||
* $view->bind('ref', $bar);
|
||||
*
|
||||
* @param string variable name
|
||||
* @param mixed referenced variable
|
||||
* @return $this
|
||||
*/
|
||||
public function bind($key, & $value)
|
||||
{
|
||||
$this->{$key} =& $value;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the template using the current view.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function render()
|
||||
{
|
||||
return $this->_stash($this->_template, $this, $this->_partials)->render();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new Mustache for the given template, view, and partials.
|
||||
*
|
||||
* @param string template
|
||||
* @param Kostache view object
|
||||
* @param array partial templates
|
||||
* @return Mustache
|
||||
*/
|
||||
protected function _stash($template, Kostache $view, array $partials)
|
||||
{
|
||||
return new Kohana_Mustache($template, $view, $partials, array(
|
||||
'charset' => Kohana::$charset,
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a template and return it.
|
||||
*
|
||||
* @param string template path
|
||||
* @return string
|
||||
* @throws Kohana_Exception if the template does not exist
|
||||
*/
|
||||
protected function _load($path)
|
||||
{
|
||||
$file = Kohana::find_file('templates', $path, 'mustache');
|
||||
|
||||
if ( ! $file)
|
||||
{
|
||||
throw new Kohana_Exception('Template file does not exist: :path', array(
|
||||
':path' => 'templates/'.$path,
|
||||
));
|
||||
}
|
||||
|
||||
return file_get_contents($file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect the template name from the class name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function _detect_template()
|
||||
{
|
||||
// Start creating the template path from the class name
|
||||
$template = explode('_', get_class($this));
|
||||
|
||||
// Remove "View" prefix
|
||||
array_shift($template);
|
||||
|
||||
// Convert name parts into a path
|
||||
$template = strtolower(implode('/', $template));
|
||||
|
||||
return $template;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -5,42 +5,42 @@
|
|||
* @package Kostache
|
||||
* @category Base
|
||||
* @author Jeremy Bush <jeremy.bush@kohanaframework.org>
|
||||
* @author Woody Gilk <woody.gilk@kohanaframework.org>
|
||||
* @copyright (c) 2010-2012 Jeremy Bush
|
||||
* @copyright (c) 2011-2012 Woody Gilk
|
||||
* @license MIT
|
||||
*/
|
||||
abstract class Kohana_Kostache_Layout extends Kostache {
|
||||
class Kohana_Kostache_Layout extends Kohana_Kostache {
|
||||
|
||||
/**
|
||||
* @var string partial name for content
|
||||
*/
|
||||
const CONTENT_PARTIAL = 'content';
|
||||
|
||||
/**
|
||||
* @var boolean render template in layout?
|
||||
*/
|
||||
public $render_layout = TRUE;
|
||||
|
||||
/**
|
||||
* @var string layout path
|
||||
*/
|
||||
protected $_layout = 'layout';
|
||||
|
||||
public function render()
|
||||
public static function factory($layout = 'layout')
|
||||
{
|
||||
if ( ! $this->render_layout)
|
||||
{
|
||||
return parent::render();
|
||||
}
|
||||
$k = parent::factory();
|
||||
$k->set_layout($layout);
|
||||
return $k;
|
||||
}
|
||||
|
||||
$partials = $this->_partials;
|
||||
public function set_layout($layout)
|
||||
{
|
||||
$this->_layout = (string) $layout;
|
||||
}
|
||||
|
||||
$partials[Kostache_Layout::CONTENT_PARTIAL] = $this->_template;
|
||||
public function render($class, $template = NULL)
|
||||
{
|
||||
$this->_engine->setPartials(
|
||||
array(
|
||||
Kostache_Layout::CONTENT_PARTIAL => parent::render($class, $template)
|
||||
)
|
||||
);
|
||||
|
||||
$template = $this->_load($this->_layout);
|
||||
|
||||
return $this->_stash($template, $this, $partials)->render();
|
||||
return $this->_engine->loadTemplate($this->_layout)->render($class);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
|
||||
abstract class Kostache extends Kohana_Kostache { }
|
||||
class Kostache extends Kohana_Kostache { }
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
|
||||
abstract class Kostache_Layout extends Kohana_Kostache_Layout { }
|
||||
class Kostache_Layout extends Kohana_Kostache_Layout { }
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
<?php
|
||||
|
||||
class Mustache_Loader_Kohana implements Mustache_Loader, Mustache_Loader_MutableLoader
|
||||
{
|
||||
private $_base_dir = 'templates';
|
||||
private $_extension = 'mustache';
|
||||
private $_templates = array();
|
||||
|
||||
public function __construct($base_dir = NULL, $options = array())
|
||||
{
|
||||
if ($base_dir)
|
||||
$this->_base_dir = $base_dir;
|
||||
|
||||
if (isset($options['extension']))
|
||||
{
|
||||
$this->_extension = '.' . ltrim($options['extension'], '.');
|
||||
}
|
||||
}
|
||||
|
||||
public function load($name)
|
||||
{
|
||||
if (!isset($this->_templates[$name]))
|
||||
{
|
||||
$this->_templates[$name] = $this->_load_file($name);
|
||||
}
|
||||
|
||||
return $this->_templates[$name];
|
||||
}
|
||||
|
||||
protected function _load_file($name)
|
||||
{
|
||||
$filename = Kohana::find_file($this->_base_dir, $name, $this->_extension);
|
||||
return file_get_contents($filename);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set an associative array of Template sources for this loader.
|
||||
*
|
||||
* @param array $templates
|
||||
*/
|
||||
public function setTemplates(array $templates)
|
||||
{
|
||||
$this->_templates = array_merge($this->_templates, $templates);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a Template source by name.
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $template Mustache Template source
|
||||
*/
|
||||
public function setTemplate($name, $template)
|
||||
{
|
||||
$this->_templates[$name] = $template;
|
||||
}
|
||||
}
|
3
init.php
3
init.php
|
@ -1,4 +1,5 @@
|
|||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
|
||||
// Load Mustache for PHP
|
||||
include Kohana::find_file('vendor', 'mustache/Mustache');
|
||||
include Kohana::find_file('vendor', 'mustache/src/Mustache/Autoloader');
|
||||
Mustache_Autoloader::register();
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit cd6bfaefd30e13082780b3711c2aa4b92d146b1e
|
||||
Subproject commit d99be3444e5b2f0fb605941d7e692d3b5159360c
|
Loading…
Reference in New Issue