/** * Renders and returns output for given template filename with its * array of data. Handles parent/extended templates. * * @param string $viewFile Filename of the view * @param array $data Data to include in rendered view. If empty the current * View::$viewVars will be used. * @return string Rendered output * @throws \LogicException When a block is left open. * @triggers View.beforeRenderFile $this, [$viewFile] * @triggers View.afterRenderFile $this, [$viewFile, $content] */ protected function _render($viewFile, $data = []) { if (empty($data)) { $data = $this->viewVars; } $this->_current = $viewFile; $initialBlocks = count($this->Blocks->unclosed()); $this->dispatchEvent('View.beforeRenderFile', [$viewFile]); $content = $this->_evaluate($viewFile, $data); $afterEvent = $this->dispatchEvent('View.afterRenderFile', [$viewFile, $content]); if (isset($afterEvent->result)) { $content = $afterEvent->result; } if (isset($this->_parents[$viewFile])) { $this->_stack[] = $this->fetch('content'); $this->assign('content', $content); $content = $this->_render($this->_parents[$viewFile]); $this->assign('content', array_pop($this->_stack)); } $remainingBlocks = count($this->Blocks->unclosed()); if ($initialBlocks !== $remainingBlocks) { throw new LogicException(sprintf('The "%s" block was left open. Blocks are not allowed to cross files.', $this->Blocks->active())); } return $content; }