mirror of
https://github.com/Mibew/handlebars.php.git
synced 2024-11-15 08:44:12 +03:00
Merge pull request #1 from XaminProject/master
Make the fork up to date with the main repo
This commit is contained in:
commit
c952ebb65f
3
.gitignore
vendored
3
.gitignore
vendored
@ -5,3 +5,6 @@ composer.phar
|
||||
composer.lock
|
||||
*.iml
|
||||
.idea
|
||||
GPATH
|
||||
GRTAGS
|
||||
GTAGS
|
||||
|
@ -4,6 +4,7 @@ php:
|
||||
- 5.4
|
||||
- 5.5
|
||||
- 5.6
|
||||
- 7.0
|
||||
- hhvm
|
||||
branches:
|
||||
except:
|
||||
|
@ -142,7 +142,12 @@ class Arguments
|
||||
// Remove found argument from arguments string.
|
||||
$current_str = ltrim(substr($current_str, strlen($matches[0])));
|
||||
} else {
|
||||
throw new \InvalidArgumentException('Malformed arguments string');
|
||||
throw new \InvalidArgumentException(
|
||||
sprintf(
|
||||
'Malformed arguments string: "%s"',
|
||||
$args_string
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -150,26 +155,26 @@ class Arguments
|
||||
/**
|
||||
* Prepares argument's value to add to arguments list.
|
||||
*
|
||||
* The method unescapes value and wrap it into \Handlebars\String class if
|
||||
* needed.
|
||||
* The method unescapes value and wrap it into \Handlebars\StringWrapper
|
||||
* class if needed.
|
||||
*
|
||||
* @param string $value Argument's value
|
||||
*
|
||||
* @return string|\Handlebars\String
|
||||
* @return string|\Handlebars\StringWrapper
|
||||
*/
|
||||
protected function prepareArgumentValue($value)
|
||||
{
|
||||
// Check if argument's value is a quoted string literal
|
||||
if ($value[0] == "'" || $value[0] == '"') {
|
||||
// Remove enclosing quotes and unescape
|
||||
return new String(stripcslashes(substr($value, 1, -1)));
|
||||
return new StringWrapper(stripcslashes(substr($value, 1, -1)));
|
||||
}
|
||||
|
||||
// Check if the value is an integer literal
|
||||
if (preg_match("/^-?\d+$/", $value)) {
|
||||
// Wrap the value into the String class to tell the Context that
|
||||
// it's a value and not a variable name.
|
||||
return new String($value);
|
||||
return new StringWrapper($value);
|
||||
}
|
||||
|
||||
return $value;
|
||||
|
@ -9,6 +9,7 @@
|
||||
* @package Handlebars
|
||||
* @author fzerorubigd <fzerorubigd@gmail.com>
|
||||
* @author Behrooz Shabani <everplays@gmail.com>
|
||||
* @author Mária Šormanová <maria.sormanova@gmail.com>
|
||||
* @copyright 2012 (c) ParsPooyesh Co
|
||||
* @copyright 2013 (c) Behrooz Shabani
|
||||
* @license MIT <http://opensource.org/licenses/MIT>
|
||||
@ -46,14 +47,17 @@ interface Cache
|
||||
public function get($name);
|
||||
|
||||
/**
|
||||
* Set a cache
|
||||
* Set a cache with $ttl, if present
|
||||
* If $ttl set to -1, the cache expires immediately
|
||||
* If $ttl set to 0 (default), cache is never purged
|
||||
*
|
||||
* @param string $name cache id
|
||||
* @param mixed $value data to store
|
||||
* @param int $ttl time to live in seconds
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function set($name, $value);
|
||||
public function set($name, $value, $ttl = 0);
|
||||
|
||||
/**
|
||||
* Remove cache
|
||||
|
@ -9,6 +9,7 @@
|
||||
* @package Handlebars
|
||||
* @author Joey Baker <joey@byjoeybaker.com>
|
||||
* @author Behrooz Shabani <everplays@gmail.com>
|
||||
* @author Mária Šormanová <maria.sormanova@gmail.com>
|
||||
* @copyright 2013 (c) Meraki, LLP
|
||||
* @copyright 2013 (c) Behrooz Shabani
|
||||
* @license MIT <http://opensource.org/licenses/MIT>
|
||||
@ -20,7 +21,7 @@ namespace Handlebars\Cache;
|
||||
use Handlebars\Cache;
|
||||
|
||||
/**
|
||||
* A dummy array cache
|
||||
* A APC cache
|
||||
*
|
||||
* @category Xamin
|
||||
* @package Handlebars
|
||||
@ -35,31 +36,51 @@ class APC implements Cache
|
||||
{
|
||||
|
||||
/**
|
||||
* Get cache for $name if exist.
|
||||
*
|
||||
* @param string $name Cache id
|
||||
*
|
||||
* @return mixed data on hit, boolean false on cache not found
|
||||
* @var string
|
||||
*/
|
||||
public function get($name)
|
||||
private $_prefix;
|
||||
|
||||
/**
|
||||
* Construct the APC cache.
|
||||
*
|
||||
* @param string|null $prefix optional key prefix, defaults to null
|
||||
*/
|
||||
public function __construct( $prefix = null )
|
||||
{
|
||||
if (apc_exists($name)) {
|
||||
return apc_fetch($name);
|
||||
}
|
||||
return false;
|
||||
$this->_prefix = (string)$prefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a cache
|
||||
* Get cache for $name if exist
|
||||
* and if the cache is not older than defined TTL.
|
||||
*
|
||||
* @param string $name Cache id
|
||||
*
|
||||
* @return mixed data on hit, boolean false on cache not found/expired
|
||||
*/
|
||||
public function get($name)
|
||||
{
|
||||
$success = null;
|
||||
$result = apc_fetch($this->_getKey($name), $success);
|
||||
|
||||
return $success ? $result : false;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a cache with $ttl, if present
|
||||
* If $ttl set to -1, the cache expires immediately
|
||||
* If $ttl set to 0 (default), cache is never purged
|
||||
*
|
||||
* @param string $name cache id
|
||||
* @param mixed $value data to store
|
||||
* @param int $ttl time to live in seconds
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function set($name, $value)
|
||||
public function set($name, $value, $ttl = 0)
|
||||
{
|
||||
apc_store($name, $value);
|
||||
apc_store($this->_getKey($name), $value, $ttl);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -71,7 +92,19 @@ class APC implements Cache
|
||||
*/
|
||||
public function remove($name)
|
||||
{
|
||||
apc_delete($name);
|
||||
apc_delete($this->_getKey($name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the full cache key for a given cache item's
|
||||
*
|
||||
* @param string $name Name of the cache item
|
||||
*
|
||||
* @return string full cache key of cached item
|
||||
*/
|
||||
private function _getKey($name)
|
||||
{
|
||||
return $this->_prefix . ':' . $name;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -9,6 +9,7 @@
|
||||
* @package Handlebars
|
||||
* @author Alex Soncodi <alex@brokerloop.com>
|
||||
* @author Behrooz Shabani <everplays@gmail.com>
|
||||
* @author Mária Šormanová <maria.sormanova@gmail.com>
|
||||
* @copyright 2013 (c) Brokerloop, Inc.
|
||||
* @copyright 2013 (c) Behrooz Shabani
|
||||
* @license MIT <http://opensource.org/licenses/MIT>
|
||||
@ -25,6 +26,7 @@ use Handlebars\Cache;
|
||||
* @category Xamin
|
||||
* @package Handlebars
|
||||
* @author Alex Soncodi <alex@brokerloop.com>
|
||||
* @author Mária Šormanová <maria.sormanova@gmail.com>
|
||||
* @copyright 2013 (c) Brokerloop, Inc.
|
||||
* @license MIT <http://opensource.org/licenses/MIT>
|
||||
* @version Release: @package_version@
|
||||
@ -81,33 +83,49 @@ class Disk implements Cache
|
||||
}
|
||||
|
||||
/**
|
||||
* Get cache for $name if it exists.
|
||||
* Get cache for $name if it exists
|
||||
* and if the cache is not older than defined TTL.
|
||||
*
|
||||
* @param string $name Cache id
|
||||
*
|
||||
* @return mixed data on hit, boolean false on cache not found
|
||||
* @return mixed data on hit, boolean false on cache not found/expired
|
||||
*/
|
||||
public function get($name)
|
||||
{
|
||||
$path = $this->_getPath($name);
|
||||
|
||||
return (file_exists($path)) ?
|
||||
unserialize(file_get_contents($path)) : false;
|
||||
$output = false;
|
||||
if (file_exists($path)) {
|
||||
$file = fopen($path, "r");
|
||||
$ttl = fgets($file);
|
||||
$ctime = filectime($path);
|
||||
$time = time();
|
||||
if ($ttl == -1 || ($ttl > 0 && $time - $ctime > $ttl)) {
|
||||
unlink($path);
|
||||
} else {
|
||||
$serialized_data = fread($file, filesize($path));
|
||||
$output = unserialize($serialized_data);
|
||||
}
|
||||
fclose($file);
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a cache
|
||||
* Set a cache with $ttl, if present
|
||||
* If $ttl set to -1, the cache expires immediately
|
||||
* If $ttl set to 0 (default), cache is never purged
|
||||
*
|
||||
* @param string $name cache id
|
||||
* @param mixed $value data to store
|
||||
* @param int $ttl time to live in seconds
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function set($name, $value)
|
||||
public function set($name, $value, $ttl = 0)
|
||||
{
|
||||
$path = $this->_getPath($name);
|
||||
|
||||
file_put_contents($path, serialize($value));
|
||||
file_put_contents($path, $ttl.PHP_EOL.serialize($value));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -9,6 +9,7 @@
|
||||
* @package Handlebars
|
||||
* @author fzerorubigd <fzerorubigd@gmail.com>
|
||||
* @author Behrooz Shabani <everplays@gmail.com>
|
||||
* @author Mária Šormanová <maria.sormanova@gmail.com>
|
||||
* @copyright 2012 (c) ParsPooyesh Co
|
||||
* @copyright 2013 (c) Behrooz Shabani
|
||||
* @license MIT <http://opensource.org/licenses/MIT>
|
||||
@ -55,10 +56,14 @@ class Dummy implements Cache
|
||||
*
|
||||
* @param string $name cache id
|
||||
* @param mixed $value data to store
|
||||
* @param int $ttl time to live in seconds
|
||||
*
|
||||
* $ttl is ignored since the cache is implemented
|
||||
* by an array and lives only inside one request
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function set($name, $value)
|
||||
public function set($name, $value, $ttl = 0)
|
||||
{
|
||||
$this->_cache[$name] = $value;
|
||||
}
|
||||
|
89
src/Handlebars/ChildContext.php
Normal file
89
src/Handlebars/ChildContext.php
Normal file
@ -0,0 +1,89 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of Handlebars-php
|
||||
* Base on mustache-php https://github.com/bobthecow/mustache.php
|
||||
*
|
||||
* PHP version 5.3
|
||||
*
|
||||
* @category Xamin
|
||||
* @package Handlebars
|
||||
* @author fzerorubigd <fzerorubigd@gmail.com>
|
||||
* @author Behrooz Shabani <everplays@gmail.com>
|
||||
* @author Chris Gray <chris.w.gray@gmail.com>
|
||||
* @author Ulrik Lystbaek <ulrik@bettertaste.dk>
|
||||
* @author Dmitriy Simushev <simushevds@gmail.com>
|
||||
* @author Christian Blanquera <cblanquera@openovate.com>
|
||||
* @copyright 2010-2012 (c) Justin Hileman
|
||||
* @copyright 2012 (c) ParsPooyesh Co
|
||||
* @copyright 2013 (c) Behrooz Shabani
|
||||
* @copyright 2013 (c) f0ruD A
|
||||
* @license MIT <http://opensource.org/licenses/MIT>
|
||||
* @version GIT: $Id$
|
||||
* @link http://xamin.ir
|
||||
*/
|
||||
|
||||
namespace Handlebars;
|
||||
|
||||
/**
|
||||
* Handlebars context
|
||||
* Context for a template
|
||||
*
|
||||
* @category Xamin
|
||||
* @package Handlebars
|
||||
* @author fzerorubigd <fzerorubigd@gmail.com>
|
||||
* @author Behrooz Shabani <everplays@gmail.com>
|
||||
* @copyright 2010-2012 (c) Justin Hileman
|
||||
* @copyright 2012 (c) ParsPooyesh Co
|
||||
* @license MIT <http://opensource.org/licenses/MIT>
|
||||
* @version Release: @package_version@
|
||||
* @link http://xamin.ir
|
||||
*/
|
||||
|
||||
class ChildContext extends Context
|
||||
{
|
||||
protected $parentContext = null;
|
||||
|
||||
/**
|
||||
* Sets a parent context in which
|
||||
* we will case for the ../ in get()
|
||||
*
|
||||
* @param Context $parent parent context
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setParent(Context $parent)
|
||||
{
|
||||
$this->parentContext = $parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a available from current context
|
||||
* Supported types :
|
||||
* variable , ../variable , variable.variable , variable.[variable] , .
|
||||
*
|
||||
* @param string $variableName variable name to get from current context
|
||||
* @param boolean $strict strict search? if not found then throw exception
|
||||
*
|
||||
* @throws \InvalidArgumentException in strict mode and variable not found
|
||||
* @throws \RuntimeException if supplied argument is a malformed quoted string
|
||||
* @throws \InvalidArgumentException if variable name is invalid
|
||||
* @return mixed
|
||||
*/
|
||||
public function get($variableName, $strict = false)
|
||||
{
|
||||
//if the variable name starts with a ../
|
||||
//and we have a parent
|
||||
if (strpos($variableName, '../') === 0
|
||||
&& $this->parentContext instanceof Context
|
||||
) {
|
||||
//just remove the first ../
|
||||
$variableName = substr($variableName, 3);
|
||||
|
||||
//and let the parent context handle the rest
|
||||
return $this->parentContext->get($variableName, $strict);
|
||||
}
|
||||
|
||||
//otherwise, it's business as usual
|
||||
return parent::get($variableName, $strict);
|
||||
}
|
||||
}
|
@ -40,7 +40,6 @@ namespace Handlebars;
|
||||
|
||||
class Context
|
||||
{
|
||||
|
||||
/**
|
||||
* List of charcters that cannot be used in identifiers.
|
||||
*/
|
||||
@ -53,22 +52,30 @@ class Context
|
||||
const NOT_VALID_SEGMENT_NAME_CHARS = "]";
|
||||
|
||||
/**
|
||||
* Context stack
|
||||
*
|
||||
* @var array stack for context only top stack is available
|
||||
*/
|
||||
protected $stack = array();
|
||||
|
||||
/**
|
||||
* Section stack index
|
||||
*
|
||||
* @var array index stack for sections
|
||||
*/
|
||||
protected $index = array();
|
||||
|
||||
/**
|
||||
* Object stack keys
|
||||
*
|
||||
* @var array key stack for objects
|
||||
*/
|
||||
protected $key = array();
|
||||
|
||||
/**
|
||||
* @var array Special variables stack for sections. Each stack element can
|
||||
* Special variables stack for sections.
|
||||
*
|
||||
* @var array Each stack element can
|
||||
* contain elements with "@index", "@key", "@first" and "@last" keys.
|
||||
*/
|
||||
protected $specialVariables = array();
|
||||
@ -185,7 +192,7 @@ class Context
|
||||
*/
|
||||
public function get($variableName, $strict = false)
|
||||
{
|
||||
if ($variableName instanceof \Handlebars\String) {
|
||||
if ($variableName instanceof \Handlebars\StringWrapper) {
|
||||
return (string)$variableName;
|
||||
}
|
||||
$variableName = trim($variableName);
|
||||
@ -197,7 +204,10 @@ class Context
|
||||
if (count($this->stack) < $level) {
|
||||
if ($strict) {
|
||||
throw new \InvalidArgumentException(
|
||||
'can not find variable in context'
|
||||
sprintf(
|
||||
'Can not find variable in context: "%s"',
|
||||
$variableName
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@ -216,9 +226,13 @@ class Context
|
||||
if (!$variableName) {
|
||||
if ($strict) {
|
||||
throw new \InvalidArgumentException(
|
||||
'can not find variable in context'
|
||||
sprintf(
|
||||
'Can not find variable in context: "%s"',
|
||||
$variableName
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return '';
|
||||
} elseif ($variableName == '.' || $variableName == 'this') {
|
||||
return $current;
|
||||
@ -228,19 +242,27 @@ class Context
|
||||
return $specialVariables[$variableName];
|
||||
} elseif ($strict) {
|
||||
throw new \InvalidArgumentException(
|
||||
'can not find variable in context'
|
||||
sprintf(
|
||||
'Can not find variable in context: "%s"',
|
||||
$variableName
|
||||
)
|
||||
);
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
} else {
|
||||
$chunks = $this->_splitVariableName($variableName);
|
||||
do {
|
||||
$current = current($this->stack);
|
||||
foreach ($chunks as $chunk) {
|
||||
if (is_string($current) and $current == '') {
|
||||
return $current;
|
||||
}
|
||||
$current = $this->_findVariableInContext($current, $chunk, $strict);
|
||||
}
|
||||
prev($this->stack);
|
||||
|
||||
} while ($current === null && current($this->stack) !== false);
|
||||
}
|
||||
return $current;
|
||||
}
|
||||
@ -275,7 +297,12 @@ class Context
|
||||
}
|
||||
|
||||
if ($strict) {
|
||||
throw new \InvalidArgumentException('can not find variable in context');
|
||||
throw new \InvalidArgumentException(
|
||||
sprintf(
|
||||
'Can not find variable in context: "%s"',
|
||||
$inside
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return $value;
|
||||
@ -294,12 +321,27 @@ class Context
|
||||
$bad_chars = preg_quote(self::NOT_VALID_NAME_CHARS, '/');
|
||||
$bad_seg_chars = preg_quote(self::NOT_VALID_SEGMENT_NAME_CHARS, '/');
|
||||
|
||||
$name_pattern = "(?:[^" . $bad_chars . "\s]+)|(?:\[[^" . $bad_seg_chars . "]+\])";
|
||||
$check_pattern = "/^((" . $name_pattern . ")\.)*(" . $name_pattern . ")\.?$/";
|
||||
$name_pattern = "(?:[^"
|
||||
. $bad_chars
|
||||
. "\s]+)|(?:\[[^"
|
||||
. $bad_seg_chars
|
||||
. "]+\])";
|
||||
|
||||
$check_pattern = "/^(("
|
||||
. $name_pattern
|
||||
. ")\.)*("
|
||||
. $name_pattern
|
||||
. ")\.?$/";
|
||||
|
||||
$get_pattern = "/(?:" . $name_pattern . ")/";
|
||||
|
||||
if (!preg_match($check_pattern, $variableName)) {
|
||||
throw new \InvalidArgumentException('variable name is invalid');
|
||||
throw new \InvalidArgumentException(
|
||||
sprintf(
|
||||
'Variable name is invalid: "%s"',
|
||||
$variableName
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
preg_match_all($get_pattern, $variableName, $matches);
|
||||
|
@ -10,6 +10,7 @@
|
||||
* @author fzerorubigd <fzerorubigd@gmail.com>
|
||||
* @author Behrooz Shabani <everplays@gmail.com>
|
||||
* @author Jeff Turcotte <jeff.turcotte@gmail.com>
|
||||
* @author Mária Šormanová <maria.sormanova@gmail.com>
|
||||
* @copyright 2010-2012 (c) Justin Hileman
|
||||
* @copyright 2012 (c) ParsPooyesh Co
|
||||
* @copyright 2013 (c) Behrooz Shabani
|
||||
@ -37,10 +38,10 @@ use Handlebars\Cache\Dummy;
|
||||
class Handlebars
|
||||
{
|
||||
private static $_instance = false;
|
||||
const VERSION = '1.0.0';
|
||||
const VERSION = '1.1.0';
|
||||
|
||||
/**
|
||||
* factory method
|
||||
* Factory method
|
||||
*
|
||||
* @param array $options see __construct's options parameter
|
||||
*
|
||||
@ -56,35 +57,54 @@ class Handlebars
|
||||
}
|
||||
|
||||
/**
|
||||
* Current tokenizer instance
|
||||
*
|
||||
* @var Tokenizer
|
||||
*/
|
||||
private $_tokenizer;
|
||||
|
||||
/**
|
||||
* Current parser instance
|
||||
*
|
||||
* @var Parser
|
||||
*/
|
||||
private $_parser;
|
||||
|
||||
/**
|
||||
* Current helper list
|
||||
*
|
||||
* @var Helpers
|
||||
*/
|
||||
private $_helpers;
|
||||
|
||||
/**
|
||||
* Current loader instance
|
||||
*
|
||||
* @var Loader
|
||||
*/
|
||||
private $_loader;
|
||||
|
||||
/**
|
||||
* Current partial loader instance
|
||||
*
|
||||
* @var Loader
|
||||
*/
|
||||
private $_partialsLoader;
|
||||
|
||||
/**
|
||||
* Current cache instance
|
||||
*
|
||||
* @var Cache
|
||||
*/
|
||||
private $_cache;
|
||||
|
||||
/**
|
||||
* @var int time to live parameter in seconds for the cache usage
|
||||
* default set to 0 which means that entries stay in cache
|
||||
* forever and are never purged
|
||||
*/
|
||||
private $_ttl = 0;
|
||||
|
||||
/**
|
||||
* @var string the class to use for the template
|
||||
*/
|
||||
@ -96,6 +116,8 @@ class Handlebars
|
||||
private $_escape = 'htmlspecialchars';
|
||||
|
||||
/**
|
||||
* Parameters for the escpae method above
|
||||
*
|
||||
* @var array parametes to pass to escape function
|
||||
*/
|
||||
private $_escapeArgs = array(
|
||||
@ -138,6 +160,10 @@ class Handlebars
|
||||
$this->setCache($options['cache']);
|
||||
}
|
||||
|
||||
if (isset($options['ttl'])) {
|
||||
$this->setTtl($options['ttl']);
|
||||
}
|
||||
|
||||
if (isset($options['template_class'])) {
|
||||
$this->setTemplateClass($options['template_class']);
|
||||
}
|
||||
@ -247,6 +273,110 @@ class Handlebars
|
||||
return $this->getHelpers()->has($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new helper.
|
||||
*
|
||||
* @param string $name helper name
|
||||
* @param mixed $helper helper callable
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function registerHelper($name, $helper)
|
||||
{
|
||||
$callback = function ($template, $context, $arg) use ($helper) {
|
||||
$args = $template->parseArguments($arg);
|
||||
$named = $template->parseNamedArguments($arg);
|
||||
|
||||
foreach ($args as $i => $arg) {
|
||||
//if it's literally string
|
||||
if ($arg instanceof BaseString) {
|
||||
//we have no problems here
|
||||
$args[$i] = (string) $arg;
|
||||
continue;
|
||||
}
|
||||
|
||||
//not sure what to do if it's not a string or StringWrapper
|
||||
if (!is_string($arg)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
//it's a variable and we need to figure out the value of it
|
||||
$args[$i] = $context->get($arg);
|
||||
}
|
||||
|
||||
//push the options
|
||||
$args[] = array(
|
||||
//special fields
|
||||
'data' => array(
|
||||
'index' => $context->get('@index'),
|
||||
'key' => $context->get('@key'),
|
||||
'first' => $context->get('@first'),
|
||||
'last' => $context->get('@last')),
|
||||
// Named arguments
|
||||
'hash' => $named,
|
||||
// A renderer for block helper
|
||||
'fn' => function ($inContext = null) use ($context, $template) {
|
||||
$defined = !!$inContext;
|
||||
|
||||
if (!$defined) {
|
||||
$inContext = $context;
|
||||
$inContext->push($inContext->last());
|
||||
} else if (!$inContext instanceof Context) {
|
||||
$inContext = new ChildContext($inContext);
|
||||
$inContext->setParent($context);
|
||||
}
|
||||
|
||||
$template->setStopToken('else');
|
||||
$buffer = $template->render($inContext);
|
||||
$template->setStopToken(false);
|
||||
//what if it's a loop ?
|
||||
$template->rewind();
|
||||
//What's the point of this again?
|
||||
//I mean in this context (literally)
|
||||
//$template->discard($inContext);
|
||||
|
||||
if (!$defined) {
|
||||
$inContext->pop();
|
||||
}
|
||||
|
||||
return $buffer;
|
||||
},
|
||||
|
||||
// A render for the else block
|
||||
'inverse' => function ($inContext = null) use ($context, $template) {
|
||||
$defined = !!$inContext;
|
||||
|
||||
if (!$defined) {
|
||||
$inContext = $context;
|
||||
$inContext->push($inContext->last());
|
||||
} else if (!$inContext instanceof Context) {
|
||||
$inContext = new ChildContext($inContext);
|
||||
$inContext->setParent($context);
|
||||
}
|
||||
|
||||
$template->setStopToken('else');
|
||||
$template->discard($inContext);
|
||||
$template->setStopToken(false);
|
||||
$buffer = $template->render($inContext);
|
||||
|
||||
if (!$defined) {
|
||||
$inContext->pop();
|
||||
}
|
||||
|
||||
return $buffer;
|
||||
},
|
||||
|
||||
// The current context.
|
||||
'context' => $context,
|
||||
// The current template
|
||||
'template' => $template);
|
||||
|
||||
return call_user_func_array($helper, $args);
|
||||
};
|
||||
|
||||
$this->addHelper($name, $callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a helper by name.
|
||||
*
|
||||
@ -272,7 +402,7 @@ class Handlebars
|
||||
}
|
||||
|
||||
/**
|
||||
* get current loader
|
||||
* Get current loader
|
||||
*
|
||||
* @return Loader
|
||||
*/
|
||||
@ -298,7 +428,7 @@ class Handlebars
|
||||
}
|
||||
|
||||
/**
|
||||
* get current partials loader
|
||||
* Get current partials loader
|
||||
*
|
||||
* @return Loader
|
||||
*/
|
||||
@ -337,6 +467,28 @@ class Handlebars
|
||||
return $this->_cache;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set time to live for the used cache
|
||||
*
|
||||
* @param int $ttl time to live in seconds
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setTtl($ttl)
|
||||
{
|
||||
$this->_ttl = $ttl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get ttl
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getTtl()
|
||||
{
|
||||
return $this->_ttl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current escape function
|
||||
*
|
||||
@ -460,7 +612,10 @@ class Handlebars
|
||||
{
|
||||
if (!is_a($class, 'Handlebars\\Template', true)) {
|
||||
throw new \InvalidArgumentException(
|
||||
'Custom template class must extend Template'
|
||||
sprintf(
|
||||
'Custom template class "%s" must extend Template',
|
||||
$class
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@ -542,7 +697,7 @@ class Handlebars
|
||||
}
|
||||
|
||||
/**
|
||||
* try to tokenize source, or get them from cache if available
|
||||
* Try to tokenize source, or get them from cache if available
|
||||
*
|
||||
* @param string $source handlebars source code
|
||||
*
|
||||
@ -555,7 +710,7 @@ class Handlebars
|
||||
if ($tree === false) {
|
||||
$tokens = $this->getTokenizer()->scan($source);
|
||||
$tree = $this->getParser()->parse($tokens);
|
||||
$this->getCache()->set($hash, $tree);
|
||||
$this->getCache()->set($hash, $tree, $this->_ttl);
|
||||
}
|
||||
|
||||
return $tree;
|
||||
|
@ -33,7 +33,7 @@ interface Helper
|
||||
*
|
||||
* @param \Handlebars\Template $template The template instance
|
||||
* @param \Handlebars\Context $context The current context
|
||||
* @param array $args The arguments passed the the helper
|
||||
* @param \Handlebars\Arguments $args The arguments passed the the helper
|
||||
* @param string $source The source
|
||||
*
|
||||
* @return mixed
|
||||
|
@ -43,7 +43,7 @@ class BindAttrHelper implements Helper
|
||||
*
|
||||
* @param \Handlebars\Template $template The template instance
|
||||
* @param \Handlebars\Context $context The current context
|
||||
* @param array $args The arguments passed the the helper
|
||||
* @param \Handlebars\Arguments $args The arguments passed the the helper
|
||||
* @param string $source The source
|
||||
*
|
||||
* @return mixed
|
||||
|
@ -45,14 +45,15 @@ class EachHelper implements Helper
|
||||
*
|
||||
* @param \Handlebars\Template $template The template instance
|
||||
* @param \Handlebars\Context $context The current context
|
||||
* @param array $args The arguments passed the the helper
|
||||
* @param \Handlebars\Arguments $args The arguments passed the the helper
|
||||
* @param string $source The source
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function execute(Template $template, Context $context, $args, $source)
|
||||
{
|
||||
$tmp = $context->get($args);
|
||||
$positionalArgs = $args->getPositionalArguments();
|
||||
$tmp = $context->get($positionalArgs[0]);
|
||||
$buffer = '';
|
||||
|
||||
if (!$tmp) {
|
||||
|
@ -43,7 +43,7 @@ class IfHelper implements Helper
|
||||
*
|
||||
* @param \Handlebars\Template $template The template instance
|
||||
* @param \Handlebars\Context $context The current context
|
||||
* @param array $args The arguments passed the the helper
|
||||
* @param \Handlebars\Arguments $args The arguments passed the the helper
|
||||
* @param string $source The source
|
||||
*
|
||||
* @return mixed
|
||||
@ -53,7 +53,6 @@ class IfHelper implements Helper
|
||||
$parsedArgs = $template->parseArguments($args);
|
||||
$tmp = $context->get($parsedArgs[0]);
|
||||
|
||||
$context->push($context->last());
|
||||
if ($tmp) {
|
||||
$template->setStopToken('else');
|
||||
$buffer = $template->render($context);
|
||||
@ -65,7 +64,6 @@ class IfHelper implements Helper
|
||||
$template->setStopToken(false);
|
||||
$buffer = $template->render($context);
|
||||
}
|
||||
$context->pop();
|
||||
|
||||
return $buffer;
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ class UnlessHelper implements Helper
|
||||
*
|
||||
* @param \Handlebars\Template $template The template instance
|
||||
* @param \Handlebars\Context $context The current context
|
||||
* @param array $args The arguments passed the the helper
|
||||
* @param \Handlebars\Arguments $args The arguments passed the the helper
|
||||
* @param string $source The source
|
||||
*
|
||||
* @return mixed
|
||||
@ -53,8 +53,6 @@ class UnlessHelper implements Helper
|
||||
$parsedArgs = $template->parseArguments($args);
|
||||
$tmp = $context->get($parsedArgs[0]);
|
||||
|
||||
$context->push($context->last());
|
||||
|
||||
if (!$tmp) {
|
||||
$template->setStopToken('else');
|
||||
$buffer = $template->render($context);
|
||||
@ -66,8 +64,6 @@ class UnlessHelper implements Helper
|
||||
$buffer = $template->render($context);
|
||||
}
|
||||
|
||||
$context->pop();
|
||||
|
||||
return $buffer;
|
||||
}
|
||||
}
|
||||
|
@ -43,14 +43,15 @@ class WithHelper implements Helper
|
||||
*
|
||||
* @param \Handlebars\Template $template The template instance
|
||||
* @param \Handlebars\Context $context The current context
|
||||
* @param array $args The arguments passed the the helper
|
||||
* @param \Handlebars\Arguments $args The arguments passed the the helper
|
||||
* @param string $source The source
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function execute(Template $template, Context $context, $args, $source)
|
||||
{
|
||||
$context->with($args);
|
||||
$positionalArgs = $args->getPositionalArguments();
|
||||
$context->with($positionalArgs[0]);
|
||||
$buffer = $template->render($context);
|
||||
$context->pop();
|
||||
|
||||
|
@ -23,7 +23,7 @@ namespace Handlebars;
|
||||
/**
|
||||
* Handlebars helpers
|
||||
*
|
||||
* a collection of helper function. normally a function like
|
||||
* A collection of helper function. normally a function like
|
||||
* function ($sender, $name, $arguments) $arguments is unscaped arguments and
|
||||
* is a string, not array
|
||||
*
|
||||
@ -35,10 +35,11 @@ namespace Handlebars;
|
||||
* @version Release: @package_version@
|
||||
* @link http://xamin.ir
|
||||
*/
|
||||
|
||||
class Helpers
|
||||
{
|
||||
/**
|
||||
* Raw helper array
|
||||
*
|
||||
* @var array array of helpers
|
||||
*/
|
||||
protected $helpers = array();
|
||||
@ -100,7 +101,10 @@ class Helpers
|
||||
{
|
||||
if (!is_callable($helper) && ! $helper instanceof Helper) {
|
||||
throw new \InvalidArgumentException(
|
||||
"$name Helper is not a callable or doesn't implement the Helper interface."
|
||||
sprintf(
|
||||
"%s Helper is not a callable or doesn't implement the Helper interface.",
|
||||
$name
|
||||
)
|
||||
);
|
||||
}
|
||||
$this->helpers[$name] = $helper;
|
||||
@ -136,16 +140,28 @@ class Helpers
|
||||
public function call($name, Template $template, Context $context, $args, $source)
|
||||
{
|
||||
if (!$this->has($name)) {
|
||||
throw new \InvalidArgumentException('Unknown helper: ' . $name);
|
||||
}
|
||||
|
||||
if ($this->helpers[$name] instanceof Helper) {
|
||||
return $this->helpers[$name]->execute(
|
||||
$template, $context, $args, $source
|
||||
throw new \InvalidArgumentException(
|
||||
sprintf(
|
||||
'Unknown helper: "%s"',
|
||||
$name
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return call_user_func($this->helpers[$name], $template, $context, $args, $source);
|
||||
$parsedArgs = new Arguments($args);
|
||||
if ($this->helpers[$name] instanceof Helper) {
|
||||
return $this->helpers[$name]->execute(
|
||||
$template, $context, $parsedArgs, $source
|
||||
);
|
||||
}
|
||||
|
||||
return call_user_func(
|
||||
$this->helpers[$name],
|
||||
$template,
|
||||
$context,
|
||||
$parsedArgs,
|
||||
$source
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -171,7 +187,12 @@ class Helpers
|
||||
public function __get($name)
|
||||
{
|
||||
if (!$this->has($name)) {
|
||||
throw new \InvalidArgumentException('Unknown helper :' . $name);
|
||||
throw new \InvalidArgumentException(
|
||||
sprintf(
|
||||
'Unknown helper: "%s"',
|
||||
$name
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return $this->helpers[$name];
|
||||
@ -226,7 +247,12 @@ class Helpers
|
||||
public function remove($name)
|
||||
{
|
||||
if (!$this->has($name)) {
|
||||
throw new \InvalidArgumentException('Unknown helper: ' . $name);
|
||||
throw new \InvalidArgumentException(
|
||||
sprintf(
|
||||
'Unknown helper: "%s"',
|
||||
$name
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
unset($this->helpers[$name]);
|
||||
|
98
src/Handlebars/Loader/FilesystemLoader.php
Executable file → Normal file
98
src/Handlebars/Loader/FilesystemLoader.php
Executable file → Normal file
@ -12,6 +12,7 @@
|
||||
* @author Behrooz Shabani <everplays@gmail.com>
|
||||
* @author Craig Bass <craig@clearbooks.co.uk>
|
||||
* @author ^^ <craig@devls.co.uk>
|
||||
* @author Dave Stein <be.davestein@gmail.com>
|
||||
* @copyright 2010-2012 (c) Justin Hileman
|
||||
* @copyright 2012 (c) ParsPooyesh Co
|
||||
* @copyright 2013 (c) Behrooz Shabani
|
||||
@ -23,7 +24,7 @@
|
||||
namespace Handlebars\Loader;
|
||||
|
||||
use Handlebars\Loader;
|
||||
use Handlebars\String;
|
||||
use Handlebars\StringWrapper;
|
||||
|
||||
/**
|
||||
* Handlebars Template filesystem Loader implementation.
|
||||
@ -40,7 +41,7 @@ use Handlebars\String;
|
||||
|
||||
class FilesystemLoader implements Loader
|
||||
{
|
||||
private $_baseDir;
|
||||
protected $baseDir;
|
||||
private $_extension = '.handlebars';
|
||||
private $_prefix = '';
|
||||
private $_templates = array();
|
||||
@ -62,32 +63,8 @@ class FilesystemLoader implements Loader
|
||||
*/
|
||||
public function __construct($baseDirs, array $options = array())
|
||||
{
|
||||
if (is_string($baseDirs)) {
|
||||
$baseDirs = array(rtrim(realpath($baseDirs), '/'));
|
||||
} else {
|
||||
foreach ($baseDirs as &$dir) {
|
||||
$dir = rtrim(realpath($dir), '/');
|
||||
}
|
||||
unset($dir);
|
||||
}
|
||||
|
||||
$this->_baseDir = $baseDirs;
|
||||
|
||||
foreach ($this->_baseDir as $dir) {
|
||||
if (!is_dir($dir)) {
|
||||
throw new \RuntimeException(
|
||||
'FilesystemLoader baseDir must be a directory: ' . $dir
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($options['extension'])) {
|
||||
$this->_extension = '.' . ltrim($options['extension'], '.');
|
||||
}
|
||||
|
||||
if (isset($options['prefix'])) {
|
||||
$this->_prefix = $options['prefix'];
|
||||
}
|
||||
$this->setBaseDir($baseDirs);
|
||||
$this->handleOptions($options);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -99,7 +76,7 @@ class FilesystemLoader implements Loader
|
||||
*
|
||||
* @param string $name template name
|
||||
*
|
||||
* @return String Handlebars Template source
|
||||
* @return StringWrapper Handlebars Template source
|
||||
*/
|
||||
public function load($name)
|
||||
{
|
||||
@ -107,7 +84,66 @@ class FilesystemLoader implements Loader
|
||||
$this->_templates[$name] = $this->loadFile($name);
|
||||
}
|
||||
|
||||
return new String($this->_templates[$name]);
|
||||
return new StringWrapper($this->_templates[$name]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets directories to load templates from
|
||||
*
|
||||
* @param string|array $baseDirs A path contain template files or array of paths
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function setBaseDir($baseDirs)
|
||||
{
|
||||
if (is_string($baseDirs)) {
|
||||
$baseDirs = array($this->sanitizeDirectory($baseDirs));
|
||||
} else {
|
||||
foreach ($baseDirs as &$dir) {
|
||||
$dir = $this->sanitizeDirectory($dir);
|
||||
}
|
||||
unset($dir);
|
||||
}
|
||||
|
||||
foreach ($baseDirs as $dir) {
|
||||
if (!is_dir($dir)) {
|
||||
throw new \RuntimeException(
|
||||
'FilesystemLoader baseDir must be a directory: ' . $dir
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$this->baseDir = $baseDirs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts directory into standardized format
|
||||
*
|
||||
* @param String $dir The directory to sanitize
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
protected function sanitizeDirectory($dir)
|
||||
{
|
||||
return rtrim(realpath($dir), '/');
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets properties based on options
|
||||
*
|
||||
* @param array $options Array of Loader options (default: array())
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handleOptions(array $options = array())
|
||||
{
|
||||
if (isset($options['extension'])) {
|
||||
$this->_extension = '.' . ltrim($options['extension'], '.');
|
||||
}
|
||||
|
||||
if (isset($options['prefix'])) {
|
||||
$this->_prefix = $options['prefix'];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -138,7 +174,7 @@ class FilesystemLoader implements Loader
|
||||
*/
|
||||
protected function getFileName($name)
|
||||
{
|
||||
foreach ($this->_baseDir as $baseDir) {
|
||||
foreach ($this->baseDir as $baseDir) {
|
||||
$fileName = $baseDir . '/';
|
||||
$fileParts = explode('/', $name);
|
||||
$file = array_pop($fileParts);
|
||||
|
@ -75,11 +75,21 @@ class InlineLoader implements Loader
|
||||
public function __construct($fileName, $offset)
|
||||
{
|
||||
if (!is_file($fileName)) {
|
||||
throw new \InvalidArgumentException('InlineLoader expects a valid filename.');
|
||||
throw new \InvalidArgumentException(
|
||||
sprintf(
|
||||
'InlineLoader expects a valid filename, "%s" given.',
|
||||
$fileName
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if (!is_int($offset) || $offset < 0) {
|
||||
throw new \InvalidArgumentException('InlineLoader expects a valid file offset.');
|
||||
throw new \InvalidArgumentException(
|
||||
sprintf(
|
||||
'InlineLoader expects a valid file offset, "%s" given.',
|
||||
$offset
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$this->fileName = $fileName;
|
||||
@ -98,7 +108,7 @@ class InlineLoader implements Loader
|
||||
$this->loadTemplates();
|
||||
|
||||
if (!array_key_exists($name, $this->templates)) {
|
||||
throw new \InvalidArgumentException("Template {$name} not found.");
|
||||
throw new \InvalidArgumentException("Template $name not found.");
|
||||
}
|
||||
|
||||
return $this->templates[$name];
|
||||
|
6
src/Handlebars/Loader/StringLoader.php
Executable file → Normal file
6
src/Handlebars/Loader/StringLoader.php
Executable file → Normal file
@ -19,7 +19,7 @@
|
||||
|
||||
namespace Handlebars\Loader;
|
||||
use Handlebars\Loader;
|
||||
use Handlebars\String;
|
||||
use Handlebars\StringWrapper;
|
||||
|
||||
/**
|
||||
* Handlebars Template string Loader implementation.
|
||||
@ -42,11 +42,11 @@ class StringLoader implements Loader
|
||||
*
|
||||
* @param string $name Handlebars Template source
|
||||
*
|
||||
* @return String Handlebars Template source
|
||||
* @return StringWrapper Handlebars Template source
|
||||
*/
|
||||
public function load($name)
|
||||
{
|
||||
return new String($name);
|
||||
return new StringWrapper($name);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -61,7 +61,6 @@ class Parser
|
||||
* @throws \LogicException when nesting errors or mismatched section tags
|
||||
* are encountered.
|
||||
* @return array Token parse tree
|
||||
*
|
||||
*/
|
||||
private function _buildTree(\ArrayIterator $tokens)
|
||||
{
|
||||
@ -79,22 +78,33 @@ class Parser
|
||||
$result = array_pop($stack);
|
||||
if ($result === null) {
|
||||
throw new \LogicException(
|
||||
'Unexpected closing tag: /' . $token[Tokenizer::NAME]
|
||||
sprintf(
|
||||
'Unexpected closing tag: /%s',
|
||||
$token[Tokenizer::NAME]
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if (!array_key_exists(Tokenizer::NODES, $result)
|
||||
&& isset($result[Tokenizer::NAME])
|
||||
&& ($result[Tokenizer::TYPE] == Tokenizer::T_SECTION
|
||||
|| $result[Tokenizer::TYPE] == Tokenizer::T_INVERTED)
|
||||
&& $result[Tokenizer::NAME] == $token[Tokenizer::NAME]
|
||||
) {
|
||||
if (isset($result[Tokenizer::TRIM_RIGHT]) && $result[Tokenizer::TRIM_RIGHT]) {
|
||||
// If the start node has trim right, then its equal with the first item in the loop with
|
||||
if (isset($result[Tokenizer::TRIM_RIGHT])
|
||||
&& $result[Tokenizer::TRIM_RIGHT]
|
||||
) {
|
||||
// If the start node has trim right, then its equal
|
||||
//with the first item in the loop with
|
||||
// Trim left
|
||||
$newNodes[0][Tokenizer::TRIM_LEFT] = true;
|
||||
}
|
||||
|
||||
if (isset($token[Tokenizer::TRIM_RIGHT]) && $token[Tokenizer::TRIM_RIGHT]) {
|
||||
//OK, if we have trim right here, we should pass it to the upper level.
|
||||
if (isset($token[Tokenizer::TRIM_RIGHT])
|
||||
&& $token[Tokenizer::TRIM_RIGHT]
|
||||
) {
|
||||
//OK, if we have trim right here, we should
|
||||
//pass it to the upper level.
|
||||
$result[Tokenizer::TRIM_RIGHT] = true;
|
||||
}
|
||||
|
||||
|
@ -27,8 +27,9 @@ namespace Handlebars;
|
||||
* @license MIT <http://opensource.org/licenses/MIT>
|
||||
* @version Release: @package_version@
|
||||
* @link http://xamin.ir
|
||||
* @deprecated Since v0.10.3. Use \Handlebars\StringWrapper instead.
|
||||
*/
|
||||
|
||||
class String extends BaseString
|
||||
class String extends StringWrapper
|
||||
{
|
||||
}
|
||||
|
34
src/Handlebars/StringWrapper.php
Normal file
34
src/Handlebars/StringWrapper.php
Normal file
@ -0,0 +1,34 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of Handlebars-php
|
||||
*
|
||||
* PHP version 5.3
|
||||
*
|
||||
* @category Xamin
|
||||
* @package Handlebars
|
||||
* @author fzerorubigd <fzerorubigd@gmail.com>
|
||||
* @author Behrooz Shabani <everplays@gmail.com>
|
||||
* @author Dmitriy Simushev <simushevds@gmail.com>
|
||||
* @copyright 2013 Authors
|
||||
* @license MIT <http://opensource.org/licenses/MIT>
|
||||
* @version GIT: $Id$
|
||||
* @link http://xamin.ir
|
||||
*/
|
||||
|
||||
namespace Handlebars;
|
||||
|
||||
/**
|
||||
* Handlebars string
|
||||
*
|
||||
* @category Xamin
|
||||
* @package Handlebars
|
||||
* @author fzerorubigd <fzerorubigd@gmail.com>
|
||||
* @copyright 2013 Authors
|
||||
* @license MIT <http://opensource.org/licenses/MIT>
|
||||
* @version Release: @package_version@
|
||||
* @link http://xamin.ir
|
||||
*/
|
||||
|
||||
class StringWrapper extends BaseString
|
||||
{
|
||||
}
|
@ -23,6 +23,8 @@
|
||||
*/
|
||||
|
||||
namespace Handlebars;
|
||||
use Handlebars\Arguments;
|
||||
use Traversable;
|
||||
|
||||
/**
|
||||
* Handlebars base template
|
||||
@ -31,6 +33,7 @@ namespace Handlebars;
|
||||
* @category Xamin
|
||||
* @package Handlebars
|
||||
* @author fzerorubigd <fzerorubigd@gmail.com>
|
||||
* @author Pascal Thormeier <pascal.thormeier@gmail.com>
|
||||
* @copyright 2010-2012 (c) Justin Hileman
|
||||
* @copyright 2012 (c) ParsPooyesh Co
|
||||
* @license MIT <http://opensource.org/licenses/MIT>
|
||||
@ -41,6 +44,8 @@ namespace Handlebars;
|
||||
class Template
|
||||
{
|
||||
/**
|
||||
* Handlebars instance
|
||||
*
|
||||
* @var Handlebars
|
||||
*/
|
||||
protected $handlebars;
|
||||
@ -56,9 +61,11 @@ class Template
|
||||
protected $source = '';
|
||||
|
||||
/**
|
||||
* Run stack
|
||||
*
|
||||
* @var array Run stack
|
||||
*/
|
||||
private $_stack = array();
|
||||
protected $stack = array();
|
||||
|
||||
/**
|
||||
* Handlebars template constructor
|
||||
@ -72,7 +79,7 @@ class Template
|
||||
$this->handlebars = $engine;
|
||||
$this->tree = $tree;
|
||||
$this->source = $source;
|
||||
array_push($this->_stack, array(0, $this->getTree(), false));
|
||||
array_push($this->stack, array(0, $this->getTree(), false));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -106,29 +113,27 @@ class Template
|
||||
}
|
||||
|
||||
/**
|
||||
* set stop token for render and discard method
|
||||
* Set stop token for render and discard method
|
||||
*
|
||||
* @param string $token token to set as stop token or false to remove
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
public function setStopToken($token)
|
||||
{
|
||||
$topStack = array_pop($this->_stack);
|
||||
$topStack = array_pop($this->stack);
|
||||
$topStack[2] = $token;
|
||||
array_push($this->_stack, $topStack);
|
||||
array_push($this->stack, $topStack);
|
||||
}
|
||||
|
||||
/**
|
||||
* get current stop token
|
||||
* Get current stop token
|
||||
*
|
||||
* @return string|bool
|
||||
*/
|
||||
|
||||
public function getStopToken()
|
||||
{
|
||||
$topStack = end($this->_stack);
|
||||
$topStack = end($this->stack);
|
||||
|
||||
return $topStack[2];
|
||||
}
|
||||
@ -140,7 +145,7 @@ class Template
|
||||
*/
|
||||
public function getCurrentTokenTree()
|
||||
{
|
||||
$topStack = end($this->_stack);
|
||||
$topStack = end($this->stack);
|
||||
|
||||
return $topStack[1];
|
||||
}
|
||||
@ -158,7 +163,7 @@ class Template
|
||||
if (!$context instanceof Context) {
|
||||
$context = new Context($context);
|
||||
}
|
||||
$topTree = end($this->_stack); // never pop a value from stack
|
||||
$topTree = end($this->stack); // never pop a value from stack
|
||||
list($index, $tree, $stop) = $topTree;
|
||||
|
||||
$buffer = '';
|
||||
@ -173,33 +178,42 @@ class Template
|
||||
) {
|
||||
break;
|
||||
}
|
||||
if (isset($current[Tokenizer::TRIM_LEFT]) && $current[Tokenizer::TRIM_LEFT]) {
|
||||
if (isset($current[Tokenizer::TRIM_LEFT])
|
||||
&& $current[Tokenizer::TRIM_LEFT]
|
||||
) {
|
||||
$buffer = rtrim($buffer);
|
||||
}
|
||||
|
||||
$tmp = $this->_renderInternal($current, $context);
|
||||
$tmp = $this->renderInternal($current, $context);
|
||||
|
||||
if (isset($current[Tokenizer::TRIM_LEFT]) && $current[Tokenizer::TRIM_LEFT]) {
|
||||
if (isset($current[Tokenizer::TRIM_LEFT])
|
||||
&& $current[Tokenizer::TRIM_LEFT]
|
||||
) {
|
||||
$tmp = rtrim($tmp);
|
||||
}
|
||||
|
||||
if ($rTrim || (isset($current[Tokenizer::TRIM_RIGHT]) && $current[Tokenizer::TRIM_RIGHT])) {
|
||||
if ($rTrim
|
||||
|| (isset($current[Tokenizer::TRIM_RIGHT])
|
||||
&& $current[Tokenizer::TRIM_RIGHT])
|
||||
) {
|
||||
$tmp = ltrim($tmp);
|
||||
}
|
||||
|
||||
$buffer .= $tmp;
|
||||
// Some time, there is more than one string token (first is empty),
|
||||
// Some time, there is more than
|
||||
//one string token (first is empty),
|
||||
//so we need to trim all of them in one shot
|
||||
|
||||
$rTrim = (empty($tmp) && $rTrim) ||
|
||||
isset($current[Tokenizer::TRIM_RIGHT]) && $current[Tokenizer::TRIM_RIGHT];
|
||||
isset($current[Tokenizer::TRIM_RIGHT])
|
||||
&& $current[Tokenizer::TRIM_RIGHT];
|
||||
}
|
||||
if ($stop) {
|
||||
//Ok break here, the helper should be aware of this.
|
||||
$newStack = array_pop($this->_stack);
|
||||
$newStack = array_pop($this->stack);
|
||||
$newStack[0] = $index;
|
||||
$newStack[2] = false; //No stop token from now on
|
||||
array_push($this->_stack, $newStack);
|
||||
array_push($this->stack, $newStack);
|
||||
}
|
||||
|
||||
return $buffer;
|
||||
@ -213,7 +227,7 @@ class Template
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function _renderInternal($current, $context)
|
||||
protected function renderInternal($current, $context)
|
||||
{
|
||||
$result = '';
|
||||
switch ($current[Tokenizer::TYPE]) {
|
||||
@ -222,16 +236,16 @@ class Template
|
||||
case Tokenizer::T_SECTION :
|
||||
$newStack = isset($current[Tokenizer::NODES])
|
||||
? $current[Tokenizer::NODES] : array();
|
||||
array_push($this->_stack, array(0, $newStack, false));
|
||||
array_push($this->stack, array(0, $newStack, false));
|
||||
$result = $this->_section($context, $current);
|
||||
array_pop($this->_stack);
|
||||
array_pop($this->stack);
|
||||
break;
|
||||
case Tokenizer::T_INVERTED :
|
||||
$newStack = isset($current[Tokenizer::NODES]) ?
|
||||
$current[Tokenizer::NODES] : array();
|
||||
array_push($this->_stack, array(0, $newStack, false));
|
||||
array_push($this->stack, array(0, $newStack, false));
|
||||
$result = $this->_inverted($context, $current);
|
||||
array_pop($this->_stack);
|
||||
array_pop($this->stack);
|
||||
break;
|
||||
case Tokenizer::T_COMMENT :
|
||||
$result = '';
|
||||
@ -269,7 +283,7 @@ class Template
|
||||
*/
|
||||
public function discard()
|
||||
{
|
||||
$topTree = end($this->_stack); //This method never pop a value from stack
|
||||
$topTree = end($this->stack); //This method never pop a value from stack
|
||||
list($index, $tree, $stop) = $topTree;
|
||||
while (array_key_exists($index, $tree)) {
|
||||
$current = $tree[$index];
|
||||
@ -284,10 +298,10 @@ class Template
|
||||
}
|
||||
if ($stop) {
|
||||
//Ok break here, the helper should be aware of this.
|
||||
$newStack = array_pop($this->_stack);
|
||||
$newStack = array_pop($this->stack);
|
||||
$newStack[0] = $index;
|
||||
$newStack[2] = false;
|
||||
array_push($this->_stack, $newStack);
|
||||
array_push($this->stack, $newStack);
|
||||
}
|
||||
|
||||
return '';
|
||||
@ -300,9 +314,9 @@ class Template
|
||||
*/
|
||||
public function rewind()
|
||||
{
|
||||
$topStack = array_pop($this->_stack);
|
||||
$topStack = array_pop($this->stack);
|
||||
$topStack[0] = 0;
|
||||
array_push($this->_stack, $topStack);
|
||||
array_push($this->stack, $topStack);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -329,7 +343,9 @@ class Template
|
||||
}
|
||||
|
||||
// subexpression parsing loop
|
||||
$subexprs = array(); // will contain all subexpressions inside outermost brackets
|
||||
// will contain all subexpressions
|
||||
// inside outermost brackets
|
||||
$subexprs = array();
|
||||
$insideOf = array( 'single' => false, 'double' => false );
|
||||
$lvl = 0;
|
||||
$cur_start = 0;
|
||||
@ -351,7 +367,11 @@ class Template
|
||||
if ($cur == ')' && ! $insideOf['single'] && ! $insideOf['double']) {
|
||||
$lvl--;
|
||||
if ($lvl == 0) {
|
||||
$subexprs[] = substr($current[Tokenizer::ARGS], $cur_start, $i - $cur_start);
|
||||
$subexprs[] = substr(
|
||||
$current[Tokenizer::ARGS],
|
||||
$cur_start,
|
||||
$i - $cur_start
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
@ -370,16 +390,32 @@ class Template
|
||||
Tokenizer::INDEX => $current[Tokenizer::INDEX],
|
||||
Tokenizer::ARGS => implode(" ", array_slice($cmd, 1))
|
||||
);
|
||||
|
||||
// resolve the node recursively
|
||||
$resolved = addcslashes($this->_handlebarsStyleSection($context, $section_node), '"');
|
||||
$resolved = $this->_handlebarsStyleSection(
|
||||
$context,
|
||||
$section_node
|
||||
);
|
||||
|
||||
$resolved = addcslashes($resolved, '"');
|
||||
// replace original subexpression with result
|
||||
$current[Tokenizer::ARGS] = str_replace('('.$expr.')', '"' . $resolved . '"', $current[Tokenizer::ARGS]);
|
||||
$current[Tokenizer::ARGS] = str_replace(
|
||||
'('.$expr.')',
|
||||
'"' . $resolved . '"',
|
||||
$current[Tokenizer::ARGS]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$return = $helpers->call($sectionName, $this, $context, $current[Tokenizer::ARGS], $source);
|
||||
$return = $helpers->call(
|
||||
$sectionName,
|
||||
$this,
|
||||
$context,
|
||||
$current[Tokenizer::ARGS],
|
||||
$source
|
||||
);
|
||||
|
||||
if ($return instanceof String) {
|
||||
if ($return instanceof StringWrapper) {
|
||||
return $this->handlebars->loadString($return)->render($context);
|
||||
} else {
|
||||
return $return;
|
||||
@ -402,42 +438,39 @@ class Template
|
||||
// fallback to mustache style each/with/for just if there is
|
||||
// no argument at all.
|
||||
try {
|
||||
$sectionVar = $context->get($sectionName, true);
|
||||
$sectionVar = $context->get($sectionName, false);
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
throw new \RuntimeException(
|
||||
$sectionName . ' is not registered as a helper'
|
||||
sprintf(
|
||||
'"%s" is not registered as a helper',
|
||||
$sectionName
|
||||
)
|
||||
);
|
||||
}
|
||||
$buffer = '';
|
||||
if (is_array($sectionVar) || $sectionVar instanceof \Traversable) {
|
||||
$isList = is_array($sectionVar) &&
|
||||
(array_keys($sectionVar) === range(0, count($sectionVar) - 1));
|
||||
if ($this->_checkIterable($sectionVar)) {
|
||||
$index = 0;
|
||||
$lastIndex = $isList ? (count($sectionVar) - 1) : false;
|
||||
|
||||
$lastIndex = (count($sectionVar) - 1);
|
||||
foreach ($sectionVar as $key => $d) {
|
||||
$specialVariables = array(
|
||||
$context->pushSpecialVariables(
|
||||
array(
|
||||
'@index' => $index,
|
||||
'@first' => ($index === 0),
|
||||
'@last' => ($index === $lastIndex),
|
||||
'@key' => $key
|
||||
)
|
||||
);
|
||||
if (!$isList) {
|
||||
$specialVariables['@key'] = $key;
|
||||
}
|
||||
$context->pushSpecialVariables($specialVariables);
|
||||
$context->push($d);
|
||||
$buffer .= $this->render($context);
|
||||
$context->pop();
|
||||
$context->popSpecialVariables();
|
||||
$index++;
|
||||
}
|
||||
} elseif (is_object($sectionVar)) {
|
||||
} elseif ($sectionVar) {
|
||||
//Act like with
|
||||
$context->push($sectionVar);
|
||||
$buffer = $this->render($context);
|
||||
$context->pop();
|
||||
} elseif ($sectionVar) {
|
||||
$buffer = $this->render($context);
|
||||
}
|
||||
|
||||
return $buffer;
|
||||
@ -462,7 +495,10 @@ class Template
|
||||
return $this->_mustacheStyleSection($context, $current);
|
||||
} else {
|
||||
throw new \RuntimeException(
|
||||
$sectionName . ' is not registered as a helper'
|
||||
sprintf(
|
||||
'"%s"" is not registered as a helper',
|
||||
$sectionName
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -500,12 +536,44 @@ class Template
|
||||
$partial = $this->handlebars->loadPartial($current[Tokenizer::NAME]);
|
||||
|
||||
if ($current[Tokenizer::ARGS]) {
|
||||
$context = $context->get($current[Tokenizer::ARGS]);
|
||||
$arguments = new Arguments($current[Tokenizer::ARGS]);
|
||||
|
||||
$context = new Context($this->_preparePartialArguments($context, $arguments));
|
||||
}
|
||||
|
||||
return $partial->render($context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the arguments of a partial to actual array values to be used in a new context
|
||||
*
|
||||
* @param Context $context Current context
|
||||
* @param Arguments $arguments Arguments for partial
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function _preparePartialArguments(Context $context, Arguments $arguments)
|
||||
{
|
||||
$positionalArgs = array();
|
||||
foreach ($arguments->getPositionalArguments() as $positionalArg) {
|
||||
$contextArg = $context->get($positionalArg);
|
||||
if (is_array($contextArg)) {
|
||||
foreach ($contextArg as $key => $value) {
|
||||
$positionalArgs[$key] = $value;
|
||||
}
|
||||
} else {
|
||||
$positionalArgs[$positionalArg] = $contextArg;
|
||||
}
|
||||
}
|
||||
|
||||
$namedArguments = array();
|
||||
foreach ($arguments->getNamedArguments() as $key => $value) {
|
||||
$namedArguments[$key] = $context->get($value);
|
||||
}
|
||||
|
||||
return array_merge($positionalArgs, $namedArguments);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check if there is a helper with this variable name available or not.
|
||||
@ -524,9 +592,9 @@ class Template
|
||||
}
|
||||
|
||||
/**
|
||||
* get replacing value of a tag
|
||||
* Get replacing value of a tag
|
||||
*
|
||||
* will process the tag as section, if a helper with the same name could be
|
||||
* Will process the tag as section, if a helper with the same name could be
|
||||
* found, so {{helper arg}} can be used instead of {{#helper arg}}.
|
||||
*
|
||||
* @param Context $context current context
|
||||
@ -589,16 +657,16 @@ class Template
|
||||
if (is_array($value)) {
|
||||
return 'Array';
|
||||
}
|
||||
if ($escaped) {
|
||||
if ($escaped && !($value instanceof SafeString)) {
|
||||
$args = $this->handlebars->getEscapeArgs();
|
||||
array_unshift($args, $value);
|
||||
array_unshift($args, (string)$value);
|
||||
$value = call_user_func_array(
|
||||
$this->handlebars->getEscape(),
|
||||
array_values($args)
|
||||
);
|
||||
}
|
||||
|
||||
return $value;
|
||||
return (string)$value;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -639,4 +707,31 @@ class Template
|
||||
|
||||
return $args->getPositionalArguments();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether a value should be iterated over (e.g. in a section context).
|
||||
*
|
||||
* @param mixed $value Value to check if iterable.
|
||||
*
|
||||
* @return bool True if the value is 'iterable'
|
||||
*
|
||||
* @see https://github.com/bobthecow/mustache.php/blob/18a2adc/src/Mustache/Template.php#L85-L113
|
||||
*/
|
||||
private function _checkIterable($value)
|
||||
{
|
||||
switch (gettype($value)) {
|
||||
case 'object':
|
||||
return $value instanceof Traversable;
|
||||
case 'array':
|
||||
$i = 0;
|
||||
foreach ($value as $k => $v) {
|
||||
if ($k !== $i++) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -122,7 +122,7 @@ class Tokenizer
|
||||
*/
|
||||
public function scan($text/*, $delimiters = null*/)
|
||||
{
|
||||
if ($text instanceof String) {
|
||||
if ($text instanceof StringWrapper) {
|
||||
$text = $text->getString();
|
||||
}
|
||||
$this->reset();
|
||||
@ -136,7 +136,6 @@ class Tokenizer
|
||||
*/
|
||||
$len = strlen($text);
|
||||
for ($i = 0; $i < $len; $i++) {
|
||||
|
||||
$this->escaping = $this->tagChange(self::T_ESCAPE, $text, $i);
|
||||
|
||||
// To play nice with helpers' arguments quote and apostrophe marks
|
||||
@ -144,13 +143,21 @@ class Tokenizer
|
||||
$quoteInTag = $this->state != self::IN_TEXT
|
||||
&& ($text[$i] == self::T_SINGLE_Q || $text[$i] == self::T_DOUBLE_Q);
|
||||
|
||||
if ($this->escaped && $text[$i] != self::T_UNESCAPED && !$quoteInTag) {
|
||||
if ($this->escaped && !$this->tagChange($this->otag, $text, $i) && !$quoteInTag) {
|
||||
$this->buffer .= "\\";
|
||||
}
|
||||
|
||||
switch ($this->state) {
|
||||
case self::IN_TEXT:
|
||||
if ($this->tagChange($this->otag. self::T_TRIM, $text, $i) and !$this->escaped) {
|
||||
// Handlebars.js does not think that openning curly brace in
|
||||
// "\\\{{data}}" template is escaped. Instead it removes one
|
||||
// slash and leaves others "as is". To emulate similar behavior
|
||||
// we have to check the last character in the buffer. If it's a
|
||||
// slash we actually does not need to escape openning curly
|
||||
// brace.
|
||||
$prev_slash = substr($this->buffer, -1) == '\\';
|
||||
|
||||
if ($this->tagChange($this->otag. self::T_TRIM, $text, $i) and (!$this->escaped || $prev_slash)) {
|
||||
$this->flushBuffer();
|
||||
$this->state = self::IN_TAG_TYPE;
|
||||
$this->trimLeft = true;
|
||||
@ -158,12 +165,16 @@ class Tokenizer
|
||||
$this->buffer .= "{{{";
|
||||
$i += 2;
|
||||
continue;
|
||||
} elseif ($this->tagChange($this->otag, $text, $i) and !$this->escaped) {
|
||||
} elseif ($this->tagChange($this->otag, $text, $i) and (!$this->escaped || $prev_slash)) {
|
||||
$i--;
|
||||
$this->flushBuffer();
|
||||
$this->state = self::IN_TAG_TYPE;
|
||||
} elseif ($this->escaped and $this->escaping) {
|
||||
// We should not add extra slash before opening tag because
|
||||
// doubled slash where should be transformed to single one
|
||||
if (($i + 1) < $len && !$this->tagChange($this->otag, $text, $i + 1)) {
|
||||
$this->buffer .= "\\";
|
||||
}
|
||||
} elseif (!$this->escaping) {
|
||||
if ($text[$i] == "\n") {
|
||||
$this->filterLine();
|
||||
|
118
tests/Xamin/Cache/APCTest.php
Normal file
118
tests/Xamin/Cache/APCTest.php
Normal file
@ -0,0 +1,118 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of Handlebars-php
|
||||
* Base on mustache-php https://github.com/bobthecow/mustache.php
|
||||
*
|
||||
* PHP version 5.3
|
||||
*
|
||||
* @category Xamin
|
||||
* @package Handlebars
|
||||
* @author fzerorubigd <fzerorubigd@gmail.com>
|
||||
* @author Dmitriy Simushev <simushevds@gmail.com>
|
||||
* @author Mária Šormanová <maria.sormanova@gmail.com>
|
||||
* @copyright 2013 (c) f0ruD A
|
||||
* @license MIT <http://opensource.org/licenses/MIT>
|
||||
* @version GIT: $Id$
|
||||
* @link http://xamin.ir
|
||||
*/
|
||||
|
||||
/**
|
||||
* Test of APC cache driver
|
||||
*
|
||||
* Run without sikp:
|
||||
* php -d apc.enable_cli=1 ./vendor/bin/phpunit
|
||||
*
|
||||
* @category Xamin
|
||||
* @package Handlebars
|
||||
* @subpackage Test
|
||||
* @author Tamás Szijártó <szijarto.tamas.developer@gmail.com>
|
||||
* @license MIT <http://opensource.org/licenses/MIT>
|
||||
* @version Release: @package_version@
|
||||
* @link http://xamin.ir
|
||||
*/
|
||||
class APCTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setUp()
|
||||
{
|
||||
if ( ! extension_loaded('apc') || false === @apc_cache_info()) {
|
||||
$this->markTestSkipped('The ' . __CLASS__ .' requires the use of APC');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the new driver
|
||||
*
|
||||
* @param null|string $prefix optional key prefix, defaults to null
|
||||
*
|
||||
* @return \Handlebars\Cache\APC
|
||||
*/
|
||||
private function _getCacheDriver( $prefix = null )
|
||||
{
|
||||
return new \Handlebars\Cache\APC($prefix);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test with cache prefix
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testWithPrefix()
|
||||
{
|
||||
$prefix = __CLASS__;
|
||||
$driver = $this->_getCacheDriver($prefix);
|
||||
|
||||
$this->assertEquals(false, $driver->get('foo'));
|
||||
|
||||
$driver->set('foo', 10);
|
||||
$this->assertEquals(10, $driver->get('foo'));
|
||||
|
||||
$driver->set('foo', array(12));
|
||||
$this->assertEquals(array(12), $driver->get('foo'));
|
||||
|
||||
$driver->remove('foo');
|
||||
$this->assertEquals(false, $driver->get('foo'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test without cache prefix
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testWithoutPrefix()
|
||||
{
|
||||
$driver = $this->_getCacheDriver();
|
||||
|
||||
$this->assertEquals(false, $driver->get('foo'));
|
||||
|
||||
$driver->set('foo', 20);
|
||||
$this->assertEquals(20, $driver->get('foo'));
|
||||
|
||||
$driver->set('foo', array(22));
|
||||
|
||||
$this->assertEquals(array(22), $driver->get('foo'));
|
||||
|
||||
$driver->remove('foo');
|
||||
$this->assertEquals(false, $driver->get('foo'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test ttl
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testTtl()
|
||||
{
|
||||
$driver = $this->_getCacheDriver();
|
||||
|
||||
$driver->set('foo', 10, -1);
|
||||
$this->assertEquals(false, $driver->get('foo'));
|
||||
|
||||
$driver->set('foo', 20, 3600);
|
||||
$this->assertEquals(20, $driver->get('foo'));
|
||||
}
|
||||
}
|
84
tests/Xamin/Cache/DiskTest.php
Normal file
84
tests/Xamin/Cache/DiskTest.php
Normal file
@ -0,0 +1,84 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of Handlebars-php
|
||||
* Base on mustache-php https://github.com/bobthecow/mustache.php
|
||||
*
|
||||
* PHP version 5.3
|
||||
*
|
||||
* @category Xamin
|
||||
* @package Handlebars
|
||||
* @author Mária Šormanová <maria.sormanova@gmail.com>
|
||||
* @copyright 2016 (c) Mária Šormanová
|
||||
* @license MIT <http://opensource.org/licenses/MIT>
|
||||
* @version GIT: $Id$
|
||||
* @link http://xamin.ir
|
||||
*/
|
||||
|
||||
/**
|
||||
* Test of Disk cache driver
|
||||
*
|
||||
* @category Xamin
|
||||
* @package Handlebars
|
||||
* @subpackage Test
|
||||
* @author Mária Šormanová <maria.sormanova@gmail.com>
|
||||
* @license MIT <http://opensource.org/licenses/MIT>
|
||||
* @version Release: @package_version@
|
||||
* @link http://xamin.ir
|
||||
*/
|
||||
|
||||
class DiskTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setUp()
|
||||
{
|
||||
\Handlebars\Autoloader::register();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the new driver
|
||||
*
|
||||
* @param string $path folder where the cache is located
|
||||
*
|
||||
* @return \Handlebars\Cache\Disk
|
||||
*/
|
||||
private function _getCacheDriver( $path = '')
|
||||
{
|
||||
return new \Handlebars\Cache\Disk($path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the Disk cache
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testDiskCache()
|
||||
{
|
||||
$cache_dir = getcwd().'/tests/cache';
|
||||
$driver = $this->_getCacheDriver($cache_dir);
|
||||
|
||||
$this->assertEquals(false, $driver->get('foo'));
|
||||
|
||||
$driver->set('foo', "hello world");
|
||||
$this->assertEquals("hello world", $driver->get('foo'));
|
||||
|
||||
$driver->set('foo', "hello world", -1);
|
||||
$this->assertEquals(false, $driver->get('foo'));
|
||||
|
||||
$driver->set('foo', "hello world", 3600);
|
||||
$this->assertEquals("hello world", $driver->get('foo'));
|
||||
|
||||
$driver->set('foo', array(12));
|
||||
$this->assertEquals(array(12), $driver->get('foo'));
|
||||
|
||||
$driver->remove('foo');
|
||||
$this->assertEquals(false, $driver->get('foo'));
|
||||
|
||||
rmdir($cache_dir);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
@ -118,32 +118,47 @@ class HandlebarsTest extends \PHPUnit_Framework_TestCase
|
||||
'<strong>Test</strong>'
|
||||
),
|
||||
array(
|
||||
"\{{data}}", // is equal to \\{{data}}
|
||||
"\\{{data}}", // is equal to \{{data}} in template file
|
||||
array('data' => 'foo'),
|
||||
'{{data}}',
|
||||
),
|
||||
array(
|
||||
'\\\\{{data}}',
|
||||
'\\\\{{data}}', // is equal to \\{{data}} in template file
|
||||
array('data' => 'foo'),
|
||||
'\\\\foo'
|
||||
'\\foo' // is equals to \foo in output
|
||||
),
|
||||
array(
|
||||
'\\\{{data}}', // is equal to \\\\{{data}} in php
|
||||
'\\\\\\{{data}}', // is equal to \\\{{data}} in template file
|
||||
array('data' => 'foo'),
|
||||
'\\\\foo'
|
||||
'\\\\foo' // is equals to \\foo in output
|
||||
),
|
||||
array(
|
||||
'\{{{data}}}',
|
||||
'\\\\\\\\{{data}}', // is equal to \\\\{{data}} in template file
|
||||
array('data' => 'foo'),
|
||||
'\\\\\\foo' // is equals to \\\foo in output
|
||||
),
|
||||
array(
|
||||
'\{{{data}}}', // is equal to \{{{data}}} in template file
|
||||
array('data' => 'foo'),
|
||||
'{{{data}}}'
|
||||
),
|
||||
array(
|
||||
'\pi',
|
||||
'\pi', // is equal to \pi in template
|
||||
array(),
|
||||
'\pi'
|
||||
),
|
||||
array(
|
||||
'\\\\\\\\qux',
|
||||
'\\\\foo', // is equal to \\foo in template
|
||||
array(),
|
||||
'\\\\foo'
|
||||
),
|
||||
array(
|
||||
'\\\\\\bar', // is equal to \\\bar in template
|
||||
array(),
|
||||
'\\\\\\bar'
|
||||
),
|
||||
array(
|
||||
'\\\\\\\\qux', // is equal to \\\\qux in template file
|
||||
array(),
|
||||
'\\\\\\\\qux'
|
||||
),
|
||||
@ -161,7 +176,12 @@ class HandlebarsTest extends \PHPUnit_Framework_TestCase
|
||||
'{{#if first}}The first{{else}}{{#if second}}The second{{/if}}{{/if}}',
|
||||
array('first' => false, 'second' => true),
|
||||
'The second'
|
||||
)
|
||||
),
|
||||
array(
|
||||
'{{#value}}Hello {{value}}, from {{parent_context}}{{/value}}',
|
||||
array('value' => 'string', 'parent_context' => 'parent string'),
|
||||
'Hello string, from parent string'
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@ -380,7 +400,7 @@ class HandlebarsTest extends \PHPUnit_Framework_TestCase
|
||||
$this->assertEquals('Test helper is called with a b c', $engine->render('{{test2 a b c}}', array()));
|
||||
|
||||
$engine->addHelper('renderme', function () {
|
||||
return new \Handlebars\String("{{test}}");
|
||||
return new \Handlebars\StringWrapper("{{test}}");
|
||||
});
|
||||
$this->assertEquals('Test helper is called', $engine->render('{{#renderme}}', array()));
|
||||
|
||||
@ -439,12 +459,212 @@ class HandlebarsTest extends \PHPUnit_Framework_TestCase
|
||||
$engine->getHelpers()->call('invalid', $engine->loadTemplate(''), new \Handlebars\Context(), '', '');
|
||||
}
|
||||
|
||||
public function testInvalidHelperMustacheStyle()
|
||||
public function testRegisterHelper()
|
||||
{
|
||||
$this->setExpectedException('RuntimeException');
|
||||
$loader = new \Handlebars\Loader\StringLoader();
|
||||
$engine = new \Handlebars\Handlebars(array('loader' => $loader));
|
||||
$engine->render('{{#NOTVALID}}XXX{{/NOTVALID}}', array());
|
||||
//date_default_timezone_set('GMT');
|
||||
|
||||
//FIRST UP: some awesome helpers!!
|
||||
|
||||
//translations
|
||||
$translations = array(
|
||||
'hello' => 'bonjour',
|
||||
'my name is %s' => 'mon nom est %s',
|
||||
'how are your %s kids and %s' => 'comment sont les enfants de votre %s et %s'
|
||||
);
|
||||
|
||||
//i18n
|
||||
$engine->registerHelper('_', function($key) use ($translations) {
|
||||
$args = func_get_args();
|
||||
$key = array_shift($args);
|
||||
$options = array_pop($args);
|
||||
|
||||
//make sure it's a string
|
||||
$key = (string) $key;
|
||||
|
||||
//by default the translation is the key
|
||||
$translation = $key;
|
||||
|
||||
//if there is a translation
|
||||
if(isset($translations[$key])) {
|
||||
//translate it
|
||||
$translation = $translations[$key];
|
||||
}
|
||||
|
||||
//if there are more arguments
|
||||
if(!empty($args)) {
|
||||
//it means the translations was
|
||||
//something like 'Hello %s'
|
||||
return vsprintf($translation, $args);
|
||||
}
|
||||
|
||||
//just return what we got
|
||||
return $translation;
|
||||
});
|
||||
|
||||
//create a better if helper
|
||||
$engine->registerHelper('when', function($value1, $operator, $value2, $options) {
|
||||
$valid = false;
|
||||
//the amazing reverse switch!
|
||||
switch (true) {
|
||||
case $operator == 'eq' && $value1 == $value2:
|
||||
case $operator == '==' && $value1 == $value2:
|
||||
case $operator == 'req' && $value1 === $value2:
|
||||
case $operator == '===' && $value1 === $value2:
|
||||
case $operator == 'neq' && $value1 != $value2:
|
||||
case $operator == '!=' && $value1 != $value2:
|
||||
case $operator == 'rneq' && $value1 !== $value2:
|
||||
case $operator == '!==' && $value1 !== $value2:
|
||||
case $operator == 'lt' && $value1 < $value2:
|
||||
case $operator == '<' && $value1 < $value2:
|
||||
case $operator == 'lte' && $value1 <= $value2:
|
||||
case $operator == '<=' && $value1 <= $value2:
|
||||
case $operator == 'gt' && $value1 > $value2:
|
||||
case $operator == '>' && $value1 > $value2:
|
||||
case $operator == 'gte' && $value1 >= $value2:
|
||||
case $operator == '>=' && $value1 >= $value2:
|
||||
case $operator == 'and' && $value1 && $value2:
|
||||
case $operator == '&&' && ($value1 && $value2):
|
||||
case $operator == 'or' && ($value1 || $value2):
|
||||
case $operator == '||' && ($value1 || $value2):
|
||||
$valid = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if($valid) {
|
||||
return $options['fn']();
|
||||
}
|
||||
|
||||
return $options['inverse']();
|
||||
});
|
||||
|
||||
//a loop helper
|
||||
$engine->registerHelper('loop', function($object, $options) {
|
||||
//expected for subtemplates of this block to use
|
||||
// {{value.profile_name}} vs {{profile_name}}
|
||||
// {{key}} vs {{@index}}
|
||||
|
||||
$i = 0;
|
||||
$buffer = array();
|
||||
$total = count($object);
|
||||
|
||||
//loop through the object
|
||||
foreach($object as $key => $value) {
|
||||
//call the sub template and
|
||||
//add it to the buffer
|
||||
$buffer[] = $options['fn'](array(
|
||||
'key' => $key,
|
||||
'value' => $value,
|
||||
'last' => ++$i === $total
|
||||
));
|
||||
}
|
||||
|
||||
return implode('', $buffer);
|
||||
});
|
||||
|
||||
//array in
|
||||
$engine->registerHelper('in', function(array $array, $key, $options) {
|
||||
if(in_array($key, $array)) {
|
||||
return $options['fn']();
|
||||
}
|
||||
|
||||
return $options['inverse']();
|
||||
});
|
||||
|
||||
//converts date formats to other formats
|
||||
$engine->registerHelper('date', function($time, $format, $options) {
|
||||
return date($format, strtotime($time));
|
||||
});
|
||||
|
||||
//nesting helpers, these don't really help anyone :)
|
||||
$engine->registerHelper('nested1', function($test1, $test2, $options) {
|
||||
return $options['fn'](array(
|
||||
'test4' => $test1,
|
||||
'test5' => 'This is Test 5'
|
||||
));
|
||||
});
|
||||
|
||||
$engine->registerHelper('nested2', function($options) {
|
||||
return $options['fn'](array('test6' => 'This is Test 6'));
|
||||
});
|
||||
|
||||
//NEXT UP: some practical case studies
|
||||
|
||||
//case 1 - i18n
|
||||
$variable1 = array();
|
||||
$template1 = "{{_ 'hello'}}, {{_ 'my name is %s' 'Foo'}}! {{_ 'how are your %s kids and %s' 6 'dog'}}?";
|
||||
$expected1 = 'bonjour, mon nom est Foo! comment sont les enfants de votre 6 et dog?';
|
||||
|
||||
//case 2 - when
|
||||
$variable2 = array('gender' => 'female', 'foo' => 'bar');
|
||||
$template2 = "Hello {{#when gender '===' 'male'}}sir{{else}}maam{{/when}} {{foo}}";
|
||||
$expected2 = 'Hello maam bar';
|
||||
|
||||
//case 3 - when else
|
||||
$variable3 = array('gender' => 'male');
|
||||
$template3 = "Hello {{#when gender '===' 'male'}}sir{{else}}maam{{/when}}";
|
||||
$expected3 = 'Hello sir';
|
||||
|
||||
//case 4 - loop
|
||||
$variable4 = array(
|
||||
'rows' => array(
|
||||
array(
|
||||
'profile_name' => 'Jane Doe',
|
||||
'profile_created' => '2014-04-04 00:00:00'
|
||||
),
|
||||
array(
|
||||
'profile_name' => 'John Doe',
|
||||
'profile_created' => '2015-01-21 00:00:00'
|
||||
)
|
||||
)
|
||||
);
|
||||
$template4 = "{{#loop rows}}<li>{{value.profile_name}} - {{date value.profile_created 'M d'}}</li>{{/loop}}";
|
||||
$expected4 = '<li>Jane Doe - Apr 04</li><li>John Doe - Jan 21</li>';
|
||||
|
||||
//case 5 - array in
|
||||
$variable5 = $variable4;
|
||||
$variable5['me'] = 'Jack Doe';
|
||||
$variable5['admins'] = array('Jane Doe', 'John Doe');
|
||||
$template5 = "{{#in admins me}}<ul>".$template4."</ul>{{else}}No Access{{/in}}{{suffix}}";
|
||||
$expected5 = 'No Access';
|
||||
|
||||
//case 6 - array in else
|
||||
$variable6 = $variable5;
|
||||
$variable6['me'] = 'Jane Doe';
|
||||
$variable6['suffix'] = 'qux';
|
||||
$template6 = $template5;
|
||||
$expected6 = '<ul><li>Jane Doe - Apr 04</li><li>John Doe - Jan 21</li></ul>qux';
|
||||
|
||||
//case 7 - nested templates and parent-grand variables
|
||||
$variable7 = array('test' => 'Hello World');
|
||||
$template7 = '{{#nested1 test "test2"}} '
|
||||
.'In 1: {{test4}} {{#nested1 ../test \'test3\'}} '
|
||||
.'In 2: {{test5}}{{#nested2}} '
|
||||
.'In 3: {{test6}} {{../../../test}}{{/nested2}}{{/nested1}}{{/nested1}}';
|
||||
$expected7 = ' In 1: Hello World In 2: This is Test 5 In 3: This is Test 6 Hello World';
|
||||
|
||||
//case 8 - when inside an each
|
||||
$variable8 = array('data' => array(0, 1, 2, 3),'finish' => 'ok');
|
||||
$template8 = '{{#each data}}{{#when this ">" "0"}}{{this}}{{/when}}{{/each}} {{finish}}';
|
||||
$expected8 = '123 ok';
|
||||
|
||||
//case 9 - when inside an each
|
||||
$variable9 = array('data' => array(),'finish' => 'ok');
|
||||
$template9 = '{{#each data}}{{#when this ">" "0"}}{{this}}{{/when}}{{else}}foo{{/each}} {{finish}}';
|
||||
$expected9 = 'foo ok';
|
||||
|
||||
//LAST UP: the actual testing
|
||||
|
||||
$this->assertEquals($expected1, $engine->render($template1, $variable1));
|
||||
$this->assertEquals($expected2, $engine->render($template2, $variable2));
|
||||
$this->assertEquals($expected3, $engine->render($template3, $variable3));
|
||||
$this->assertEquals($expected4, $engine->render($template4, $variable4));
|
||||
$this->assertEquals($expected5, $engine->render($template5, $variable5));
|
||||
$this->assertEquals($expected6, $engine->render($template6, $variable6));
|
||||
$this->assertEquals($expected7, $engine->render($template7, $variable7));
|
||||
$this->assertEquals($expected8, $engine->render($template8, $variable8));
|
||||
$this->assertEquals($expected9, $engine->render($template9, $variable9));
|
||||
}
|
||||
|
||||
public function testInvalidHelper()
|
||||
@ -464,16 +684,23 @@ class HandlebarsTest extends \PHPUnit_Framework_TestCase
|
||||
$engine = new \Handlebars\Handlebars(array('loader' => $loader));
|
||||
$this->assertEquals('yes', $engine->render('{{#x}}yes{{/x}}', array('x' => true)));
|
||||
$this->assertEquals('', $engine->render('{{#x}}yes{{/x}}', array('x' => false)));
|
||||
$this->assertEquals('', $engine->render('{{#NOTVALID}}XXX{{/NOTVALID}}', array()));
|
||||
$this->assertEquals('yes', $engine->render('{{^x}}yes{{/x}}', array('x' => false)));
|
||||
$this->assertEquals('', $engine->render('{{^x}}yes{{/x}}', array('x' => true)));
|
||||
$this->assertEquals('1234', $engine->render('{{#x}}{{this}}{{/x}}', array('x' => array(1, 2, 3, 4))));
|
||||
$this->assertEquals('012', $engine->render('{{#x}}{{@index}}{{/x}}', array('x' => array('a', 'b', 'c'))));
|
||||
$this->assertEquals('abc', $engine->render('{{#x}}{{@key}}{{/x}}', array('x' => array('a' => 1, 'b' => 2, 'c' => 3))));
|
||||
$this->assertEquals('the_only_key', $engine->render('{{#x}}{{@key}}{{/x}}', array('x' => array('the_only_key' => 1))));
|
||||
$this->assertEquals('123', $engine->render('{{#x}}{{a}}{{b}}{{c}}{{/x}}', array('x' => array('a' => 1, 'b' => 2, 'c' => 3))));
|
||||
$this->assertEquals('1', $engine->render('{{#x}}{{the_only_key}}{{/x}}', array('x' => array('the_only_key' => 1))));
|
||||
$std = new stdClass();
|
||||
$std->value = 1;
|
||||
$std->other = 4;
|
||||
$this->assertEquals('1', $engine->render('{{#x}}{{value}}{{/x}}', array('x' => $std)));
|
||||
$this->assertEquals('1', $engine->render('{{{x}}}', array('x' => 1)));
|
||||
$this->assertEquals('1 2', $engine->render('{{#x}}{{value}} {{parent}}{{/x}}', array('x' => $std, 'parent' => 2)));
|
||||
|
||||
$y = new stdClass();
|
||||
$y->value = 2;
|
||||
$this->assertEquals('2 1 3 4', $engine->render('{{#x}}{{#y}}{{value}} {{x.value}} {{from_root}} {{other}}{{/y}}{{/x}}', array('x' => $std, 'y' => $y, 'from_root' => 3)));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -560,14 +787,28 @@ class HandlebarsTest extends \PHPUnit_Framework_TestCase
|
||||
/**
|
||||
* test String class
|
||||
*/
|
||||
public function testStringClass()
|
||||
public function testStringWrapperClass()
|
||||
{
|
||||
$string = new \Handlebars\String('test');
|
||||
$string = new \Handlebars\StringWrapper('test');
|
||||
$this->assertEquals('test', $string->getString());
|
||||
$string->setString('new');
|
||||
$this->assertEquals('new', $string->getString());
|
||||
}
|
||||
|
||||
/**
|
||||
* test SafeString class
|
||||
*/
|
||||
public function testSafeStringClass()
|
||||
{
|
||||
$loader = new \Handlebars\Loader\StringLoader();
|
||||
$helpers = new \Handlebars\Helpers();
|
||||
$engine = new \Handlebars\Handlebars(array('loader' => $loader, 'helpers' => $helpers));
|
||||
|
||||
$this->assertEquals('<strong>Test</strong>', $engine->render('{{string}}', array(
|
||||
'string' => new \Handlebars\SafeString('<strong>Test</strong>')
|
||||
)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $dir
|
||||
*
|
||||
@ -700,7 +941,11 @@ EOM;
|
||||
public function testPartial()
|
||||
{
|
||||
$loader = new \Handlebars\Loader\StringLoader();
|
||||
$partialLoader = new \Handlebars\Loader\ArrayLoader(array('test' => '{{key}}', 'bar' => 'its foo'));
|
||||
$partialLoader = new \Handlebars\Loader\ArrayLoader(array(
|
||||
'test' => '{{key}}',
|
||||
'bar' => 'its foo',
|
||||
'presetVariables' => '{{myVar}}',
|
||||
));
|
||||
$partialAliasses = array('foo' => 'bar');
|
||||
$engine = new \Handlebars\Handlebars(
|
||||
array(
|
||||
@ -710,6 +955,11 @@ EOM;
|
||||
)
|
||||
);
|
||||
|
||||
$this->assertEquals('foobar', $engine->render("{{>presetVariables myVar='foobar'}}", array()));
|
||||
$this->assertEquals('foobar=barbaz', $engine->render("{{>presetVariables myVar='foobar=barbaz'}}", array()));
|
||||
$this->assertEquals('qux', $engine->render("{{>presetVariables myVar=foo}}", array('foo' => 'qux')));
|
||||
$this->assertEquals('qux', $engine->render("{{>presetVariables myVar=foo.bar}}", array('foo' => array('bar' => 'qux'))));
|
||||
|
||||
$this->assertEquals('HELLO', $engine->render('{{>test parameter}}', array('parameter' => array('key' => 'HELLO'))));
|
||||
$this->assertEquals('its foo', $engine->render('{{>foo}}', array()));
|
||||
$engine->registerPartial('foo-again', 'bar');
|
||||
@ -718,6 +968,7 @@ EOM;
|
||||
|
||||
$this->setExpectedException('RuntimeException');
|
||||
$engine->render('{{>foo-again}}', array());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -742,6 +993,9 @@ EOM;
|
||||
// Reference array as string
|
||||
$this->assertEquals('Array', $engine->render('{{var}}', array('var' => array('test'))));
|
||||
|
||||
// Test class with __toString method
|
||||
$this->assertEquals('test', $engine->render('{{var}}', array('var' => new TestClassWithToStringMethod())));
|
||||
|
||||
$obj = new DateTime();
|
||||
$time = $obj->getTimestamp();
|
||||
$this->assertEquals($time, $engine->render('{{time.getTimestamp}}', array('time' => $obj)));
|
||||
@ -1076,7 +1330,7 @@ EOM;
|
||||
|
||||
public function testString()
|
||||
{
|
||||
$string = new \Handlebars\String("Hello World");
|
||||
$string = new \Handlebars\StringWrapper("Hello World");
|
||||
$this->assertEquals((string)$string, "Hello World");
|
||||
}
|
||||
|
||||
@ -1154,16 +1408,34 @@ EOM;
|
||||
$this->assertEquals('A-B', $engine->render('{{concat (concat a "-") b}}', array('a' => 'A', 'b' => 'B', 'A-' => '!')));
|
||||
}
|
||||
|
||||
public function ifUnlessDepthDoesntChangeProvider()
|
||||
{
|
||||
return array(array(
|
||||
'{{#with b}}{{#if this}}{{../a}}{{/if}}{{/with}}',
|
||||
array('a' => 'good', 'b' => 'stump'),
|
||||
'good',
|
||||
), array(
|
||||
'{{#with b}}{{#unless false}}{{../a}}{{/unless}}{{/with}}',
|
||||
array('a' => 'good', 'b' => 'stump'),
|
||||
'good',
|
||||
), array(
|
||||
'{{#with foo}}{{#if goodbye}}GOODBYE cruel {{../world}}!{{/if}}{{/with}}',
|
||||
array('foo' => array('goodbye' => true), 'world' => 'world'),
|
||||
'GOODBYE cruel world!',
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if and unless adding an extra layer when accessing parent
|
||||
* Test if and unless do not add an extra layer when accessing parent
|
||||
*
|
||||
* @dataProvider ifUnlessDepthDoesntChangeProvider
|
||||
*/
|
||||
public function testIfUnlessExtraLayer()
|
||||
public function testIfUnlessDepthDoesntChange($template, $data, $expected)
|
||||
{
|
||||
$loader = new \Handlebars\Loader\StringLoader();
|
||||
$engine = new \Handlebars\Handlebars(array('loader' => $loader));
|
||||
|
||||
$this->assertEquals('good', $engine->render('{{#with b}}{{#if this}}{{../../a}}{{/if}}{{/with}}', array('a' => 'good', 'b' => 'stump')));
|
||||
$this->assertEquals('good', $engine->render('{{#with b}}{{#unless false}}{{../../a}}{{/unless}}{{/with}}', array('a' => 'good', 'b' => 'stump')));
|
||||
$this->assertEquals($expected, $engine->render($template, $data));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1255,6 +1527,12 @@ EOM;
|
||||
|
||||
}
|
||||
|
||||
class TestClassWithToStringMethod {
|
||||
public function __toString() {
|
||||
return 'test';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Testcase for testInlineLoader
|
||||
*
|
||||
|
Loading…
Reference in New Issue
Block a user