Parcourir la source

Major updates to fix context in iterable blocks. Context is now stored in an array, with the most local context at index 0. Changed everything to pass context arrays around by reference. Added internal function for recursive render calls, allowing the top level to take a single view object, but all internal calls to expect a context array.

Justin Hileman il y a 15 ans
Parent
commit
f3bb419557
1 fichiers modifiés avec 89 ajouts et 51 suppressions
  1. 89 51
      Mustache.php

+ 89 - 51
Mustache.php

@@ -19,7 +19,7 @@ class Mustache {
 	protected $tagRegEx;
 
 	protected $template;
-	protected $view;
+	protected $context;
 	protected $partials;
 
 	/**
@@ -29,15 +29,18 @@ class Mustache {
 	 * array of partials as well.
 	 *
 	 * @access public
-	 * @param mixed $template (default: null)
+	 * @param string $template (default: null)
 	 * @param mixed $view (default: null)
-	 * @param mixed $partials (default: null)
+	 * @param array $partials (default: null)
 	 * @return void
 	 */
 	public function __construct($template = null, $view = null, $partials = null) {
 		$this->template = $template;
-		$this->view     = $view;
 		$this->partials = $partials;
+
+		if ($view) {
+			$this->context = array($view);
+		}
 	}
 
 	/**
@@ -49,23 +52,34 @@ class Mustache {
 	 * @access public
 	 * @param string $template (default: null)
 	 * @param mixed $view (default: null)
-	 * @param mixed $partials (default: null)
+	 * @param array $partials (default: null)
 	 * @return string Rendered Mustache template.
 	 */
 	public function render($template = null, $view = null, $partials = null) {
 		if ($template === null) $template = $this->template;
 		if ($partials !== null) $this->partials = $partials;
 
-		if ($view === null) {
-			if ($this->view) {
-				$view = $this->view;
-			} else {
-				$view = $this;
-			}
+		if ($view) {
+			$this->context = array($view);
+		} else if (empty($this->context)) {
+			$this->context = array($this);
 		}
 
-		$template = $this->renderSection($template, $view);
-		return $this->renderTags($template, $view);
+		return $this->_render($template, $this->context);
+	}
+
+
+	/**
+	 * Internal render function, used for recursive calls.
+	 *
+	 * @access protected
+	 * @param string $template
+	 * @param array &$context
+	 * @return string Rendered Mustache template.
+	 */
+	protected function _render($template, &$context) {
+		$template = $this->renderSection($template, $context);
+		return $this->renderTags($template, $context);
 	}
 
 	/**
@@ -73,10 +87,10 @@ class Mustache {
 	 *
 	 * @access protected
 	 * @param string $template
-	 * @param mixed $view
+	 * @param array $context
 	 * @return string
 	 */
-	protected function renderSection($template, $view) {
+	protected function renderSection($template, &$context) {
 		if (strpos($template, $this->otag . '#') === false) {
 			return $template;
 		}
@@ -93,10 +107,10 @@ class Mustache {
 			$content  = $matches[2][0];
 
 			$replace = '';
-			$val = $this->getVariable($tag_name, $view);
+			$val = $this->getVariable($tag_name, $context);
 			if (is_array($val)) {
-				foreach ($val as $local_view) {
-					$replace .= $this->render($content, $local_view);
+				foreach ($val as $local_context) {
+					$replace .= $this->_render($content, $this->getContext($context, $local_context));
 				}
 			} else if ($val) {
 				$replace .= $content;
@@ -113,10 +127,10 @@ class Mustache {
 	 *
 	 * @access protected
 	 * @param string $template
-	 * @param mixed $view
+	 * @param array $context
 	 * @return void
 	 */
-	protected function renderTags($template, $view) {
+	protected function renderTags($template, &$context) {
 		if (strpos($template, $this->otag) === false) {
 			return $template;
 		}
@@ -133,7 +147,7 @@ class Mustache {
 			$tag_name = trim($matches[2][0]);
 
 			$html .= substr($template, 0, $offset);
-			$html .= $this->renderTag($modifier, $tag_name, $view);
+			$html .= $this->renderTag($modifier, $tag_name, $context);
 			$template = substr($template, $offset + strlen($tag));
 		}
 
@@ -149,27 +163,27 @@ class Mustache {
 	 * @access protected
 	 * @param string $modifier
 	 * @param string $tag_name
-	 * @param mixed $view
+	 * @param array $context
 	 * @return string
 	 */
-	protected function renderTag($modifier, $tag_name, $view) {
+	protected function renderTag($modifier, $tag_name, &$context) {
 		switch ($modifier) {
 			case '=':
-				return $this->changeDelimiter($tag_name, $view);
+				return $this->changeDelimiter($tag_name, $context);
 				break;
 			case '!':
-				return $this->renderComment($tag_name, $view);
+				return $this->renderComment($tag_name, $context);
 				break;
 			case '>':
-				return $this->renderPartial($tag_name, $view);
+				return $this->renderPartial($tag_name, $context);
 				break;
 			case '{':
 			case '&':
-				return $this->renderUnescaped($tag_name, $view);
+				return $this->renderUnescaped($tag_name, $context);
 				break;
 			case '':
 			default:
-				return $this->renderEscaped($tag_name, $view);
+				return $this->renderEscaped($tag_name, $context);
 				break;
 		}
 	}
@@ -179,11 +193,11 @@ class Mustache {
 	 *
 	 * @access protected
 	 * @param string $tag_name
-	 * @param mixed $view
+	 * @param array $context
 	 * @return string
 	 */
-	protected function renderEscaped($tag_name, $view) {
-		return htmlentities($this->getVariable($tag_name, $view));
+	protected function renderEscaped($tag_name, &$context) {
+		return htmlentities($this->getVariable($tag_name, $context));
 	}
 
 	/**
@@ -191,10 +205,10 @@ class Mustache {
 	 *
 	 * @access protected
 	 * @param string $tag_name
-	 * @param mixed $view
+	 * @param array $context
 	 * @return string
 	 */
-	protected function renderComment($tag_name, $view) {
+	protected function renderComment($tag_name, &$context) {
 		return '';
 	}
 
@@ -203,11 +217,11 @@ class Mustache {
 	 *
 	 * @access protected
 	 * @param string $tag_name
-	 * @param mixed $view
+	 * @param array $context
 	 * @return string
 	 */
-	protected function renderUnescaped($tag_name, $view) {
-		return $this->getVariable($tag_name, $view);
+	protected function renderUnescaped($tag_name, &$context) {
+		return $this->getVariable($tag_name, $context);
 	}
 
 	/**
@@ -215,11 +229,13 @@ class Mustache {
 	 *
 	 * @access protected
 	 * @param string $tag_name
-	 * @param mixed $view
+	 * @param array $context
 	 * @return string
 	 */
-	protected function renderPartial($tag_name, $view) {
-		$view = new self($this->getPartial($tag_name), $view);
+	protected function renderPartial($tag_name, &$context) {
+		$view = new self($this->getPartial($tag_name), $context, $this->partials);
+		$view->otag = $this->otag;
+		$view->ctag = $this->ctag;
 		return $view->render();
 	}
 
@@ -229,10 +245,10 @@ class Mustache {
 	 *
 	 * @access protected
 	 * @param string $tag_name
-	 * @param mixed $view
+	 * @param array $context
 	 * @return string
 	 */
-	protected function changeDelimiter($tag_name, $view) {
+	protected function changeDelimiter($tag_name, &$context) {
 		$tags = explode(' ', $tag_name);
 		$this->otag = $tags[0];
 		$this->ctag = $tags[1];
@@ -243,8 +259,28 @@ class Mustache {
 		return '';
 	}
 
+
+	/**
+	 * Prepare a new context reference array.
+	 *
+	 * This is used to create context arrays for iterable blocks.
+	 *
+	 * @access protected
+	 * @param array $context
+	 * @param mixed $local_context
+	 * @return void
+	 */
+	protected function getContext(&$context, &$local_context) {
+		$ret = array();
+		$ret[] =& $local_context;
+		foreach ($context as $view) {
+			$ret[] =& $view;
+		}
+		return $ret;
+	}
+
 	/**
-	 * Get a variable from the view object.
+	 * Get a variable from the context array.
 	 *
 	 * If the view is an array, returns the value with array key $tag_name.
 	 * If the view is an object, this will check for a public member variable
@@ -254,18 +290,20 @@ class Mustache {
 	 *
 	 * @access protected
 	 * @param string $tag_name
-	 * @param mixed $view
+	 * @param array $context
 	 * @return string
 	 */
-	protected function getVariable($tag_name, $view) {
-		if (is_object($view)) {
-			if (isset($view->$tag_name)) {
-				return $view->$tag_name;
-			} else if (method_exists($view, $tag_name)) {
-				return $view->$tag_name();
+	protected function getVariable($tag_name, &$context) {
+		foreach ($context as $view) {
+			if (is_object($view)) {
+				if (isset($view->$tag_name)) {
+					return $view->$tag_name;
+				} else if (method_exists($view, $tag_name)) {
+					return $view->$tag_name();
+				}
+			} else if (isset($view[$tag_name])) {
+				return $view[$tag_name];
 			}
-		} else if (isset($view[$tag_name])) {
-			return $view[$tag_name];
 		}
 		return '';
 	}