system/View/Parser.php
protected function parsePair(string $variable, array $data, string $template): array
	{
		// Holds the replacement patterns and contents
		// that will be used within a preg_replace in parse()
		$replace = [];

		// Find all matches of space-flexible versions of {tag}{/tag} so we
		// have something to loop over.
		preg_match_all(
				'#' . $this->leftDelimiter . '\s*' . preg_quote($variable) . '\s*' . $this->rightDelimiter . '(.+?)' .
				$this->leftDelimiter . '\s*' . '/' . preg_quote($variable) . '\s*' . $this->rightDelimiter . '#s', $template, $matches, PREG_SET_ORDER
		);

		/*
		 * Each match looks like:
		 *
		 * $match[0] {tag}...{/tag}
		 * $match[1] Contents inside the tag
		 */
		foreach ($matches as $match)
		{
			// Loop over each piece of $data, replacing
			// it's contents so that we know what to replace in parse()
			$str = '';  // holds the new contents for this tag pair.
			foreach ($data as $row)
			{
				// Objects that have a `toArray()` method should be
				// converted with that method (i.e. Entities)
				if (is_object($row) && method_exists($row, 'toArray'))
				{
					$row = $row->toArray();
				}
				// Otherwise, cast as an array and it will grab public properties.
				else if (is_object($row))
				{
					$row = (array)$row;
				}

				$temp  = [];
				$pairs = [];
				$out   = $match[1];
				foreach ($row as $key => $val)
				{
					// For nested data, send us back through this method...
					if (is_array($val))
					{
						$pair = $this->parsePair($key, $val, $match[1]);

						if (! empty($pair))
						{
							$pairs[array_keys( $pair )[0]] = true;
							$temp                          = array_merge($temp, $pair);
						}

						continue;
					}
					else if (is_object($val))
					{
						$val = 'Class: ' . get_class($val);
					}
					else if (is_resource($val))
					{
						$val = 'Resource';
					}

					$temp['#' . $this->leftDelimiter . '!?\s*' . preg_quote($key) . '\s*\|*\s*([|\w<>=\(\),:_\-\s\+]+)*\s*!?' . $this->rightDelimiter . '#s'] = $val;
				}

				// Now replace our placeholders with the new content.
				foreach ($temp as $pattern => $content)
				{
					$out = $this->replaceSingle($pattern, $content, $out, ! isset( $pairs[$pattern] ) );
				}

				$str .= $out;
			}

			$replace['#' . $match[0] . '#s'] = $str;
		}

		return $replace;
	}
protected function parsePair(string $variable, array $data, string $template): array
	{
		// Holds the replacement patterns and contents
		// that will be used within a preg_replace in parse()
		$replace = [];

		// Find all matches of space-flexible versions of {tag}{/tag} so we
		// have something to loop over.
		preg_match_all(
				'#' . $this->leftDelimiter . '\s*' . preg_quote($variable) . '\s*' . $this->rightDelimiter . '(.+?)' .
				$this->leftDelimiter . '\s*' . '/' . preg_quote($variable) . '\s*' . $this->rightDelimiter . '#s', $template, $matches, PREG_SET_ORDER
		);

		/*
		 * Each match looks like:
		 *
		 * $match[0] {tag}...{/tag}
		 * $match[1] Contents inside the tag
		 */
		foreach ($matches as $match)
		{
			// Loop over each piece of $data, replacing
			// it's contents so that we know what to replace in parse()
			$str = '';  // holds the new contents for this tag pair.
			foreach ($data as $row)
			{
				// Objects that have a `toArray()` method should be
				// converted with that method (i.e. Entities)
				if (is_object($row) && method_exists($row, 'toArray'))
				{
					$row = $row->toArray();
				}
				// Otherwise, cast as an array and it will grab public properties.
				else if (is_object($row))
				{
					$row = (array)$row;
				}

				$temp  = [];
				$pairs = [];
				$out   = $match[1];
				foreach ($row as $key => $val)
				{
					// For nested data, send us back through this method...
					if (is_array($val))
					{
						$pair = $this->parsePair($key, $val, $match[1]);

						if (! empty($pair))
						{
							$pairs[array_keys( $pair )[0]] = true;
							$temp                          = array_merge($temp, $pair);
						}

						continue;
					}
					else if (is_object($val))
					{
						$val = 'Class: ' . get_class($val);
					}
					else if (is_resource($val))
					{
						$val = 'Resource';
					}

					$temp['#' . $this->leftDelimiter . '!?\s*' . preg_quote($key) . '\s*\|*\s*([|\w<>=\(\),:_\-\s\+]+)*\s*!?' . $this->rightDelimiter . '#s'] = $val;
				}

				// Now replace our placeholders with the new content.
				foreach ($temp as $pattern => $content)
				{
					$out = $this->replaceSingle($pattern, $content, $out, ! isset( $pairs[$pattern] ) );
				}

				$str .= $out;
			}

			$replace['#' . $match[0] . '#s'] = $str;
		}

		return $replace;
	}
Parse a tag pair

Parses tag pairs: {some_tag} string... {/some_tag}

@param  string $variable
@param  array  $data
@param  string $template
@return array