$e->setSourceContext($templateName ? new Source('', $templateName) : $this->getSourceContext());
}
if ($e->getTemplateLine() > 0) {
throw $e;
}
if (!$line) {
$e->guess();
} else {
$e->setTemplateLine($line);
}
throw $e;
}
}
/**
* @internal
*
* @return self
*/
public function unwrap()
{
return $this;
}
/**
* Returns all blocks.
*
* This method is for internal use only and should never be called
* directly.
*
* @return array An array of blocks
*/
public function getBlocks()
{
return $this->blocks;
}
public function display(array $context, array $blocks = []): void
{
foreach ($this->yield($context, $blocks) as $data) {
echo $data;
}
}
public function render(array $context): string
{
$content = '';
foreach ($this->yield($context) as $data) {
$content .= $data;
}
return $content;
}
/**
* @return iterable<string>
*/
public function yield(array $context, array $blocks = []): iterable
{
$context = $this->env->mergeGlobals($context);
$blocks = array_merge($this->blocks, $blocks);
try {
if ($this->useYield) {
yield from $this->doDisplay($context, $blocks);
return;
}
$level = ob_get_level();
ob_start();
foreach ($this->doDisplay($context, $blocks) as $data) {
if (ob_get_length()) {
$data = ob_get_clean().$data;
ob_start();
}
yield $data;
}
if (ob_get_length()) {
yield ob_get_clean();
}
} catch (Error $e) {
if (!$e->getSourceContext()) {
$e->setSourceContext($this->getSourceContext());
}
// this is mostly useful for \Twig\Error\LoaderError exceptions
// see \Twig\Error\LoaderError
if (-1 === $e->getTemplateLine()) {
$e->guess();
}
throw $e;
} catch (\Throwable $e) {
$e = new RuntimeError(sprintf('An exception has been thrown during the rendering of a template ("%s").', $e->getMessage()), -1, $this->getSourceContext(), $e);
$e->guess();
throw $e;
} finally {
if (!$this->useYield) {
while (ob_get_level() > $level) {
ob_end_clean();
}
}
}
}
/**
* @return iterable<string>
*/
public function yieldBlock($name, array $context, array $blocks = [], $useBlocks = true, ?self $templateContext = null)
{
if ($useBlocks && isset($blocks[$name])) {
$template = $blocks[$name][0];
$block = $blocks[$name][1];
} elseif (isset($this->blocks[$name])) {
$template = $this->blocks[$name][0];
$block = $this->blocks[$name][1];
} else {
$template = null;
$block = null;
}
// avoid RCEs when sandbox is enabled
if (null !== $template && !$template instanceof self) {
throw new \LogicException('A block must be a method on a \Twig\Template instance.');
}
if (null !== $template) {
try {
if ($this->useYield) {
yield from $template->$block($context, $blocks);
return;
}
$level = ob_get_level();
ob_start();
foreach ($template->$block($context, $blocks) as $data) {
// this is mostly useful for \Twig\Error\LoaderError exceptions
// see \Twig\Error\LoaderError
if (-1 === $e->getTemplateLine()) {
$e->guess();
}
throw $e;
} catch (\Throwable $e) {
$e = new RuntimeError(sprintf('An exception has been thrown during the rendering of a template ("%s").', $e->getMessage()), -1, $template->getSourceContext(), $e);
$e->guess();
throw $e;
} finally {
if (!$this->useYield) {
while (ob_get_level() > $level) {
ob_end_clean();
}
}
}
} elseif ($parent = $this->getParent($context)) {
yield from $parent->unwrap()->yieldBlock($name, $context, array_merge($this->blocks, $blocks), false, $templateContext ?? $this);
} elseif (isset($blocks[$name])) {
throw new RuntimeError(sprintf('Block "%s" should not call parent() in "%s" as the block does not exist in the parent template "%s".', $name, $blocks[$name][0]->getTemplateName(), $this->getTemplateName()), -1, $blocks[$name][0]->getSourceContext());
} else {
throw new RuntimeError(sprintf('Block "%s" on template "%s" does not exist.', $name, $this->getTemplateName()), -1, ($templateContext ?? $this)->getSourceContext());
}
}
/**
* Yields a parent block.
*
* This method is for internal use only and should never be called
* directly.
*
* @param string $name The block name to display from the parent
* @param array $context The context
* @param array $blocks The current set of blocks
*
* @return iterable<string>
*/
public function yieldParentBlock($name, array $context, array $blocks = [])
{
if (isset($this->traits[$name])) {
yield from $this->traits[$name][0]->yieldBlock($name, $context, $blocks, false);
} elseif ($parent = $this->getParent($context)) {
yield from $parent->unwrap()->yieldBlock($name, $context, $blocks, false);
} else {
throw new RuntimeError(sprintf('The template has no parent and no traits defining the "%s" block.', $name), -1, $this->getSourceContext());
}
}
/**
* Auto-generated method to display the template with the given context.
*
* @param array $context An array of parameters to pass to the template
* @param array $blocks An array of blocks to pass to the template
*/
abstract protected function doDisplay(array $context, array $blocks = []);