fdcaf207a81cf70a74892afa27fd279c5bb3bf35
[core.git] / inc / classes / main / template / menu / class_MenuTemplateEngine.php
1 <?php
2 /**
3  * A Menu template engine class
4  *
5  * @author              Roland Haeder <webmaster@ship-simu.org>
6  * @version             0.0.0
7  * @copyright   Copyright (c) 2007, 2008 Roland Haeder, 2009 Core Developer Team
8  * @license             GNU GPL 3.0 or any newer version
9  * @link                http://www.ship-simu.org
10  *
11  * This program is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation, either version 3 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program. If not, see <http://www.gnu.org/licenses/>.
23  */
24 class MenuTemplateEngine extends BaseTemplateEngine implements CompileableTemplate {
25         /**
26          * Main nodes in the XML tree ('menu' is ignored)
27          */
28         private $mainNodes = array(
29                 'block-list',
30         );
31
32         /**
33          * Sub nodes in the XML tree
34          */
35         private $subNodes = array(
36                 'entry-list',
37                 'entry',
38                 'entries-content',
39                 'header',
40                 'footer',
41                 'footer-id',
42                 'footer-class',
43                 'footer-text',
44                 'block',
45                 'title',
46                 'title-id',
47                 'title-class',
48                 'title-text',
49                 'design',
50                 'text',
51                 'advert',
52                 'anchor',
53                 'anchor-id',
54                 'anchor-text',
55                 'anchor-title',
56                 'anchor-href',
57         );
58
59         /**
60          * Menu instance
61          */
62         private $menuInstance = null;
63
64         /**
65          * Current main node
66          */
67         private $curr = array();
68
69         /**
70          * Content from depency
71          */
72         private $depencyContent = array();
73
74         /**
75          * Protected constructor
76          *
77          * @return      void
78          */
79         protected function __construct () {
80                 // Call parent constructor
81                 parent::__construct(__CLASS__);
82         }
83
84         /**
85          * Creates an instance of the class TemplateEngine and prepares it for usage
86          *
87          * @param       $appInstance    A manageable application
88          * @param       $menuInstance   A RenderableMenu instance
89          * @return      $tplInstance    An instance of TemplateEngine
90          * @throws      BasePathIsEmptyException                If the provided $templateBasePath is empty
91          * @throws      InvalidBasePathStringException  If $templateBasePath is no string
92          * @throws      BasePathIsNoDirectoryException  If $templateBasePath is no
93          *                                                                                      directory or not found
94          * @throws      BasePathReadProtectedException  If $templateBasePath is
95          *                                                                                      read-protected
96          */
97         public final static function createMenuTemplateEngine (ManageableApplication $appInstance, RenderableMenu $menuInstance) {
98                 // Get a new instance
99                 $tplInstance = new MenuTemplateEngine();
100
101                 // Get language and file I/O instances from application
102                 $langInstance = $appInstance->getLanguageInstance();
103                 $ioInstance = $appInstance->getFileIoInstance();
104
105                 // Determine base path
106                 $templateBasePath = $tplInstance->getConfigInstance()->getConfigEntry('application_base_path') . $appInstance->getRequestInstance()->getRequestElement('app') . '/';
107
108                 // Is the base path valid?
109                 if (empty($templateBasePath)) {
110                         // Base path is empty
111                         throw new BasePathIsEmptyException($tplInstance, self::EXCEPTION_UNEXPECTED_EMPTY_STRING);
112                 } elseif (!is_string($templateBasePath)) {
113                         // Is not a string
114                         throw new InvalidBasePathStringException(array($tplInstance, $templateBasePath), self::EXCEPTION_INVALID_STRING);
115                 } elseif (!is_dir($templateBasePath)) {
116                         // Is not a path
117                         throw new BasePathIsNoDirectoryException(array($tplInstance, $templateBasePath), self::EXCEPTION_INVALID_PATH_NAME);
118                 } elseif (!is_readable($templateBasePath)) {
119                         // Is not readable
120                         throw new BasePathReadProtectedException(array($tplInstance, $templateBasePath), self::EXCEPTION_READ_PROTECED_PATH);
121                 }
122
123                 // Get configuration instance
124                 $configInstance = FrameworkConfiguration::getInstance();
125
126                 // Set the base path
127                 $tplInstance->setTemplateBasePath($templateBasePath);
128
129                 // Set the language and IO instances
130                 $tplInstance->setLanguageInstance($langInstance);
131                 $tplInstance->setFileIoInstance($ioInstance);
132
133                 // Set template extensions
134                 $tplInstance->setRawTemplateExtension($configInstance->getConfigEntry('raw_template_extension'));
135                 $tplInstance->setCodeTemplateExtension($configInstance->getConfigEntry('menu_template_extension'));
136
137                 // Absolute output path for compiled templates
138                 $tplInstance->setCompileOutputPath($configInstance->getConfigEntry('base_path') . $configInstance->getConfigEntry('compile_output_path'));
139
140                 // Set the menu instance
141                 $tplInstance->setMenuInstance($menuInstance);
142
143                 // Return the prepared instance
144                 return $tplInstance;
145         }
146
147         /**
148          * Load a specified menu template into the engine
149          *
150          * @param       $template       The menu template we shall load which is
151          *                                              located in 'menu' by default
152          * @return      void
153          */
154         public function loadMenuTemplate ($template) {
155                 // Set template type
156                 $this->setTemplateType($this->getConfigInstance()->getConfigEntry('menu_template_type'));
157
158                 // Load the special template
159                 $this->loadTemplate($template);
160         }
161
162         /**
163          * Getter for current main node
164          *
165          * @return      $currMainNode   Current main node
166          */
167         public final function getCurrMainNode () {
168                 return $this->curr['main_node'];
169         }
170
171         /**
172          * Setter for current main node
173          *
174          * @param       $element                Element name to set as current main node
175          * @return      $currMainNode   Current main node
176          */
177         private final function setCurrMainNode ($element) {
178                 $this->curr['main_node'] = (string) $element;
179         }
180
181         /**
182          * Getter for main node array
183          *
184          * @return      $mainNodes      Array with valid main node names
185          */
186         public final function getMainNodes () {
187                 return $this->mainNodes;
188         }
189
190         /**
191          * Getter for sub node array
192          *
193          * @return      $subNodes       Array with valid sub node names
194          */
195         public final function getSubNodes () {
196                 return $this->subNodes;
197         }
198
199         /**
200          * Handles the start element of an XML resource
201          *
202          * @param       $resource               XML parser resource (currently ignored)
203          * @param       $element                The element we shall handle
204          * @param       $attributes             All attributes
205          * @return      void
206          * @throws      InvalidXmlNodeException         If an unknown/invalid XML node name was found
207          */
208         public function startElement ($resource, $element, array $attributes) {
209                 // Initial method name which will never be called...
210                 $methodName = 'initMenu';
211
212                 // Make the element name lower-case
213                 $element = strtolower($element);
214
215                 // Is the element a main node?
216                 //* DEBUG: */ echo "START: &gt;".$element."&lt;<br />\n";
217                 if (in_array($element, $this->getMainNodes())) {
218                         // Okay, main node found!
219                         $methodName = 'start' . $this->convertToClassName($element);
220
221                         // Set it
222                         $this->setCurrMainNode($element);
223                 } elseif (in_array($element, $this->getSubNodes())) {
224                         // Sub node found
225                         $methodName = 'start' . $this->convertToClassName($element);
226                 } elseif ($element != 'menu') {
227                         // Invalid node name found
228                         throw new InvalidXmlNodeException(array($this, $element, $attributes), XmlParser::EXCEPTION_XML_NODE_UNKNOWN);
229                 }
230
231                 // Call method
232                 //* DEBUG: */ echo "call: ".$methodName."<br />\n";
233                 call_user_func_array(array($this, $methodName), $attributes);
234         }
235
236         /**
237          * Ends the main or sub node by sending out the gathered data
238          *
239          * @param       $resource       An XML resource pointer (currently ignored)
240          * @param       $nodeName       Name of the node we want to finish
241          * @return      void
242          * @throws      XmlNodeMismatchException        If current main node mismatches the closing one
243          */
244         public function endElement ($resource, $nodeName) {
245                 // Make all lower-case
246                 $nodeName = strtolower($nodeName);
247
248                 // Does this match with current main node?
249                 //* DEBUG: */ echo "END: &gt;".$nodeName."&lt;<br />\n";
250                 if (($nodeName != $this->getCurrMainNode()) && (in_array($nodeName, $this->getMainNodes()))) {
251                         // Did not match!
252                         throw new XmlNodeMismatchException (array($this, $nodeName, $this->getCurrMainNode()), XmlParser::EXCEPTION_XML_NODE_MISMATCH);
253                 } // END - if
254
255                 // Construct method name
256                 $methodName = 'finish' . $this->convertToClassName($nodeName);
257
258                 // Call the corresponding method
259                 //* DEBUG: */ echo "call: ".$methodName."<br />\n";
260                 call_user_func_array(array($this, $methodName), array());
261         }
262
263         /**
264          * Currently not used
265          *
266          * @param       $resource               XML parser resource (currently ignored)
267          * @param       $characters             Characters to handle
268          * @return      void
269          * @todo        Find something useful with this!
270          */
271         public function characterHandler ($resource, $characters) {
272                 // Trim all spaces away
273                 $characters = trim($characters);
274
275                 // Is this string empty?
276                 if (empty($characters)) {
277                         // Then skip it silently
278                         return false;
279                 } // END - if
280
281                 // Unfinished work!
282                 $this->partialStub('Handling extra characters is not yet supported! length='.strlen($characters));
283         }
284
285         /**
286          * Handles the template depency for given node
287          *
288          * @param       $node   The node we should load a depency template
289          * @param       $templateDepency        A template to load to satisfy depencies
290          * @return      void
291          */
292         private function handleTemplateDepency ($node, $templateDepency) {
293                 // Is the template depency set?
294                 if ((!empty($templateDepency)) && (!isset($this->depencyContent[$node]))) {
295                         // Get a temporay menu template instance
296                         $templateInstance = ObjectFactory::createObjectByConfiguredName('menu_template_class', array($this->getApplicationInstance(), $this->getMenuInstance()));
297
298                         // Then load it
299                         $templateInstance->loadMenuTemplate($templateDepency);
300
301                         // Get an XmlParser instance
302                         $templateInstance->renderXmlContent();
303
304                         // Parse the template's content contents
305                         $this->depencyContent[$node] = $templateInstance->getRawTemplateData();
306                 } // END - if
307         }
308
309         /**
310          * Intializes the menu
311          *
312          * @param       $templateDepency        A template to load to satisfy depencies
313          * @return      void
314          * @todo        Add cache creation here
315          */
316         private function initMenu ($templateDepency = '') {
317                 // Get web template engine
318                 $this->setTemplateInstance(ObjectFactory::createObjectByConfiguredName('web_template_class', array($this->getApplicationInstance())));
319
320                 // Handle the depency template
321                 $this->handleTemplateDepency('menu', $templateDepency);
322
323                 // Load the header template for this page
324                 $this->getTemplateInstance()->loadCodeTemplate('menu_global_start');
325
326                 // Set the variable group to page
327                 $this->setVariableGroup('menu');
328
329                 // Set its content in this template instance
330                 $this->assignVariable('menu_start', $this->getTemplateInstance()->getRawTemplateData());
331         }
332
333         /**
334          * Finishes the menu
335          *
336          * @return      void
337          */
338         private function finishMenu () {
339                 // Load the header template for this page
340                 $this->getTemplateInstance()->loadCodeTemplate('menu_global_end');
341
342                 // Set the variable group to page
343                 $this->setVariableGroup('menu');
344
345                 // Set its content in this template instance
346                 $this->assignVariable('menu_end', $this->getTemplateInstance()->getRawTemplateData());
347         }
348
349         /**
350          * Starts the menu entries by loading a (maybe) provided template depency
351          *
352          * @param       $templateDepency        A template to load to satisfy depencies
353          * @return      void
354          */
355         private function startEntryList ($templateDepency = '') {
356                 // Handle the depency template
357                 $this->handleTemplateDepency('entries', $templateDepency);
358
359                 // Load the header template for this page
360                 $this->getTemplateInstance()->loadCodeTemplate('menu_entries_start');
361
362                 // Set the variable group to page
363                 $this->setVariableGroup('menu');
364
365                 // Set its content in this template instance
366                 $this->assignVariable('entries_start', $this->getTemplateInstance()->getRawTemplateData());
367         }
368
369         /**
370          * Finishes the menu entries
371          *
372          * @return      void
373          */
374         private function finishEntryList () {
375                 // Load the header template for this page
376                 $this->getTemplateInstance()->loadCodeTemplate('menu_entries_end');
377
378                 // Set the variable group to page
379                 $this->setVariableGroup('menu');
380
381                 // Set its content in this template instance
382                 $this->assignVariable('entries_end', $this->getTemplateInstance()->getRawTemplateData());
383         }
384
385         /**
386          * Starts the menu header
387          *
388          * @return      void
389          */
390         private function startHeader () {
391                 // Do we have a template instance?
392                 if (is_null($this->getTemplateInstance())) {
393                         // Init template instance for underlaying web templates
394                         $templateInstance = ObjectFactory::createObjectByConfiguredName('web_template_class');
395
396                         // Set it in this template engine
397                         $this->setTemplateInstance($templateInstance);
398                 } // END - if
399
400                 // Load the header template for this page
401                 $this->getTemplateInstance()->loadCodeTemplate('menu_header_start');
402
403                 // Set the variable group to page
404                 $this->setVariableGroup('menu');
405
406                 // Set its content in this template instance
407                 $this->assignVariable('header', $this->getTemplateInstance()->getRawTemplateData());
408         }
409
410         /**
411          * Finishes the menu header
412          *
413          * @return      void
414          */
415         private function finishHeader () {
416                 // Load the header template for this page
417                 $this->getTemplateInstance()->loadCodeTemplate('menu_header_end');
418
419                 // Set the variable group to page
420                 $this->setVariableGroup('menu');
421
422                 // Set its content in this template instance
423                 $this->assignVariable('header_end', $this->getTemplateInstance()->getRawTemplateData());
424         }
425
426         /**
427          * Starts the menu footer
428          *
429          * @return      void
430          */
431         private function startFooter () {
432                 // Do we have a template instance?
433                 if (is_null($this->getTemplateInstance())) {
434                         // Init template instance for underlaying web templates
435                         $templateInstance = ObjectFactory::createObjectByConfiguredName('web_template_class');
436
437                         // Set it in this template engine
438                         $this->setTemplateInstance($templateInstance);
439                 } // END - if
440
441                 // Load the footer template for this page
442                 $this->getTemplateInstance()->loadCodeTemplate('menu_footer_start');
443
444                 // Set the variable group to page
445                 $this->setVariableGroup('menu');
446
447                 // Set its content in this template instance
448                 $this->assignVariable('footer', $this->getTemplateInstance()->getRawTemplateData());
449         }
450
451         /**
452          * Finishes the menu footer
453          *
454          * @return      void
455          */
456         private function finishFooter () {
457                 // Load the footer template for this page
458                 $this->getTemplateInstance()->loadCodeTemplate('menu_footer_end');
459
460                 // Set the variable group to page
461                 $this->setVariableGroup('menu');
462
463                 // Set its content in this template instance
464                 $this->assignVariable('footer_end', $this->getTemplateInstance()->getRawTemplateData());
465         }
466
467         /**
468          * Starts the menu property 'title'
469          *
470          * @return      void
471          */
472         private function startTitle () {
473                 $this->partialStub('Cleared due to XML rewrite.');
474         }
475
476         /**
477          * Finishes the title node by added another template to the menu
478          *
479          * @return      void
480          */
481         private function finishTitle () {
482                 $this->partialStub('Cleared due to XML rewrite.');
483         }
484
485         /**
486          * Starts the menu text
487          *
488          * @return      void
489          */
490         private function startText () {
491                 // Do we have a template instance?
492                 if (is_null($this->getTemplateInstance())) {
493                         // Init template instance for underlaying web templates
494                         $templateInstance = ObjectFactory::createObjectByConfiguredName('web_template_class');
495
496                         // Set it in this template engine
497                         $this->setTemplateInstance($templateInstance);
498                 } // END - if
499
500                 // Load the text template for this page
501                 $this->getTemplateInstance()->loadCodeTemplate('menu_text_start');
502
503                 // Set the variable group to page
504                 $this->setVariableGroup('menu');
505
506                 // Set its content in this template instance
507                 $this->assignVariable('text', $this->getTemplateInstance()->getRawTemplateData());
508         }
509
510         /**
511          * Finishes the menu text
512          *
513          * @return      void
514          */
515         private function finishText () {
516                 // Load the text template for this page
517                 $this->getTemplateInstance()->loadCodeTemplate('menu_text_end');
518
519                 // Set the variable group to page
520                 $this->setVariableGroup('menu');
521
522                 // Set its content in this template instance
523                 $this->assignVariable('text_end', $this->getTemplateInstance()->getRawTemplateData());
524         }
525
526         /**
527          * Starts the menu property 'entry'
528          *
529          * @param       $id             Id of the menu
530          * @return      void
531          */
532         private function startEntry ($id) {
533                 // Set id as current
534                 $this->curr['entry_id'] = $id;
535
536                 // Load the entry template for this page
537                 $this->getTemplateInstance()->loadCodeTemplate('menu_entry_' . $id . '_start');
538
539                 // Set the variable group to page
540                 $this->setVariableGroup('menu');
541
542                 // Set its content in this template instance
543                 $this->assignVariable('entry_start_' . $this->curr['id'], $this->getTemplateInstance()->getRawTemplateData());
544         }
545
546         /**
547          * Finishes the entry node by added another template to the menu
548          *
549          * @return      void
550          */
551         private function finishEntry () {
552                 // Load the entry template for this page
553                 $this->getTemplateInstance()->loadCodeTemplate('menu_entry_' . $this->curr['entry_id'] . '_end');
554
555                 // Set the variable group to page
556                 $this->setVariableGroup('menu');
557
558                 // Set its content in this template instance
559                 $this->assignVariable('entry_end_' . $this->curr['id'], $this->getTemplateInstance()->getRawTemplateData());
560         }
561         /**
562          * Starts the menu property 'anchor'
563          *
564          * @param       $id             Id of the anchor
565          * @param       $link   Link text of the anchor
566          * @param       $title  Link title of the anchor
567          * @return      void
568          */
569         private function startAnchor () {
570                 $this->partialStub('Please implement this method.');
571         }
572
573         /**
574          * Finishes the anchor node by added another template to the menu
575          *
576          * @return      void
577          */
578         private function finishAnchor () {
579                 $this->partialStub('Please implement this method.');
580         }
581
582         /**
583          * Getter for menu cache file (FQFN)
584          *
585          * @return      $fqfn   Full-qualified file name of the menu cache
586          */
587         public function getMenuCacheFqfn () {
588                 // Get the FQFN ready
589                 $fqfn = sprintf("%s%s%s/%s.%s",
590                         $this->getConfigInstance()->getConfigEntry('base_path'),
591                         $this->getGenericBasePath(),
592                         'menus/_cache',
593                         md5(
594                                 $this->getMenuInstance()->getMenuName() . ':' .
595                                 $this->__toString() . ':' .
596                                 $this->getMenuInstance()->__toString()
597                         ),
598                         $this->getMenuInstance()->getMenuType()
599                 );
600
601                 // Return it
602                 return $fqfn;
603         }
604 }
605
606 // [EOF]
607 ?>