1: <?php
2: /**
3: * This file contains the former template class.
4: *
5: * @package Core
6: * @subpackage GUI
7: * @version SVN Revision $Rev:$
8: *
9: * @author Jan Lengowski, Stefan Jelner
10: * @copyright four for business AG <www.4fb.de>
11: * @license http://www.contenido.org/license/LIZENZ.txt
12: * @link http://www.4fb.de
13: * @link http://www.contenido.org
14: */
15:
16: defined('CON_FRAMEWORK') || die('Illegal call: Missing framework initialization - request aborted.');
17:
18: /**
19: * class Template
20: * Light template mechanism
21: *
22: * @package Core
23: * @subpackage GUI
24: */
25: class cTemplate {
26:
27: /**
28: * Needles (static)
29: *
30: * @var array
31: */
32: public $needles = array();
33:
34: /**
35: * Replacements (static)
36: *
37: * @var array
38: */
39: public $replacements = array();
40:
41: /**
42: * Dyn_Needles (dynamic)
43: *
44: * @var array
45: */
46: public $Dyn_needles = array();
47:
48: /**
49: * Dyn_Replacements (dynamic)
50: *
51: * @var array
52: */
53: public $Dyn_replacements = array();
54:
55:
56: /**
57: * Dynamic counter
58: *
59: * @var int
60: */
61: public $dyn_cnt = 0;
62:
63: /**
64: * Tags array (for dynamic blocks);
65: *
66: * @var array
67: */
68: public $tags = array(
69: 'static' => '{%s}',
70: 'start' => '<!-- BEGIN:BLOCK -->',
71: 'end' => '<!-- END:BLOCK -->'
72: );
73:
74: /**
75: * gettext domain (default: contenido)
76: *
77: * @var string
78: */
79: protected $_sDomain = 'contenido';
80:
81: /**
82: * Constructor function
83: *
84: * @param array|bool $tags [optional]
85: */
86: public function __construct($tags = false) {
87: if (is_array($tags)) {
88: $this->tags = $tags;
89: }
90:
91: $this->setEncoding("");
92: }
93:
94: /**
95: * Sets the gettext domain to use for translations in a template
96: *
97: * @param string $sDomain
98: * Sets the domain to use for template translations
99: */
100: public function setDomain($sDomain) {
101: $this->_sDomain = $sDomain;
102: }
103:
104: /**
105: * Set Templates placeholders and values
106: *
107: * With this method you can replace the placeholders
108: * in the static templates with dynamic data.
109: *
110: * @param string $which
111: * 's' for Static or else dynamic
112: * @param string $needle
113: * Placeholder
114: * @param string $replacement
115: * Replacement String
116: */
117: public function set($which, $needle, $replacement) {
118: if ($which == 's') {
119: // static
120: $this->needles[] = sprintf($this->tags['static'], $needle);
121: $this->replacements[] = $replacement;
122: } else {
123: // dynamic
124: $this->Dyn_needles[$this->dyn_cnt][] = sprintf($this->tags['static'], $needle);
125: $this->Dyn_replacements[$this->dyn_cnt][] = $replacement;
126: }
127: }
128:
129: /**
130: * Sets an encoding for the template's head block.
131: *
132: * @param string $encoding
133: * Encoding to set
134: */
135: public function setEncoding($encoding) {
136: $this->_encoding = $encoding;
137: }
138:
139: /**
140: * Iterate internal counter by one
141: */
142: public function next() {
143: $this->dyn_cnt++;
144: }
145:
146: /**
147: * Reset template data
148: */
149: public function reset() {
150: $this->dyn_cnt = 0;
151: $this->needles = array();
152: $this->replacements = array();
153: $this->Dyn_needles = array();
154: $this->Dyn_replacements = array();
155: }
156:
157: /**
158: * Generate the template and print/return it.
159: * (do translations sequentially to save memory!!!)
160: *
161: * @param string $template
162: * Either template string or template file path
163: * @param bool $return [optional]
164: * Return or print template
165: * @param bool $note [optional]
166: * Echo "Generated by ... " Comment
167: * @return string|void
168: * Complete template string or nothing
169: */
170: public function generate($template, $return = false, $note = false) {
171: global $cCurrentModule, $cfg, $frontend_debug;
172:
173: $moduleHandler = NULL;
174: if (!is_null($cCurrentModule)) {
175: $moduleHandler = new cModuleHandler($cCurrentModule);
176: }
177:
178: // Check if the template is a file or a string
179: if (!@is_file($template)) {
180: if (is_object($moduleHandler) && is_file($moduleHandler->getTemplatePath($template))) {
181: // Module directory has higher priority
182: $content = $moduleHandler->getFilesContent('template', '', $template);
183: if ($frontend_debug['template_display']) {
184: echo('<!-- CTEMPLATE ' . $template . ' -->');
185: }
186: } else {
187: // Template is a string (it is a reference to save memory!!!)
188: $content = &$template;
189: }
190: } else {
191: if (is_object($moduleHandler) && is_file($moduleHandler->getTemplatePath($template))) {
192: // Module directory has higher priority
193: $content = $moduleHandler->getFilesContent('template', '', $template);
194: } else {
195: // Template is a file in template directory
196: $content = implode('', file($template));
197: }
198: }
199:
200: // prepend note
201: if ($note) {
202: $content = "<!-- Generated by CONTENIDO " . CON_VERSION . "-->\n" . $content;
203: }
204:
205: // CEC for template pre processing
206: $content = cApiCecHook::executeAndReturn('Contenido.Template.BeforeParse', $content, $this);
207:
208: $pieces = array();
209:
210: // Replace i18n strings before replacing other placeholders
211: $this->replacei18n($content, 'i18n');
212: $this->replacei18n($content, 'trans');
213:
214: // If content has dynamic blocks
215: $startQ = preg_quote($this->tags['start'], '/');
216: $endQ = preg_quote($this->tags['end'], '/');
217: if (preg_match('/^.*' . $startQ . '.*?' . $endQ . '.*$/s', $content)) {
218: // Split everything into an array
219: preg_match_all('/^(.*)' . $startQ . '(.*?)' . $endQ . '(.*)$/s', $content, $pieces);
220: // Safe memory
221: array_shift($pieces);
222: $content = '';
223: // Now combine pieces together
224: // Start block
225: $content .= str_replace($this->needles, $this->replacements, $pieces[0][0]);
226: unset($pieces[0][0]);
227:
228: // Generate dynamic blocks
229: for ($a = 0; $a < $this->dyn_cnt; $a++) {
230: $content .= str_replace($this->Dyn_needles[$a], $this->Dyn_replacements[$a], $pieces[1][0]);
231: }
232: unset($pieces[1][0]);
233:
234: // End block
235: $content .= str_replace($this->needles, $this->replacements, $pieces[2][0]);
236: unset($pieces[2][0]);
237: } else {
238: $content = str_replace($this->needles, $this->replacements, $content);
239: }
240:
241: if ($this->_encoding != '') {
242: // $content = str_replace("</head>", '<meta http-equiv="Content-Type" content="text/html; charset=' . $this->_encoding . '">' . "\n" . '</head>', $content);
243: }
244:
245: // if ('templates/standard/template.con_meta_edit_form.html' == $template) {
246: // error_log($content);
247: // }
248:
249: if ($return) {
250: return $content;
251: } else {
252: echo $content;
253: }
254: }
255:
256: /**
257: * Replaces a named function with the translated variant
258: *
259: * @param string $template
260: * Contents of the template to translate.
261: * It is reference to save memory!!!
262: * @param string $functionName
263: * Name of the translation function (e.g. i18n)
264: */
265: public function replacei18n(&$template, $functionName) {
266: $container = array();
267:
268: // Be sure that php code stays unchanged
269: $php_matches = array();
270: /*
271: * if (preg_match_all('/<\?(php)?((.)|(\s))*?\?>/i', $template,
272: * $php_matches)) { $x = 0; foreach ($php_matches[0] as $php_match) {
273: * $x++; $template = str_replace($php_match , '{PHP#' . $x . '#PHP}',
274: * $template); $container[$x] = $php_match; } }
275: */
276:
277: $functionNameQ = preg_quote($functionName, '/');
278:
279: // If template contains functionName + parameter store all matches
280: $matches = array();
281: preg_match_all('/' . $functionNameQ . "\\(([\\\"\\'])(.*?)\\1\\)/s", $template, $matches);
282:
283: $matches = array_values(array_unique($matches[2]));
284: for ($a = 0; $a < count($matches); $a++) {
285: $template = preg_replace('/' . $functionNameQ . "\\([\\\"\\']" . preg_quote($matches[$a], '/') . "[\\\"\\']\\)/s", i18n($matches[$a], $this->_sDomain), $template);
286: }
287:
288: // Change back php placeholder
289: if (is_array($container)) {
290: foreach ($container as $x => $php_match) {
291: $template = str_replace('{PHP#' . $x . '#PHP}', $php_match, $template);
292: }
293: }
294: }
295:
296: }
297: