1: <?php
2: /**
3: * PHP 5
4: *
5: * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
6: * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
7: *
8: * Licensed under The MIT License
9: * For full copyright and license information, please see the LICENSE.txt
10: * Redistributions of files must retain the above copyright notice.
11: *
12: * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
13: * @link http://cakephp.org CakePHP(tm) Project
14: * @since CakePHP(tm) v2.1
15: * @license http://www.opensource.org/licenses/mit-license.php MIT License
16: */
17:
18: /**
19: * ViewBlock implements the concept of Blocks or Slots in the View layer.
20: * Slots or blocks are combined with extending views and layouts to afford slots
21: * of content that are present in a layout or parent view, but are defined by the child
22: * view or elements used in the view.
23: *
24: * @package Cake.View
25: */
26: class ViewBlock {
27:
28: /**
29: * Append content
30: *
31: * @constant APPEND
32: */
33: const APPEND = 'append';
34:
35: /**
36: * Prepend content
37: *
38: * @constant PREPEND
39: */
40: const PREPEND = 'prepend';
41:
42: /**
43: * Block content. An array of blocks indexed by name.
44: *
45: * @var array
46: */
47: protected $_blocks = array();
48:
49: /**
50: * The active blocks being captured.
51: *
52: * @var array
53: */
54: protected $_active = array();
55:
56: /**
57: * Should the currently captured content be discarded on ViewBlock::end()
58: *
59: * @var boolean
60: * @see ViewBlock::end()
61: * @see ViewBlock::startIfEmpty()
62: */
63: protected $_discardActiveBufferOnEnd = false;
64:
65: /**
66: * Start capturing output for a 'block'
67: *
68: * Blocks allow you to create slots or blocks of dynamic content in the layout.
69: * view files can implement some or all of a layout's slots.
70: *
71: * You can end capturing blocks using View::end(). Blocks can be output
72: * using View::get();
73: *
74: * @param string $name The name of the block to capture for.
75: * @return void
76: */
77: public function start($name) {
78: $this->_active[] = $name;
79: ob_start();
80: }
81:
82: /**
83: * Start capturing output for a 'block' if it is empty
84: *
85: * Blocks allow you to create slots or blocks of dynamic content in the layout.
86: * view files can implement some or all of a layout's slots.
87: *
88: * You can end capturing blocks using View::end(). Blocks can be output
89: * using View::get();
90: *
91: * @param string $name The name of the block to capture for.
92: * @return void
93: */
94: public function startIfEmpty($name) {
95: if (empty($this->_blocks[$name])) {
96: return $this->start($name);
97: }
98: $this->_discardActiveBufferOnEnd = true;
99: ob_start();
100: }
101:
102: /**
103: * End a capturing block. The compliment to ViewBlock::start()
104: *
105: * @return void
106: * @see ViewBlock::start()
107: */
108: public function end() {
109: if ($this->_discardActiveBufferOnEnd) {
110: $this->_discardActiveBufferOnEnd = false;
111: ob_end_clean();
112: return;
113: }
114: if (!empty($this->_active)) {
115: $active = end($this->_active);
116: $content = ob_get_clean();
117: if (!isset($this->_blocks[$active])) {
118: $this->_blocks[$active] = '';
119: }
120: $this->_blocks[$active] .= $content;
121: array_pop($this->_active);
122: }
123: }
124:
125: /**
126: * Concat content to an existing or new block.
127: * Concating to a new block will create the block.
128: *
129: * Calling concat() without a value will create a new capturing
130: * block that needs to be finished with View::end(). The content
131: * of the new capturing context will be added to the existing block context.
132: *
133: * @param string $name Name of the block
134: * @param string $value The content for the block
135: * @param string $mode If ViewBlock::APPEND content will be appended to existing content.
136: * If ViewBlock::PREPEND it will be prepended.
137: * @return void
138: * @throws CakeException when you use non-string values.
139: */
140: public function concat($name, $value = null, $mode = ViewBlock::APPEND) {
141: if (isset($value)) {
142: if (!is_string($value)) {
143: throw new CakeException(__d('cake_dev', '%s must be a string.', '$value'));
144: }
145: if (!isset($this->_blocks[$name])) {
146: $this->_blocks[$name] = '';
147: }
148: if ($mode === ViewBlock::PREPEND) {
149: $this->_blocks[$name] = $value . $this->_blocks[$name];
150: } else {
151: $this->_blocks[$name] .= $value;
152: }
153: } else {
154: $this->start($name);
155: }
156: }
157:
158: /**
159: * Append to an existing or new block. Appending to a new
160: * block will create the block.
161: *
162: * Calling append() without a value will create a new capturing
163: * block that needs to be finished with View::end(). The content
164: * of the new capturing context will be added to the existing block context.
165: *
166: * @param string $name Name of the block
167: * @param string $value The content for the block.
168: * @return void
169: * @throws CakeException when you use non-string values.
170: * @deprecated As of 2.3 use ViewBlock::concat() instead.
171: */
172: public function append($name, $value = null) {
173: $this->concat($name, $value);
174: }
175:
176: /**
177: * Set the content for a block. This will overwrite any
178: * existing content.
179: *
180: * @param string $name Name of the block
181: * @param string $value The content for the block.
182: * @return void
183: * @throws CakeException when you use non-string values.
184: */
185: public function set($name, $value) {
186: if (!is_string($value)) {
187: throw new CakeException(__d('cake_dev', 'Blocks can only contain strings.'));
188: }
189: $this->_blocks[$name] = $value;
190: }
191:
192: /**
193: * Get the content for a block.
194: *
195: * @param string $name Name of the block
196: * @param string $default Default string
197: * @return string The block content or $default if the block does not exist.
198: */
199: public function get($name, $default = '') {
200: if (!isset($this->_blocks[$name])) {
201: return $default;
202: }
203: return $this->_blocks[$name];
204: }
205:
206: /**
207: * Get the names of all the existing blocks.
208: *
209: * @return array An array containing the blocks.
210: */
211: public function keys() {
212: return array_keys($this->_blocks);
213: }
214:
215: /**
216: * Get the name of the currently open block.
217: *
218: * @return mixed Either null or the name of the last open block.
219: */
220: public function active() {
221: return end($this->_active);
222: }
223:
224: /**
225: * Get the names of the unclosed/active blocks.
226: *
227: * @return array An array of unclosed blocks.
228: */
229: public function unclosed() {
230: return $this->_active;
231: }
232:
233: }
234: