1: <?php
2:
3: /**
4: * This file is part of the Latte (https://latte.nette.org)
5: * Copyright (c) 2008 David Grudl (https://davidgrudl.com)
6: */
7:
8: namespace Latte\Runtime;
9:
10: use Latte;
11:
12:
13: /**
14: * Snippet driver
15: * @internal
16: */
17: class SnippetDriver
18: {
19: use Latte\Strict;
20:
21: const TYPE_STATIC = 'static',
22: TYPE_DYNAMIC = 'dynamic',
23: TYPE_AREA = 'area';
24:
25: /** @var array */
26: private $stack = [];
27:
28: /** @var int */
29: private $nestingLevel = 0;
30:
31: /** @var bool */
32: private $renderingSnippets = false;
33:
34: /** @var ISnippetBridge */
35: private $bridge;
36:
37:
38: public function __construct(ISnippetBridge $bridge)
39: {
40: $this->bridge = $bridge;
41: }
42:
43:
44: public function enter($name, $type)
45: {
46: if (!$this->renderingSnippets) {
47: return;
48: }
49: $obStarted = false;
50: if (
51: ($this->nestingLevel === 0 && $this->bridge->needsRedraw($name))
52: || ($type === self::TYPE_DYNAMIC && ($previous = end($this->stack)) && $previous[1] === true)
53: ) {
54: ob_start(function () {});
55: $this->nestingLevel = $type === self::TYPE_AREA ? 0 : 1;
56: $obStarted = true;
57: } elseif ($this->nestingLevel > 0) {
58: $this->nestingLevel++;
59: }
60: $this->stack[] = [$name, $obStarted];
61: $this->bridge->markRedrawn($name);
62: }
63:
64:
65: public function leave()
66: {
67: if (!$this->renderingSnippets) {
68: return;
69: }
70: list($name, $obStarted) = array_pop($this->stack);
71: if ($this->nestingLevel > 0 && --$this->nestingLevel === 0) {
72: $content = ob_get_clean();
73: $this->bridge->addSnippet($name, $content);
74: } elseif ($obStarted) { // dynamic snippet wrapper or snippet area
75: ob_end_clean();
76: }
77: }
78:
79:
80: public function getHtmlId($name)
81: {
82: return $this->bridge->getHtmlId($name);
83: }
84:
85:
86: public function renderSnippets(array $blocks, array $params)
87: {
88: if ($this->renderingSnippets || !$this->bridge->isSnippetMode()) {
89: return false;
90: }
91: $this->renderingSnippets = true;
92: $this->bridge->setSnippetMode(false);
93: foreach ($blocks as $name => $function) {
94: if ($name[0] !== '_' || !$this->bridge->needsRedraw(substr($name, 1))) {
95: continue;
96: }
97: $function = reset($function);
98: $function($params);
99: }
100: $this->bridge->setSnippetMode(true);
101: $this->bridge->renderChildren();
102: return true;
103: }
104: }
105: