Also check on existence.
[core.git] / inc / loader / class_ClassLoader.php
index 4b46ffa801f5e09e629cba3453051b23dcbc0300..11683c49963afd05d9d79552cdba9fe0b8a956d1 100644 (file)
@@ -2,11 +2,11 @@
 /**
  * This class loads class include files with a specific prefix and suffix
  *
- * @author             Roland Haeder <webmaster@ship-simu.org>
+ * @author             Roland Haeder <webmaster@shipsimu.org>
  * @version            0.0.0
- * @copyright  Copyright (c) 2007, 2008 Roland Haeder, 2009 - 2012 Core Developer Team
+ * @copyright  Copyright (c) 2007, 2008 Roland Haeder, 2009 - 2015 Core Developer Team
  * @license            GNU GPL 3.0 or any newer version
- * @link               http://www.ship-simu.org
+ * @link               http://www.shipsimu.org
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -69,19 +69,19 @@ class ClassLoader {
        private $ignoreList = array();
 
        /**
-        * Debug this class loader? (true = yes, false = no)
+        * Debug this class loader? (TRUE = yes, FALSE = no)
         */
-       private $debug = false;
+       private $debug = FALSE;
 
        /**
         * Whether the file list is cached
         */
-       private $listCached = false;
+       private $listCached = FALSE;
 
        /**
         * Wethe class content has been cached
         */
-       private $classesCached = false;
+       private $classesCached = FALSE;
 
        /**
         * Filename for the list cache
@@ -98,6 +98,17 @@ class ClassLoader {
         */
        private $total = 0;
 
+       /**
+        * Framework/application paths for classes, etc.
+        */
+       private static $frameworkPaths = array(
+               'exceptions', // Exceptions
+               'interfaces', // Interfaces
+               'main',       // General main classes
+               'middleware'  // The middleware
+       );
+
+
        /**
         * The protected constructor. Please use the factory method below, or use
         * getSelfInstance() for singleton
@@ -120,14 +131,14 @@ class ClassLoader {
                } // END - if
 
                // Skip here if already cached
-               if ($this->listCached === false) {
+               if ($this->listCached === FALSE) {
                        // Writes the cache file of our list away
-                       $cacheContent = serialize($this->classes);
+                       $cacheContent = json_encode($this->classes);
                        file_put_contents($this->listCacheFQFN, $cacheContent);
                } // END - if
 
                // Skip here if already cached
-               if ($this->classesCached === false) {
+               if ($this->classesCached === FALSE) {
                        // Generate a full-cache of all classes
                        $cacheContent = '';
                        foreach ($this->loadedClasses as $fqfn) {
@@ -157,6 +168,44 @@ class ClassLoader {
                return $loaderInstance;
        }
 
+       /**
+        * Scans for all framework classes, exceptions and interfaces.
+        *
+        * @return      void
+        */
+       public static function scanFrameworkClasses () {
+               // Cache loader instance
+               $loaderInstance = self::getSelfInstance();
+
+               // Load all classes
+               foreach (self::$frameworkPaths as $className) {
+                       // Try to load the framework classes
+                       $loaderInstance->scanClassPath('inc/classes/' . $className . '/');
+               } // END - foreach
+       }
+
+       /**
+        * Scans for application's classes, etc.
+        *
+        * @return      void
+        */
+       public static function scanApplicationClasses () {
+               // Get config instance
+               $cfg = FrameworkConfiguration::getSelfInstance();
+
+               // Load all classes for the application
+               foreach (self::$frameworkPaths as $class) {
+                       // Create path name
+                       $path = sprintf('%s/%s/%s', $cfg->getConfigEntry('application_path'), $cfg->getConfigEntry('app_name'), $class);
+
+                       // Is the path readable?
+                       if (is_dir($path)) {
+                               // Try to load the application classes
+                               ClassLoader::getSelfInstance()->scanClassPath($path);
+                       } // END - if
+               } // END - foreach
+       }
+
        /**
         * Initializes our loader class
         *
@@ -186,24 +235,24 @@ class ClassLoader {
                } // END - if
 
                // IS the cache there?
-               if (file_exists($this->listCacheFQFN)) {
+               if (BaseFrameworkSystem::isReadableFile($this->listCacheFQFN)) {
                        // Get content
                        $cacheContent = file_get_contents($this->listCacheFQFN);
 
                        // And convert it
-                       $this->classes = unserialize($cacheContent);
+                       $this->classes = json_decode($cacheContent);
 
                        // List has been restored from cache!
-                       $this->listCached = true;
+                       $this->listCached = TRUE;
                } // END - if
 
                // Does the class cache exist?
-               if (file_exists($this->classCacheFQFN)) {
+               if (BaseFrameworkSystem::isReadableFile($this->listCacheFQFN)) {
                        // Then include it
                        require($this->classCacheFQFN);
 
                        // Mark the class cache as loaded
-                       $this->classesCached = true;
+                       $this->classesCached = TRUE;
                } // END - if
        }
 
@@ -215,6 +264,7 @@ class ClassLoader {
         */
        public static function autoLoad ($className) {
                // Try to include this class
+               //* NOISY-DEBUG: */ printf('[%s:%d] className=%s' . PHP_EOL, __METHOD__, __LINE__, $className);
                self::getSelfInstance()->includeClass($className);
        }
 
