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