A super easy PHP Framework for web development!
https://github.com/exacti/phacil-framework
243 lines
6.7 KiB
243 lines
6.7 KiB
6 years ago
|
<?php
|
||
|
|
||
|
/*
|
||
|
* This file is part of Mustache.php.
|
||
|
*
|
||
|
* (c) 2010-2017 Justin Hileman
|
||
|
*
|
||
|
* For the full copyright and license information, please view the LICENSE
|
||
|
* file that was distributed with this source code.
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* Mustache Template rendering Context.
|
||
|
*/
|
||
|
class Mustache_Context
|
||
|
{
|
||
|
private $stack = array();
|
||
|
private $blockStack = array();
|
||
|
|
||
|
/**
|
||
|
* Mustache rendering Context constructor.
|
||
|
*
|
||
|
* @param mixed $context Default rendering context (default: null)
|
||
|
*/
|
||
|
public function __construct($context = null)
|
||
|
{
|
||
|
if ($context !== null) {
|
||
|
$this->stack = array($context);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Push a new Context frame onto the stack.
|
||
|
*
|
||
|
* @param mixed $value Object or array to use for context
|
||
|
*/
|
||
|
public function push($value)
|
||
|
{
|
||
|
array_push($this->stack, $value);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Push a new Context frame onto the block context stack.
|
||
|
*
|
||
|
* @param mixed $value Object or array to use for block context
|
||
|
*/
|
||
|
public function pushBlockContext($value)
|
||
|
{
|
||
|
array_push($this->blockStack, $value);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Pop the last Context frame from the stack.
|
||
|
*
|
||
|
* @return mixed Last Context frame (object or array)
|
||
|
*/
|
||
|
public function pop()
|
||
|
{
|
||
|
return array_pop($this->stack);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Pop the last block Context frame from the stack.
|
||
|
*
|
||
|
* @return mixed Last block Context frame (object or array)
|
||
|
*/
|
||
|
public function popBlockContext()
|
||
|
{
|
||
|
return array_pop($this->blockStack);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get the last Context frame.
|
||
|
*
|
||
|
* @return mixed Last Context frame (object or array)
|
||
|
*/
|
||
|
public function last()
|
||
|
{
|
||
|
return end($this->stack);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Find a variable in the Context stack.
|
||
|
*
|
||
|
* Starting with the last Context frame (the context of the innermost section), and working back to the top-level
|
||
|
* rendering context, look for a variable with the given name:
|
||
|
*
|
||
|
* * If the Context frame is an associative array which contains the key $id, returns the value of that element.
|
||
|
* * If the Context frame is an object, this will check first for a public method, then a public property named
|
||
|
* $id. Failing both of these, it will try `__isset` and `__get` magic methods.
|
||
|
* * If a value named $id is not found in any Context frame, returns an empty string.
|
||
|
*
|
||
|
* @param string $id Variable name
|
||
|
*
|
||
|
* @return mixed Variable value, or '' if not found
|
||
|
*/
|
||
|
public function find($id)
|
||
|
{
|
||
|
return $this->findVariableInStack($id, $this->stack);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Find a 'dot notation' variable in the Context stack.
|
||
|
*
|
||
|
* Note that dot notation traversal bubbles through scope differently than the regular find method. After finding
|
||
|
* the initial chunk of the dotted name, each subsequent chunk is searched for only within the value of the previous
|
||
|
* result. For example, given the following context stack:
|
||
|
*
|
||
|
* $data = array(
|
||
|
* 'name' => 'Fred',
|
||
|
* 'child' => array(
|
||
|
* 'name' => 'Bob'
|
||
|
* ),
|
||
|
* );
|
||
|
*
|
||
|
* ... and the Mustache following template:
|
||
|
*
|
||
|
* {{ child.name }}
|
||
|
*
|
||
|
* ... the `name` value is only searched for within the `child` value of the global Context, not within parent
|
||
|
* Context frames.
|
||
|
*
|
||
|
* @param string $id Dotted variable selector
|
||
|
*
|
||
|
* @return mixed Variable value, or '' if not found
|
||
|
*/
|
||
|
public function findDot($id)
|
||
|
{
|
||
|
$chunks = explode('.', $id);
|
||
|
$first = array_shift($chunks);
|
||
|
$value = $this->findVariableInStack($first, $this->stack);
|
||
|
|
||
|
foreach ($chunks as $chunk) {
|
||
|
if ($value === '') {
|
||
|
return $value;
|
||
|
}
|
||
|
|
||
|
$value = $this->findVariableInStack($chunk, array($value));
|
||
|
}
|
||
|
|
||
|
return $value;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Find an 'anchored dot notation' variable in the Context stack.
|
||
|
*
|
||
|
* This is the same as findDot(), except it looks in the top of the context
|
||
|
* stack for the first value, rather than searching the whole context stack
|
||
|
* and starting from there.
|
||
|
*
|
||
|
* @see Mustache_Context::findDot
|
||
|
*
|
||
|
* @throws Mustache_Exception_InvalidArgumentException if given an invalid anchored dot $id
|
||
|
*
|
||
|
* @param string $id Dotted variable selector
|
||
|
*
|
||
|
* @return mixed Variable value, or '' if not found
|
||
|
*/
|
||
|
public function findAnchoredDot($id)
|
||
|
{
|
||
|
$chunks = explode('.', $id);
|
||
|
$first = array_shift($chunks);
|
||
|
if ($first !== '') {
|
||
|
throw new Mustache_Exception_InvalidArgumentException(sprintf('Unexpected id for findAnchoredDot: %s', $id));
|
||
|
}
|
||
|
|
||
|
$value = $this->last();
|
||
|
|
||
|
foreach ($chunks as $chunk) {
|
||
|
if ($value === '') {
|
||
|
return $value;
|
||
|
}
|
||
|
|
||
|
$value = $this->findVariableInStack($chunk, array($value));
|
||
|
}
|
||
|
|
||
|
return $value;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Find an argument in the block context stack.
|
||
|
*
|
||
|
* @param string $id
|
||
|
*
|
||
|
* @return mixed Variable value, or '' if not found
|
||
|
*/
|
||
|
public function findInBlock($id)
|
||
|
{
|
||
|
foreach ($this->blockStack as $context) {
|
||
|
if (array_key_exists($id, $context)) {
|
||
|
return $context[$id];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return '';
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Helper function to find a variable in the Context stack.
|
||
|
*
|
||
|
* @see Mustache_Context::find
|
||
|
*
|
||
|
* @param string $id Variable name
|
||
|
* @param array $stack Context stack
|
||
|
*
|
||
|
* @return mixed Variable value, or '' if not found
|
||
|
*/
|
||
|
private function findVariableInStack($id, array $stack)
|
||
|
{
|
||
|
for ($i = count($stack) - 1; $i >= 0; $i--) {
|
||
|
$frame = &$stack[$i];
|
||
|
|
||
|
switch (gettype($frame)) {
|
||
|
case 'object':
|
||
|
if (!($frame instanceof Closure)) {
|
||
|
// Note that is_callable() *will not work here*
|
||
|
// See https://github.com/bobthecow/mustache.php/wiki/Magic-Methods
|
||
|
if (method_exists($frame, $id)) {
|
||
|
return $frame->$id();
|
||
|
}
|
||
|
|
||
|
if (isset($frame->$id)) {
|
||
|
return $frame->$id;
|
||
|
}
|
||
|
|
||
|
if ($frame instanceof ArrayAccess && isset($frame[$id])) {
|
||
|
return $frame[$id];
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case 'array':
|
||
|
if (array_key_exists($id, $frame)) {
|
||
|
return $frame[$id];
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return '';
|
||
|
}
|
||
|
}
|