Initial import of current development status
[shipsimu.git] / ship-simu / application / selector / class_ApplicationSelector.php
1 <?php
2 /**
3  * The application selector class.
4  *
5  * Please remember that this include file is being loaded *before* the class
6  * loader is loading classes from "exceptions", "interfaces" and "main"!
7  *
8  * @todo        Extend a later BaseFrameworkApplication class
9  *
10  * @author     Roland Haeder <roland __NOSPAM__ [at] __REMOVE_ME__ mxchange [dot] org>
11  * @version    0.1
12  */
13 class ApplicationSelector extends BaseFrameworkSystem {
14         /**
15          * An ArrayObject for all found applications
16          */
17         private $foundApps = null;
18
19         /**
20          * An array object for all loaded application templates (selector_app-name.tpl)
21          */
22         private $loadedTemplates = null;
23
24         /**
25          * The application selector's own template engine handler
26          */
27         private $selectorTplEngine = null;
28
29         /**
30          * A list of items we shall ignore while reading from directories
31          */
32         private $dirIgnoreList = array(
33                 ".",
34                 "..",
35                 ".htaccess"
36         );
37
38         /**
39          * The language instance for the template loader
40          */
41         private $langInstance = null;
42
43         /**
44          * The file I/O instance for the template loader
45          */
46         private $fileIOInstance = null;
47
48         /**
49          * The private constructor. No direct instances can be created from this.
50          *
51          * @return      void
52          */
53         private function __construct() {
54                 // Call parent constructor
55                 parent::constructor(__CLASS__);
56
57                 // Set description
58                 $this->setPartDescr("Applikationswechsler");
59
60                 // Create unique ID number
61                 $this->createUniqueID();
62
63                 // Remove system array and thousand seperator
64                 $this->removeSystemArray();
65                 $this->removeNumberFormaters();
66
67                 // Initialize the array lists
68                 $this->initializeAppsList();
69                 $this->initializeTemplatesList();
70         }
71
72         /**
73          * Create a prepared instance of ApplicationSelector
74          *
75          * @param               $langInstance           The language sub-system: LanguageSystem
76          * @param               $fileIOInstance The file I/O instance
77          * @return      $selInstance            An instance of ApplicationSelector
78          */
79         public static function createApplicationSelector ($langInstance, $fileIOInstance) {
80                 // Get a new instance
81                 $selInstance = new ApplicationSelector();
82
83                 // Get all applications
84                 $selInstance->readApplicationDirectory();
85
86                 // Set language and file I/O instances
87                 $selInstance->setLanguageInstance($langInstance);
88                 $selInstance->setFileIOInstance($fileIOInstance);
89
90                 // Return the prepared instance
91                 return $selInstance;
92         }
93
94         /**
95          * Initialize the application list
96          *
97          * @return      void
98          */
99         private function initializeAppsList () {
100                 $this->foundApps = new FrameworkArrayObject();
101         }
102
103         /**
104          * Initialize the loaded templates list
105          *
106          * @return      void
107          */
108         private function initializeTemplatesList () {
109                 $this->loadedTemplates = new FrameworkArrayObject();
110         }
111
112         /**
113          * Private getter for language instance
114          *
115          * @return      $langInstance   An instance to the language sub-system
116          */
117         private function getLanguageInstance () {
118                 return $this->langInstance;
119         }
120
121         /**
122          * Private getter for file IO instance
123          *
124          * @return      $fileIOInstance An instance to the file I/O sub-system
125          */
126         private function getFileIOInstance () {
127                 return $this->fileIOInstance;
128         }
129
130         /**
131          * Prepare the template engine (TemplateEngine by default) for a give
132          * application helper instance (ApplicationHelper by default).
133          *
134          * @param               $appInstance    An application helper instance
135          * @return      $tplEngine      The template engine instance
136          * @throws      NullPointerException    If the template engine could not
137          *                                                              be initialized
138          * @throws      NoObjectException               If $tplEngine is not an object
139          * @throws      MissingMethodException  If $tplEngine misses a required
140          *                                                              method 'loadWebTemplate()'
141          */
142         private function prepareTemplateEngine ($appInstance) {
143                 // Generate FQFN for all application templates
144                 $fqfn = sprintf("%s%s/%s/%s",
145                         PATH,
146                         $this->getConfigInstance()->readConfig("application_path"),
147                         strtolower($appInstance->getAppShortName()),
148                         $this->getConfigInstance()->readConfig("tpl_base_path")
149                 );
150
151                 // Initialize the template engine
152                 $tplEngine = null;
153                 $eval = sprintf("\$tplEngine = %s::create%s(
154         \"%s\",
155         \$this->getLanguageInstance(),
156         \$this->getFileIOInstance()
157 );",
158                         $this->getConfigInstance()->readConfig("tpl_engine"),
159                         $this->getConfigInstance()->readConfig("tpl_engine"),
160                         $fqfn
161                 );
162
163                 // Debug message
164                 if ((!is_null($this->getDebugInstance())) && (defined('DEBUG_EVAL'))) {
165                         $this->getDebugInstance()->output(sprintf("[%s:] Konstruierte PHP-Anweisung: <pre><em>%s</em></pre><br />\n",
166                                 $this->__toString(),
167                                 htmlentities($eval)
168                         ));
169                 }
170
171                 // Run the command
172                 @eval($eval);
173
174                 // Is it a valid instance?
175                 if (is_null($tplEngine)) {
176                         // No class returned
177                         throw new NullPointerException($this, self::EXCEPTION_IS_NULL_POINTER);
178                 } elseif (!is_object($tplEngine)) {
179                         // Not an object! ;-(
180                         throw new NoObjectException($tplEngine, self::EXCEPTION_IS_NO_OBJECT);
181                 } elseif (!method_exists($tplEngine, 'loadWebTemplate')) {
182                         // Nope, so throw exception
183                         throw new MissingMethodException(array($tplEngine, 'loadWebTemplate'), self::EXCEPTION_MISSING_METHOD);
184                 }
185
186                 // Return the prepared instance
187                 return $tplEngine;
188         }
189
190         /**
191          * Load the init.php script of an application and append the application
192          * instance to $foundApps
193          *
194          * @param               $initScript     The FQFN of init.php
195          * @param               $appName                The application's Uni* name
196          * @return      void
197          * @throws      AppVarIsNotSetException If 'app' is not set
198          * @throws      NullPointerException    If 'app' is null
199          * @throws      NoObjectException               If 'app' is not an object
200          * @throws      MissingMethodException  If a required method is missing
201          */
202         private function loadInitScript ($initScript, $appName) {
203                 // Is it a file and readable?
204                 if ((is_file($initScript)) && (is_readable($initScript))) {
205                         // Then include it
206                         include ($initScript);
207
208                         // We now should have $app re-defined!
209                         if (!isset($app)) {
210                                 // This application shall not be loaded
211                                 return;
212                         } elseif (is_null($app)) {
213                                 // The class instance is null
214                                 throw new NullPointerException($this, self::EXCEPTION_IS_NULL_POINTER);
215                         } elseif (!is_object($app)) {
216                                 // Not an object
217                                 throw new NoObjectException($app, self::EXCEPTION_IS_NO_OBJECT);
218                         } elseif (!method_exists($app, $this->getConfigInstance()->readConfig("entry_method"))) {
219                                 // Method not found!
220                                 throw new MissingMethodException(array($app, $this->getConfigInstance()->readConfig("entry_method")), self::EXCEPTION_MISSING_METHOD);
221                         }
222
223                         // Add the current instance to the list
224                         $this->foundApps->append($app);
225
226                 } // END - if ((is_file(...
227         }
228
229         /**
230          * Setter for the selector's template engine instance
231          *
232          * @param               $tplEngine      An instance of TemplateEngine
233          */
234         private function setSelectorTemplateEngine ($tplEngine) {
235                 $this->selectorTplEngine = $tplEngine;
236         }
237
238         /**
239          * Getter for the selector's template engine instance
240          *
241          * @return      $selectTplEngine        The selector's template engine
242          */
243         private function getSelectorTemplateEngine () {
244                 return $this->selectorTplEngine;
245         }
246
247         /**
248          * Getter for the $loadedTemplates array object
249          *
250          * @return      $loadedTemplates        An array object holding all loaded
251          *                                                      application templates
252          */
253         private function getLoadedTemplates () {
254                 return $this->loadedTemplates;
255         }
256
257         /**
258          * Method for compatiblity with prepareTemplateEngine()
259          *
260          * @return      $shortName      This selector's short name
261          */
262         private function getAppShortName() {
263                 $shortName = $this->getConfigInstance()->readConfig("selector_path");
264                 return $shortName;
265         }
266
267         /**
268          * Add a directory/file to the ignore list
269          *
270          * @param               $ignoreItem     The file/directory we shall ignore
271          * @return      void
272          */
273         public function addDirIgnoreList ($ignoreItem) {
274                 // Cast and add it
275                 $ignoreItem = (string) $ignoreItem;
276                 $this->dirIgnoreList[] = $ignoreItem;
277         }
278         
279         /**
280          * Setter for language instance
281          *
282          * @param               $langInstance   An instance to the language sub-system
283          * @return      void
284          * @see         LanguageSystem
285          */
286         public function setLanguageInstance (ManageableLanguage $langInstance) {
287                 $this->langInstance = $langInstance;
288         }
289
290         /**
291          * Setter for file I/O instance
292          *
293          * @param               $fileIOInstance An instance to the file I/O sub-system
294          * @return      void
295          */
296         public function setFileIOInstance (FileIOHandler $fileIOInstance) {
297                 $this->fileIOInstance = $fileIOInstance;
298         }
299
300         /**
301          * Read the base path for all applications (application/) and create a
302          * list of all found applications
303          *
304          * @return      void
305          */
306         public function readApplicationDirectory () {
307                 // Generate the base path for all applications
308                 $appBasePath = sprintf("%s%s/",
309                         PATH,
310                         $this->getConfigInstance()->readConfig("application_path")
311                 );
312
313                 // Add the selector path to the ignore list
314                 $this->addDirIgnoreList($this->getConfigInstance()->readConfig("selector_path"));
315
316                 // Get a directory pointer for the application path
317                 $dirInstance = FrameworkDirectoryPointer::createFrameworkDirectoryPointer($appBasePath);
318
319                 // Backup and remove the 'app' from global name space
320                 /*$appBackup = $app;
321                 unset($app);*/
322
323                 // Read all directories&files except some parts
324                 while ($appName = $dirInstance->readDirectoryExcept($this->dirIgnoreList)) {
325                         // Generate FQFN for the application name (or better directory name)
326                         $fqfn = sprintf("%s%s", $appBasePath, $appName);
327
328                         // Is this a readable directory? (files will be ignored silently)
329                         if ((is_dir($fqfn)) && (is_readable($fqfn))) {
330                                 // Then get the init.php script for analyzing
331                                 $initScript = sprintf("%s/init%s", $fqfn, $this->getConfigInstance()->readConfig("php_extension"));
332
333                                 // Load the application's init.php script and append the
334                                 // application to the ArrayObject
335                                 $this->loadInitScript($initScript, $appName);
336
337                         } // END - if ((is_dir(...
338
339                 } // END - while
340
341                 // Close directory pointer
342                 $dirInstance->closeDirectory();
343
344                 // Restore old 'app' from backup
345                 //$app = $appBackup;
346         }
347
348         /**
349          * Load all templates for found applications in previous scan
350          *
351          * @return      void
352          */
353         public function loadApplicationTemplates () {
354                 // Iterate through all applications
355                 for ($idx = $this->foundApps->getIterator(); $idx->valid(); $idx->next()) {
356                         // Get current application
357                         $appInstance = $idx->current();
358
359                         // Prepare the template engine for the current template
360                         $tplEngine = $this->prepareTemplateEngine($appInstance);
361
362                         // Try to load the web template
363                         $tplEngine->loadWebTemplate(sprintf("%s_%s",
364                                 $this->getConfigInstance()->readConfig("tpl_selector_prefix"),
365                                 strtolower($appInstance->getAppShortName())
366                         ));
367
368                         // Remember this template and the application for later usage
369                         $this->loadedTemplates->append(array(
370                                 'tpl_engine'   => $tplEngine,
371                                 'app_instance' => $appInstance
372                         ));
373                 }
374
375                 // Re-initialize the application list to avoid double loading
376                 $this->initializeAppsList();
377         }
378
379         /**
380          * Removes $dirIgnoreList from the object to save some memory
381          *
382          * @return      void
383          */
384         public function removeDirIgnoreList () {
385                 unset($this->dirIgnoreList);
386         }
387
388         /**
389          * Loads the selector's own main template. This step is not linking the
390          * application's templates into the main one.
391          *
392          * @return      void
393          */
394         public function loadSelectorTemplate () {
395                 // Prepare the template engine
396                 $tplEngine = $this->prepareTemplateEngine($this);
397
398                 // Load the selector's template
399                 $tplEngine->loadCodeTemplate($this->getConfigInstance()->readConfig("selector_main_tpl"));
400
401                 // Now store it in the class
402                 $this->setSelectorTemplateEngine($tplEngine);
403         }
404
405         /**
406          * Inserts all loaded application templates into the selector's template
407          *
408          * @return      void
409          * @throws      NullPointerException            If $curr is null
410          * @throws      NoArrayException                        If $curr is not an array
411          * @throws      InvalidArrayCountException      If $curr contains an
412          *                                                                      unexpected count of elements
413          * @throws      MissingArrayElementsException   If $curr is missing expected
414          *                                                                      array elements
415          */
416         public function insertApplicationTemplates () {
417                 // First prepare the instance
418                 $tplEngine = $this->prepareTemplateEngine($this);
419
420                 // Load template which shall later hold all application templates
421                 $tplEngine->loadCodeTemplate($this->getConfigInstance()->readConfig("selector_apps_tpl"));
422
423                 // Add all loaded application templates together
424                 $dummy = "";
425                 for ($idx = $this->getLoadedTemplates()->getIterator(); $idx->valid(); $idx->next()) {
426                         // Get current item from array object
427                         $curr = $idx->current();
428
429                         // Do some sanity checks on the loaded item
430                         if (is_null($curr)) {
431                                 // $curr is null
432                                 throw new NullPointerException($this, self::EXCEPTION_IS_NULL_POINTER);
433                         } elseif (!is_array($curr)) {
434                                 // Not an array
435                                 throw new NoArrayException($curr, self::EXCEPTION_IS_NO_ARRAY);
436                         } elseif (count($curr) != 2) {
437                                 // Not expected count of entries
438                                 throw new InvalidArrayCountException(array($this, "curr", count($curr), 2), self::EXCEPTION_ARRAY_HAS_INVALID_COUNT);
439                         } elseif (!isset($curr['tpl_engine']) || (!isset($curr['app_instance']))) {
440                                 // Expected entries missing
441                                 throw new MissingArrayElementsException(array($this, "curr", array('tpl_engine', 'app_instance')), self::EXCEPTION_ARRAY_ELEMENTS_MISSING);
442                         }
443                         die("<pre>".print_r($curr, true)."</pre>");
444
445                 } // END - for
446         }
447
448         /**
449          * Stub!
450          */
451         public function saveObjectToDatabase () {
452                 $this->getDebugInstance()->output(sprintf("[%s:] Stub <strong>%s</strong> erreicht.",
453                         $this->__toString(),
454                         __FUNCTION__
455                 ));
456         }
457 }
458
459 // [EOF]
460 ?>