Also "import" here
[core.git] / framework / main / classes / template / image / class_ImageTemplateEngine.php
1 <?php
2 // Own namespace
3 namespace CoreFramework\Template\Engine;
4
5 // Import framework stuff
6 use CoreFramework\Factory\ObjectFactory;
7 use CoreFramework\Filesystem\InvalidDirectoryException;
8 use CoreFramework\Parser\Xml\XmlParser;
9 use CoreFramework\Registry\Registry;
10 use CoreFramework\Response\Responseable;
11 use CoreFramework\Template\CompileableTemplate;
12
13 // Import SPL stuff
14 use \UnexpectedValueException;
15
16 /**
17  * The own template engine for loading caching and sending out images
18  *
19  * @author              Roland Haeder <webmaster@shipsimu.org>
20  * @version             0.0.0
21  * @copyright   Copyright (c) 2007, 2008 Roland Haeder, 2009 - 2017 Core Developer Team
22  * @license             GNU GPL 3.0 or any newer version
23  * @link                http://www.shipsimu.org
24  *
25  * This program is free software: you can redistribute it and/or modify
26  * it under the terms of the GNU General Public License as published by
27  * the Free Software Foundation, either version 3 of the License, or
28  * (at your option) any later version.
29  *
30  * This program is distributed in the hope that it will be useful,
31  * but WITHOUT ANY WARRANTY; without even the implied warranty of
32  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
33  * GNU General Public License for more details.
34  *
35  * You should have received a copy of the GNU General Public License
36  * along with this program. If not, see <http://www.gnu.org/licenses/>.
37  */
38 class ImageTemplateEngine extends BaseTemplateEngine implements CompileableTemplate {
39         /**
40          * Main nodes in the XML tree ('image' is ignored)
41          */
42         private $mainNodes = array(
43                 'base',
44                 'type',
45                 'resolution',
46                 'background-color',
47                 'foreground-color',
48                 'image-string'
49         );
50
51         /**
52          * Sub nodes in the XML tree
53          */
54         private $subNodes = array(
55                 'name',
56                 'string-name',
57                 'x',
58                 'y',
59                 'font-size',
60                 'width',
61                 'height',
62                 'red',
63                 'green',
64                 'blue',
65                 'text'
66         );
67
68         /**
69          * Current main node
70          */
71         private $currMainNode = '';
72
73         /**
74          * Protected constructor
75          *
76          * @return      void
77          */
78         protected function __construct () {
79                 // Call parent constructor
80                 parent::__construct(__CLASS__);
81         }
82
83         /**
84          * Creates an instance of the class TemplateEngine and prepares it for usage
85          *
86          * @return      $templateInstance               An instance of TemplateEngine
87          * @throws      UnexpectedValueException                If the provided $templateBasePath is empty or no string
88          * @throws      InvalidDirectoryException       If $templateBasePath is no
89          *                                                                                      directory or not found
90          * @throws      BasePathReadProtectedException  If $templateBasePath is
91          *                                                                                      read-protected
92          */
93         public static final function createImageTemplateEngine () {
94                 // Get a new instance
95                 $templateInstance = new ImageTemplateEngine();
96
97                 // Get the application instance from registry
98                 $applicationInstance = Registry::getRegistry()->getInstance('app');
99
100                 // Determine base path
101                 $templateBasePath = $templateInstance->getConfigInstance()->getConfigEntry('application_base_path') . $applicationInstance->getRequestInstance()->getRequestElement('app') . '/';
102
103                 // Is the base path valid?
104                 if (empty($templateBasePath)) {
105                         // Base path is empty
106                         throw new UnexpectedValueException(sprintf('[%s:%d] Variable templateBasePath is empty.', $templateInstance->__toString(), __LINE__), self::EXCEPTION_UNEXPECTED_EMPTY_STRING);
107                 } elseif (!is_string($templateBasePath)) {
108                         // Is not a string
109                         throw new UnexpectedValueException(sprintf('[%s:%d] %s is not a string with a base path.', $templateInstance->__toString(), __LINE__, $templateBasePath), self::EXCEPTION_INVALID_STRING);
110                 } elseif (!is_dir($templateBasePath)) {
111                         // Is not a path
112                         throw new InvalidDirectoryException(array($templateInstance, $templateBasePath), self::EXCEPTION_INVALID_PATH_NAME);
113                 } elseif (!is_readable($templateBasePath)) {
114                         // Is not readable
115                         throw new BasePathReadProtectedException(array($templateInstance, $templateBasePath), self::EXCEPTION_READ_PROTECED_PATH);
116                 }
117
118                 // Set the base path
119                 $templateInstance->setTemplateBasePath($templateBasePath);
120
121                 // Set template extensions
122                 $templateInstance->setRawTemplateExtension($templateInstance->getConfigInstance()->getConfigEntry('raw_template_extension'));
123                 $templateInstance->setCodeTemplateExtension($templateInstance->getConfigInstance()->getConfigEntry('code_template_extension'));
124
125                 // Absolute output path for compiled templates
126                 $templateInstance->setCompileOutputPath($templateInstance->getConfigInstance()->getConfigEntry('base_path') . $templateInstance->getConfigInstance()->getConfigEntry('compile_output_path'));
127
128                 // Return the prepared instance
129                 return $templateInstance;
130         }
131
132         /**
133          * Getter for current main node
134          *
135          * @return      $currMainNode   Current main node
136          */
137         public final function getCurrMainNode () {
138                 return $this->currMainNode;
139         }
140
141         /**
142          * Getter for main node array
143          *
144          * @return      $mainNodes      Array with valid main node names
145          */
146         public final function getMainNodes () {
147                 return $this->mainNodes;
148         }
149
150         /**
151          * Getter for sub node array
152          *
153          * @return      $subNodes       Array with valid sub node names
154          */
155         public final function getSubNodes () {
156                 return $this->subNodes;
157         }
158
159         /**
160          * Handles the start element of an XML resource
161          *
162          * @param       $resource               XML parser resource (currently ignored)
163          * @param       $element                The element we shall handle
164          * @param       $attributes             All attributes
165          * @return      void
166          * @throws      InvalidXmlNodeException         If an unknown/invalid XML node name was found
167          */
168         public function startElement ($resource, $element, array $attributes) {
169                 // Initial method name which will never be called...
170                 $methodName = 'initImage';
171
172                 // Make the element name lower-case
173                 $element = strtolower($element);
174
175                 // Is the element a main node?
176                 //* DEBUG: */ echo "START: &gt;".$element."&lt;<br />\n";
177                 if (in_array($element, $this->mainNodes)) {
178                         // Okay, main node found!
179                         $methodName = 'setImage' . self::convertToClassName($element);
180                 } elseif (in_array($element, $this->subNodes)) {
181                         // Sub node found
182                         $methodName = 'setImageProperty' . self::convertToClassName($element);
183                 } elseif ($element != 'image') {
184                         // Invalid node name found
185                         throw new InvalidXmlNodeException(array($this, $element, $attributes), XmlParser::EXCEPTION_XML_NODE_UNKNOWN);
186                 }
187
188                 // Call method
189                 //* DEBUG: */ echo "call: ".$methodName."<br />\n";
190                 call_user_func_array(array($this, $methodName), $attributes);
191         }
192
193         /**
194          * Ends the main or sub node by sending out the gathered data
195          *
196          * @param       $resource       An XML resource pointer (currently ignored)
197          * @param       $nodeName       Name of the node we want to finish
198          * @return      void
199          * @throws      XmlNodeMismatchException        If current main node mismatches the closing one
200          */
201         public function finishElement ($resource, $nodeName) {
202                 // Make all lower-case
203                 $nodeName = strtolower($nodeName);
204
205                 // Does this match with current main node?
206                 //* DEBUG: */ echo "END: &gt;".$nodeName."&lt;<br />\n";
207                 if (($nodeName != $this->getCurrMainNode()) && (in_array($nodeName, $this->getMainNodes()))) {
208                         // Did not match!
209                         throw new XmlNodeMismatchException (array($this, $nodeName, $this->getCurrMainNode()), XmlParser::EXCEPTION_XML_NODE_MISMATCH);
210                 } elseif (in_array($nodeName, $this->getSubNodes())) {
211                         // Silently ignore sub nodes
212                         return;
213                 }
214
215                 // Construct method name
216                 $methodName = 'finish' . self::convertToClassName($nodeName);
217
218                 // Call the corresponding method
219                 call_user_func_array(array($this->getImageInstance(), $methodName), array());
220         }
221
222         /**
223          * Currently not used
224          *
225          * @param       $resource               XML parser resource (currently ignored)
226          * @param       $characters             Characters to handle
227          * @return      void
228          * @todo        Find something usefull with this!
229          */
230         public function characterHandler ($resource, $characters) {
231                 // Trim all spaces away
232                 $characters = trim($characters);
233
234                 // Is this string empty?
235                 if (empty($characters)) {
236                         // Then skip it silently
237                         return;
238                 } // END - if
239
240                 // Unfinished work!
241                 $this->partialStub('Handling extra characters is not yet supported!');
242         }
243
244         /**
245          * Intializes the image
246          *
247          * @return      void
248          * @todo        Add cache creation here
249          */
250         private function initImage () {
251                 // Unfinished work!
252         }
253
254         /**
255          * Set the image type
256          *
257          * @param       $imageType      Code fragment or direct value holding the image type
258          * @return      void
259          */
260         private function setImageType ($imageType) {
261                 // Set group to general
262                 $this->setVariableGroup('general');
263
264                 // Try to compile it first to get the value from variable stack
265                 $imageType = $this->compileRawCode($imageType);
266
267                 // Now make a class name of it
268                 $className = self::convertToClassName($imageType.'_image');
269
270                 // And try to initiate it
271                 $this->setImageInstance(ObjectFactory::createObjectByName($className, array($this)));
272
273                 // Set current main node to type
274                 $this->currMainNode = 'type';
275         }
276
277         /**
278          * "Setter" for resolution, we first need to collect the resolution from the
279          * sub-nodes. So first, this method will prepare an array for it
280          *
281          * @return      void
282          */
283         private function setImageResolution () {
284                 // Call the image class
285                 $this->getImageInstance()->initResolution();
286
287                 // Current main node is resolution
288                 $this->currMainNode = 'resolution';
289         }
290
291         /**
292          * "Setter" for base information. For more details see above method!
293          *
294          * @return      void
295          * @see         ImageTemplateEngine::setImageResolution
296          */
297         private function setImageBase () {
298                 // Call the image class
299                 $this->getImageInstance()->initBase();
300
301                 // Current main node is resolution
302                 $this->currMainNode = 'base';
303         }
304
305         /**
306          * "Setter" for background-color. For more details see above method!
307          *
308          * @return      void
309          * @see         ImageTemplateEngine::setImageResolution
310          */
311         private function setImageBackgroundColor () {
312                 // Call the image class
313                 $this->getImageInstance()->initBackgroundColor();
314
315                 // Current main node is background-color
316                 $this->currMainNode = 'background-color';
317         }
318
319         /**
320          * "Setter" for foreground-color. For more details see above method!
321          *
322          * @return      void
323          * @see         ImageTemplateEngine::setImageResolution
324          */
325         private function setImageForegroundColor () {
326                 // Call the image class
327                 $this->getImageInstance()->initForegroundColor();
328
329                 // Current main node is foreground-color
330                 $this->currMainNode = 'foreground-color';
331         }
332
333         /**
334          * "Setter" for image-string. For more details see above method!
335          *
336          * @param       $groupable      Whether this image string is groupable
337          * @return      void
338          * @see         ImageTemplateEngine::setImageResolution
339          */
340         private function setImageImageString ($groupable = 'single') {
341                 // Call the image class
342                 $this->getImageInstance()->initImageString($groupable);
343
344                 // Current main node is foreground-color
345                 $this->currMainNode = 'image-string';
346         }
347
348         /**
349          * Setter for image name
350          *
351          * @param       $imageName      Name of the image
352          * @return      void
353          */
354         private function setImagePropertyName ($imageName) {
355                 // Call the image class
356                 $this->getImageInstance()->setImageName($imageName);
357         }
358
359         /**
360          * Setter for image width
361          *
362          * @param       $width  Width of the image or variable
363          * @return      void
364          */
365         private function setImagePropertyWidth ($width) {
366                 // Call the image class
367                 $this->getImageInstance()->setWidth($width);
368         }
369
370         /**
371          * Setter for image height
372          *
373          * @param       $height Height of the image or variable
374          * @return      void
375          */
376         private function setImagePropertyHeight ($height) {
377                 // Call the image class
378                 $this->getImageInstance()->setHeight($height);
379         }
380
381         /**
382          * Setter for image red color
383          *
384          * @param       $red    Red color value
385          * @return      void
386          */
387         private function setImagePropertyRed ($red) {
388                 // Call the image class
389                 $this->getImageInstance()->setRed($red);
390         }
391
392         /**
393          * Setter for image green color
394          *
395          * @param       $green  Green color value
396          * @return      void
397          */
398         private function setImagePropertyGreen ($green) {
399                 // Call the image class
400                 $this->getImageInstance()->setGreen($green);
401         }
402
403         /**
404          * Setter for image blue color
405          *
406          * @param       $blue   Blue color value
407          * @return      void
408          */
409         private function setImagePropertyBlue ($blue) {
410                 // Call the image class
411                 $this->getImageInstance()->setBlue($blue);
412         }
413
414         /**
415          * Setter for string name (identifier)
416          *
417          * @param       $stringName             String name (identifier)
418          * @return      void
419          */
420         private function setImagePropertyStringName ($stringName) {
421                 // Call the image class
422                 $this->getImageInstance()->setStringName($stringName);
423         }
424
425         /**
426          * Setter for font size
427          *
428          * @param       $fontSize       Size of the font
429          * @return      void
430          */
431         private function setImagePropertyFontSize ($fontSize) {
432                 // Call the image class
433                 $this->getImageInstance()->setFontSize($fontSize);
434         }
435
436         /**
437          * Setter for image string
438          *
439          * @param       $imageString    Image string to set
440          * @return      void
441          */
442         private function setImagePropertyText ($imageString) {
443                 // Call the image class
444                 $this->getImageInstance()->setString($imageString);
445         }
446
447         /**
448          * Setter for X coordinate
449          *
450          * @param       $x      X coordinate
451          * @return      void
452          */
453         private function setImagePropertyX ($x) {
454                 // Call the image class
455                 $this->getImageInstance()->setX($x);
456         }
457
458         /**
459          * Setter for Y coordinate
460          *
461          * @param       $y      Y coordinate
462          * @return      void
463          */
464         private function setImagePropertyY ($y) {
465                 // Call the image class
466                 $this->getImageInstance()->setY($y);
467         }
468
469         /**
470          * Getter for image cache file (FQFN)
471          *
472          * @return      $fqfn   Full-qualified file name of the image cache
473          */
474         public function getImageCacheFqfn () {
475                 // Get the FQFN ready
476                 $fqfn = sprintf('%s%s%s/%s.%s',
477                         $this->getConfigInstance()->getConfigEntry('base_path'),
478                         $this->getGenericBasePath(),
479                         'images/_cache',
480                         md5(
481                                 $this->getImageInstance()->getImageName() . ':' . $this->__toString() . ':' . $this->getImageInstance()->__toString()
482                         ),
483                         $this->getImageInstance()->getImageType()
484                 );
485
486                 // Return it
487                 return $fqfn;
488         }
489
490         /**
491          * Outputs the image to the world
492          *
493          * @param       $responseInstance       An instance of a Responseable class
494          * @return      void
495          */
496         public function transferToResponse (Responseable $responseInstance) {
497                 // Set the image instance
498                 $responseInstance->setImageInstance($this->getImageInstance());
499         }
500
501         /**
502          * Load a specified image template into the engine
503          *
504          * @param       $template       The image template we shall load which is
505          *                                              located in 'image' by default
506          * @return      void
507          */
508         public function loadImageTemplate ($template) {
509                 // Set template type
510                 $this->setTemplateType($this->getConfigInstance()->getConfigEntry('image_template_type'));
511
512                 // Load the special template
513                 $this->loadTemplate($template);
514         }
515
516 }