1: <?php
2: namespace Sleepy;
3:
4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49:
50:
51: class Template {
52: 53: 54: 55: 56:
57: public $extension = '.tpl';
58:
59: 60: 61: 62: 63:
64: public $directory;
65:
66: 67: 68: 69: 70: 71:
72: protected $_file;
73:
74: 75: 76: 77: 78: 79:
80: protected $_data = array();
81:
82: 83: 84: 85: 86: 87:
88: public function __construct($template='', $basedir='') {
89: if (class_exists('\Sleepy\Hook')) {
90: \Sleepy\Hook::addAction('template_start');
91: }
92:
93:
94: if ($basedir == '') {
95: if (!defined('DIRBASE')) {
96: define('DIRBASE', $_SERVER['DOCUMENT_ROOT'] . '/app');
97: }
98:
99: $this->directory = DIRBASE . '/templates/';
100: } else {
101: $this->directory = $basedir;
102: }
103:
104: if (!empty($template)) {
105: $this->setTemplate($template);
106: }
107: }
108:
109: 110: 111: 112: 113: 114: 115:
116: private function _checkTemplate($file) {
117: if (empty($file)) {
118: throw new \Exception('Template file has not been set.');
119: }
120:
121:
122: if (!file_exists($this->directory)) {
123: throw new \Exception("Template directory '{$this->directory}' does not exists.");
124: }
125:
126:
127: if (!file_exists($this->directory . $file . $this->extension)) {
128: throw new \Exception("Template '{$this->directory}{$file}{$this->extension}' does not exist.");
129: }
130:
131: return true;
132: }
133:
134: 135: 136: 137: 138: 139: 140: 141: 142:
143: private function _assignArrayByPath($arr, $path) {
144:
145: $keys = explode('.', $path);
146:
147: if (is_array($keys)) {
148: foreach ($keys as $key) {
149: if (array_key_exists($key, $arr)) {
150: $arr = $arr[$key];
151: } else {
152: return false;
153: }
154: }
155: }
156:
157: return $arr;
158: }
159:
160: 161: 162: 163: 164: 165: 166: 167:
168: private function _render($template, $data) {
169:
170: if (preg_match('/{{\s*#include\s.*}}/', $template, $include)) {
171: $index = trim(str_replace('{{', '', str_replace('}}', '', $include[0])));
172: if (file_exists($this->directory . str_replace('#include ', '', $index) . $this->extension)) {
173: ob_start();
174: include($this->directory . str_replace('#include ', '', $index) . $this->extension);
175: } else {
176: ob_clean();
177: throw new \Exception($this->directory . str_replace('#include ', '', $index) . $this->extension . ' doesn\'t exist. Cannot include file.');
178: }
179: $template = str_replace($include[0], $this->_render(ob_get_clean(), $data), $template);
180:
181: return $this->_render($template, $data);
182: }
183:
184:
185: if (preg_match_all('/{{\s?#each.+?}}(?:(?>[^{}]+)|(?R))*{{\s?\/each\s?}}/ism', $template, $loops)) {
186:
187: foreach ($loops[0] as $value) {
188:
189: $rendered = '';
190:
191:
192: preg_match('/{{\s?#each\s(?<for>\w+) in (?<in>.*?)\s?}}/', $value, $forin);
193:
194: $forin['in'] = strtolower($forin['in']);
195:
196:
197: $new_template = preg_replace('/{{\s?#each.*?}}/s', '', $value, 1);
198: $new_template = preg_replace('/{{\s?\/each\s?}}$/s', '', $new_template, 1);
199:
200:
201: $in = $this->_assignArrayByPath($data, $forin['in']);
202:
203:
204: if (is_array($in[0])) {
205:
206:
207: if (class_exists('\Sleepy\Hook')) {
208: $in = \Sleepy\Hook::addFilter('template_each_array', array($in));
209: }
210:
211: $iterator = 0;
212:
213: foreach ($in as $new_data) {
214: $iterator++;
215:
216: if (class_exists('\Sleepy\Hook')) {
217: $new_data = \Sleepy\Hook::addFilter('template_each', array($new_data));
218: $new_data = \Sleepy\Hook::addFilter('template_each_' + $forin['for'], array($new_data));
219: }
220:
221: $new_data['iterator'] = $iterator;
222: $new_data['zebra'] = ($iterator % 2) ? 'odd' : 'even';
223:
224:
225: $new_data[$forin['for']] = $new_data;
226:
227:
228: $rendered = $rendered . $this->_render($new_template, $new_data);
229: }
230: } else {
231:
232: $rendered = $rendered . $this->_render($new_template, $data);
233: }
234:
235: $template = str_replace($value, $rendered, $template);
236: }
237: }
238:
239: if (class_exists('\Sleepy\Hook')) {
240: $template = \Sleepy\Hook::addFilter('prerender_template', $template);
241: }
242:
243:
244: preg_match_all('/{{\s?(.*?)(\s.*?)?\s?}}/', $template, $matches);
245:
246:
247: foreach (array_unique($matches[0]) as $index => $placeholder) {
248: $key = strtolower($matches[1][$index]);
249:
250: $arguments = array(
251: $this->_assignArrayByPath($data, $key)
252: );
253:
254:
255: $arguments = array_merge($arguments, explode(' ', trim($matches[2][$index])));
256:
257: $boundData = $arguments;
258:
259: if (class_exists('\Sleepy\Hook')) {
260: $boundData = \Sleepy\Hook::addFilter('render_placeholder_' . strtolower($key), $boundData);
261: }
262:
263:
264:
265: if (is_array($boundData)) {
266: $boundData = $boundData[0];
267: }
268:
269: $template = str_replace($placeholder, $boundData, $template);
270: }
271:
272: return $template;
273: }
274:
275: 276: 277: 278: 279: 280:
281: private function _parseTemplate() {
282: $this->_checkTemplate($this->_file);
283:
284:
285: ob_start();
286: include($this->directory . $this->_file . $this->extension);
287: $template = $this->_render(ob_get_clean(), $this->_data);
288:
289: if (class_exists('\Sleepy\Hook')) {
290: $template = \Sleepy\Hook::addFilter('render_template_' . $this->_file, $template);
291: $template = \Sleepy\Hook::addFilter('render_template', $template);
292: }
293:
294: return $template;
295: }
296:
297: 298: 299: 300: 301:
302: public function setTemplate($file) {
303: if ($this->_checkTemplate($file)) {
304: $this->_file = $file;
305: }
306: }
307:
308: 309: 310: 311: 312: 313:
314: public function bind($placeholder, $value) {
315: $placeholder = strtolower($placeholder);
316:
317: if (!is_array($value)) {
318: if (class_exists('\Sleepy\Hook')) {
319: $value = \Sleepy\Hook::addFilter('bind_placeholder_' . $placeholder, $value);
320: }
321: }
322:
323: $this->_data[trim($placeholder)] = $value;
324: }
325:
326: 327: 328: 329:
330: public function bindStart() {
331: ob_start();
332: }
333:
334: 335: 336: 337: 338:
339: public function bindStop($placeholder) {
340: $content = ob_get_clean();
341:
342: if (class_exists('\Sleepy\Hook')) {
343: $content = \Sleepy\Hook::addFilter('bind_placeholder_' . $placeholder, $content);
344: }
345:
346: $this->_data[trim(strtolower($placeholder))] = $content;
347: }
348:
349: 350: 351: 352: 353: 354:
355: public function get($key) {
356: $value = $this->_data[$key];
357:
358: if (class_exists('\Sleepy\Hook')) {
359: \Sleepy\Hook::addFilter('template_get_' . $key, $value);
360: }
361:
362: return $value;
363: }
364:
365: 366: 367:
368: public function show() {
369: echo $this->_parseTemplate();
370: }
371:
372: 373: 374:
375: public function retrieve() {
376: return $this->_parseTemplate();
377: }
378: }