@@ -243,59 +293,76 @@ class ClassLoader {
         */
        public function scanClassPath ($basePath, array $ignoreList = array() ) {
                // Is a list has been restored from cache, don't read it again
-               if ($this->listCached === true) {
+               if ($this->listCached === TRUE) {
                        // Abort here
                        return;
                } // END - if
 
-               /*
-                * Directories which this class loader ignores by default while
-                * scanning the whole directory structure starting from given base
-                * path.
-                */
-               $ignoreList[] = '.';
-               $ignoreList[] = '..';
-               $ignoreList[] = '.htaccess';
-               $ignoreList[] = '.svn';
-
                // Keep it in class for later usage
                $this->ignoreList = $ignoreList;
 
                /*
-                * Set base directory which holds all our classes, we should use an
-                * absolute path here so is_dir(), is_file() and so on will always
+                * Ignore .htaccess by default as it is for protection of directories
+                * on Apache servers.
+                */
+               array_push($ignoreList, '.htaccess');
+
+               /*
+                * Set base directory which holds all our classes, an absolute path
+                * should be used here so is_dir(), is_file() and so on will always
                 * find the correct files and dirs.
                 */
                $basePath2 = realpath($basePath);
 
-               // If the basePath is false it is invalid
-               if ($basePath2 === false) {
-                       /* @todo: Do not die here. */
-                       die(__METHOD__ . ':Cannot read ' . $basePath . ' !');
+               // If the basePath is FALSE it is invalid
+               if ($basePath2 === FALSE) {
+                       /* @TODO: Do not exit here. */
+                       exit(__METHOD__ . ': Cannot read ' . $basePath . ' !' . PHP_EOL);
                } else {
                        // Set base path
                        $basePath = $basePath2;
                }
 
                // Get a new iterator
-               //* DEBUG: */ echo "<strong>Base path: {$basePath}</strong><br />\n";
-               $iterator = new RecursiveDirectoryIterator($basePath);
-               $recursive = new RecursiveIteratorIterator($iterator);
-               foreach ($recursive as $entry) {
+               //* NOISY-DEBUG: */ printf('[%s:%d] basePath=%s' . PHP_EOL, __METHOD__, __LINE__, $basePath);
+               $iteratorInstance = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($basePath), RecursiveIteratorIterator::CHILD_FIRST);
+
+               // Load all entries
+               while ($iteratorInstance->valid()) {
+                       // Get current entry
+                       $currentEntry = $iteratorInstance->current();
+
                        // Get filename from iterator
-                       $fileName = $entry->getFileName();
+                       $fileName = $currentEntry->getFileName();
 
-                       // Get the FQFN and add it to our class list
-                       $fqfn = $entry->getRealPath();
+                       // Get the "FQFN" (path and file name)
+                       $fqfn = $currentEntry->getRealPath();
+
+                       // Current entry must be a file, not smaller than 100 bytes and not on ignore list 
+                       if ((!$currentEntry->isFile()) || (in_array($fileName, $this->ignoreList)) || (filesize($fqfn) < 100)) {
+                               // Advance to next entry
+                               $iteratorInstance->next();
+
+                               // Skip non-file entries
+                               //* NOISY-DEBUG: */ printf('[%s:%d] SKIP: %s' . PHP_EOL, __METHOD__, __LINE__, $fileName);
+                               continue;
+                       } // END - if
 
                        // Is this file wanted?
-                       //* DEBUG: */ echo "FOUND:{$fileName}<br />\n";
-                       if ((!in_array($fileName, $this->ignoreList)) && (filesize($fqfn) > 100) && (substr($fileName, 0, strlen($this->prefix)) == $this->prefix) && (substr($fileName, -strlen($this->suffix), strlen($this->suffix)) == $this->suffix)) {
-                               //* DEBUG: */ echo "ADD: {$fileName}<br />\n";
+                       //* NOISY-DEBUG: */ printf('[%s:%d] FOUND: %s' . PHP_EOL, __METHOD__, __LINE__, $fileName);
+                       if ((substr($fileName, 0, strlen($this->prefix)) == $this->prefix) && (substr($fileName, -strlen($this->suffix), strlen($this->suffix)) == $this->suffix)) {
                                // Add it to the list
+                               //* NOISY-DEBUG: */ printf('[%s:%d] ADD: %s,fqfn=%s' . PHP_EOL, __METHOD__, __LINE__, $fileName, $fqfn);
                                $this->classes[$fileName] = $fqfn;
-                       } // END - if
-               } // END - foreach
+                       } else {
+                               // Not added
+                               //* NOISY-DEBUG: */ printf('[%s:%d] NOT ADDED: %s,fqfn=%s' . PHP_EOL, __METHOD__, __LINE__, $fileName, $fqfn);
+                       }
+
+                       // Advance to next entry
+                       //* NOISY-DEBUG: */ printf('[%s:%d] NEXT: %s' . PHP_EOL, __METHOD__, __LINE__, $fileName);
+                       $iteratorInstance->next();
+               } // END - while
        }
 
        /**
@@ -328,7 +395,7 @@ class ClassLoader {
         * missing classes or interfaces. So if you use class_exists() this method
         * does not interrupt your program.
         *
-        * @param       $className      The class we shall load
+        * @param       $className      The class that shall be loaded
         * @return      void
         */
        public function includeClass ($className) {
@@ -336,27 +403,33 @@ class ClassLoader {
                $fileName = $this->prefix . $className . $this->suffix;
 
                // Now look it up in our index
+               //* NOISY-DEBUG: */ printf('[%s:%d] ISSET: %s' . PHP_EOL, __METHOD__, __LINE__, $fileName);
                if ((isset($this->classes[$fileName])) && (!in_array($this->classes[$fileName], $this->loadedClasses))) {
                        // File is found and not loaded so load it only once
-                       //* DEBUG: */ echo "LOAD: ".$fileName." - Start<br />\n";
+                       //* NOISY-DEBUG: */ printf('[%s:%d] LOAD: %s - START' . PHP_EOL, __METHOD__, __LINE__, $fileName);
                        require($this->classes[$fileName]);
-                       //* DEBUG: */ echo "LOAD: ".$fileName." - End<br />\n";
+                       //* NOISY-DEBUG: */ printf('[%s:%d] LOAD: %s - END' . PHP_EOL, __METHOD__, __LINE__, $fileName);
 
-                       // Count this include
+                       // Count this loaded class/interface/exception
                        $this->total++;
 
-                       // Mark this class as loaded
-                       $this->loadedClasses[] = $this->classes[$fileName];
+                       // Mark this class as loaded for other purposes than loading it.
+                       array_push($this->loadedClasses, $this->classes[$fileName]);
 
-                       // Remove it from classes list
+                       // Remove it from classes list so it won't be found twice.
+                       //* NOISY-DEBUG: */ printf('[%s:%d] UNSET: %s' . PHP_EOL, __METHOD__, __LINE__, $fileName);
                        unset($this->classes[$fileName]);
 
                        // Developer mode excludes caching (better debugging)
                        if (!defined('DEVELOPER')) {
                                // Reset cache
-                               $this->classesCached = false;
+                               //* NOISY-DEBUG: */ printf('[%s:%d] classesCached=FALSE' . PHP_EOL, __METHOD__, __LINE__);
+                               $this->classesCached = FALSE;
                        } // END - if
-               } // END - if
+               } else {
+                       // Not found
+                       //* NOISY-DEBUG: */ printf('[%s:%d] 404: %s' . PHP_EOL, __METHOD__, __LINE__, $fileName);
+               }
        }
 
        /**
@@ -373,6 +446,7 @@ class ClassLoader {
                                require($fqfn);
 
                                // Remove it from the list
+                               //* NOISY-DEBUG: */ printf('[%s:%d] UNSET: %s' . PHP_EOL, __METHOD__, __LINE__, $fileName);
                                unset($this->classes[$fileName]);
                        } // END - if
                } // END - foreach
@@ -396,7 +470,7 @@ class ClassLoader {
                // Prepare the list
                $includeList = '';
                foreach ($this->loadedClasses as $classFile) {
-                       $includeList .= basename($classFile)."<br />\n";
+                       $includeList .= basename($classFile) . '<br />' . PHP_EOL;
                } // END - foreach
 
                // And return it