/** * Replaces blocks with content from `BlockSet` * @param blob $source template source * @param bool $final `true` if this template is this the last template * @param array $options * @return blob template source, replaced with blocks */ private static function _replace($source, $i, $options) { $cache = new Cache(); $cachePath = $cache->cacheDir() . "/template/"; $pattern = "/{:(block) \"({:block})\"(?: \\[(.+)\\])?}(.*){\\1:}/msU"; preg_match_all(static::$_terminals['T_BLOCK'], $source, $matches); $_blocks = null; foreach ($matches[2] as $index => $block) { $_pattern = String::insert($pattern, array('block' => $block)); $_block = static::$_blocks->blocks("{$block}"); $_blocks = static::$_blocks; /** * Top level content for block * @var string */ $content = trim($_block->content()); /** * The request for block content in the final template * @var string */ $request = $matches[4][$index]; /** * Parent/child matches/replacement */ $_parents = function ($block) use(&$content, &$_parents, &$matches, &$index, &$_pattern) { $parent = $block->parent(); if (preg_match("/{:parent:}/msU", $content, $_matches)) { if ($parent) { $content = preg_replace("/{:parent:}/msU", $parent->content(), $content); // go again return $_parents($block->parent(), $content); } else { // no parent, remove the request $content = preg_replace("/{:parent:}/msU", "", $content); } } return $content; }; /** * Parse the block and check to see if it's parents request it. * @var method */ $_children = function ($block, $content = null) use(&$_children, &$matches, &$index, &$_pattern, &$_blocks) { $content = $content == null ? $block->content() : $content; $_block = $_blocks->blocks($block->name()); /** * If the block has a child then we're not at the bottom of the chain. * We need to move up until we cant * @var mixed `object` or `false` */ $child = $block->child(); /** * If the block has a parent then we cant be at the top of the chain. * As long as there's a parent we need to keep moving. * @var mixed `object` or `false` */ $parent = $block->parent(); if (preg_match("/{:child:}/msU", $content)) { // Block doesn't have a child block if (!$child) { // Also has no parent if (!$parent) { // clear the entire block $content = ""; } else { // Has a parent, still no child tho // just remove the call for child block $content = preg_replace("/{:child:}/msU", "", $content); return $_children($block, $content); } } // not asking for a child } else { // Has a parent if ($parent) { if (preg_match("/{:child:}/msU", $parent->content())) { $content = preg_replace("/{:child:}/msU", $content, $parent->content()); return $_children($parent, $content); } } } // must return content so we dont muck up parent return $content; }; // parse children $content = $_children($_block); // parse parents $content = $_parents($_block); $source = preg_replace($_pattern, $content, $source); } // 0 should always be the final template if ($i == 0) { if ($cacheable = $cache->write($source, static::$_blocks->templates(0), $_blocks, $options)) { static::$_template = $cacheable; } } }