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