Added new interfaces Handleable/-DataSet and ProtocolHandler (no content yet).
[core.git] / inc / loader / class_ClassLoader.php
index e15f52d4b65f6eb79fa2b60a6762404e7ff4b7e2..53ee90c3d1045ffd9e8d1aea18d5719e880e4032 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 - 2009 Roland Haeder, this is free software
+ * @copyright  Copyright (c) 2007, 2008 Roland Haeder, 2009 - 2014 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
  * along with this program. If not, see <http://www.gnu.org/licenses/>.
  *
  * ----------------------------------
+ * 1.4
+ *  - Some comments improved, other minor improvements
+ * 1.3
+ *  - Constructor is now empty and factory method 'createClassLoader' is created
+ *  - renamed loadClasses to scanClassPath
+ *  - Added initLoader()
  * 1.2
  *  - ClassLoader rewritten to PHP SPL's own RecursiveIteratorIterator class
  * 1.1
@@ -34,12 +40,7 @@ class ClassLoader {
        /**
         * Instance of this class
         */
-       private static $selfInstance = null;
-
-       /**
-        * Configuration array
-        */
-       private $cfg = array();
+       private static $selfInstance = NULL;
 
        /**
         * Array with all classes
@@ -54,22 +55,12 @@ class ClassLoader {
        /**
         * Suffix with extension for all class files
         */
-       private $prefix = "class_";
+       private $prefix = 'class_';
 
        /**
         * Suffix with extension for all class files
         */
-       private $suffix = ".php";
-
-       /**
-        * Length of the suffix. Will be overwritten later.
-        */
-       private $suffixLen = 0;
-
-       /**
-        * Length of the prefix. Will be overwritten later.
-        */
-       private $prefixLen = 0;
+       private $suffix = '.php';
 
        /**
         * A list for directory names (no leading/trailing slashes!) which not be scanned by the path scanner
@@ -78,29 +69,29 @@ 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;
 
        /**
-        * Wether the file list is cached or not
+        * 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
         */
-       private $listCacheFQFN = "";
+       private $listCacheFQFN = '';
 
        /**
         * Cache for class content
         */
-       private $classCacheFQFN = "";
+       private $classCacheFQFN = '';
 
        /**
         * Counter for loaded include files
@@ -108,34 +99,140 @@ class ClassLoader {
        private $total = 0;
 
        /**
-        * The *public* constructor
+        * 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
+        *
+        * @return      void
+        */
+       protected function __construct () {
+               // Is currently empty
+       }
+
+       /**
+        * The destructor makes it sure all caches got flushed
+        *
+        * @return      void
+        */
+       public function __destruct () {
+               // Skip here if dev-mode
+               if (defined('DEVELOPER')) {
+                       return;
+               } // END - if
+
+               // Skip here if already cached
+               if ($this->listCached === FALSE) {
+                       // Writes the cache file of our list away
+                       $cacheContent = serialize($this->classes);
+                       file_put_contents($this->listCacheFQFN, $cacheContent);
+               } // END - if
+
+               // Skip here if already cached
+               if ($this->classesCached === FALSE) {
+                       // Generate a full-cache of all classes
+                       $cacheContent = '';
+                       foreach ($this->loadedClasses as $fqfn) {
+                               // Load the file
+                               $cacheContent .= file_get_contents($fqfn);
+                       } // END - foreach
+
+                       // And write it away
+                       file_put_contents($this->classCacheFQFN, $cacheContent);
+               } // END - if
+       }
+
+       /**
+        * Creates an instance of this class loader for given configuration instance
+        *
+        * @param       $configInstance         Configuration class instance
+        * @return      void
+        */
+       public static final function createClassLoader (FrameworkConfiguration $configInstance) {
+               // Get a new instance
+               $loaderInstance = new ClassLoader();
+
+               // Init the instance
+               $loaderInstance->initLoader($configInstance);
+
+               // Return the prepared instance
+               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.
         *
-        * @param               $cfgInstance            Configuration class instance
         * @return      void
         */
-       public function __construct (FrameworkConfiguration $cfgInstance) {
+       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
+        *
+        * @param       $configInstance Configuration class instance
+        * @return      void
+        */
+       protected function initLoader (FrameworkConfiguration $configInstance) {
                // Set configuration instance
-               $this->cfgInstance = $cfgInstance;
+               $this->configInstance = $configInstance;
 
                // Construct the FQFN for the cache
                if (!defined('DEVELOPER')) {
-                       $this->listCacheFQFN  = $this->cfgInstance->readConfig('local_db_path') . "list-" . $this->cfgInstance->readConfig('app_name') . ".cache";
-                       $this->classCacheFQFN = $this->cfgInstance->readConfig('local_db_path') . "class-" . $this->cfgInstance->readConfig('app_name') . ".cache";
+                       $this->listCacheFQFN  = $this->configInstance->getConfigEntry('local_db_path') . 'list-' . $this->configInstance->getConfigEntry('app_name') . '.cache';
+                       $this->classCacheFQFN = $this->configInstance->getConfigEntry('local_db_path') . 'class-' . $this->configInstance->getConfigEntry('app_name') . '.cache';
                } // END - if
 
                // Set suffix and prefix from configuration
-               $this->suffix = $cfgInstance->readConfig('class_suffix');
-               $this->prefix = $cfgInstance->readConfig('class_prefix');
-
-               // Estimate length of prefix and suffix for substr() function (cache)
-               $this->suffixLen = strlen($this->suffix);
-               $this->prefixLen = strlen($this->prefix);
+               $this->suffix = $configInstance->getConfigEntry('class_suffix');
+               $this->prefix = $configInstance->getConfigEntry('class_prefix');
 
                // Set own instance
                self::$selfInstance = $this;
 
                // Skip here if no dev-mode
-               if (defined('DEVELOPER')) return;
+               if (defined('DEVELOPER')) {
+                       return;
+               } // END - if
 
                // IS the cache there?
                if (file_exists($this->listCacheFQFN)) {
@@ -146,7 +243,7 @@ class ClassLoader {
                        $this->classes = unserialize($cacheContent);
 
                        // List has been restored from cache!
-                       $this->listCached = true;
+                       $this->listCached = TRUE;
                } // END - if
 
                // Does the class cache exist?
@@ -155,50 +252,31 @@ class ClassLoader {
                        require($this->classCacheFQFN);
 
                        // Mark the class cache as loaded
-                       $this->classesCached = true;
+                       $this->classesCached = TRUE;
                } // END - if
        }
 
        /**
-        * The destructor makes it sure all caches got flushed
+        * Autoload-function
         *
+        * @param       $className      Name of the class to load
         * @return      void
         */
-       public function __destruct () {
-               // Skip here if dev-mode
-               if (defined('DEVELOPER')) return;
-
-               // Skip here if already cached
-               if ($this->listCached === false) {
-                       // Writes the cache file of our list away
-                       $cacheContent = serialize($this->classes);
-                       file_put_contents($this->listCacheFQFN, $cacheContent);
-               } // END - if
-
-               // Skip here if already cached
-               if ($this->classesCached === false) {
-                       // Generate a full-cache of all classes
-                       $cacheContent = "";
-                       foreach ($this->loadedClasses as $fqfn) {
-                               // Load the file
-                               $cacheContent .= file_get_contents($fqfn);
-                       } // END - foreach
-
-                       // And write it away
-                       file_put_contents($this->classCacheFQFN, $cacheContent);
-               } // END - if
+       public static function autoLoad ($className) {
+               // Try to include this class
+               self::getSelfInstance()->includeClass($className);
        }
 
        /**
-        * Getter for an instance of this class
+        * Singleton getter for an instance of this class
         *
-        * @return      $selfInstance           An instance of this class
+        * @return      $selfInstance   A singleton instance of this class
         */
-       public final static function getInstance () {
+       public static final function getSelfInstance () {
                // Is the instance there?
                if (is_null(self::$selfInstance)) {
                        // Get a new one
-                       self::$selfInstance = new ClassLoader(FrameworkConfiguration::getInstance());
+                       self::$selfInstance = ClassLoader::createClassLoader(FrameworkConfiguration::getSelfInstance());
                } // END - if
 
                // Return the instance
@@ -212,32 +290,36 @@ class ClassLoader {
         * @param       $ignoreList             An optional list (array forced) of directory and file names which shall be ignored
         * @return      void
         */
-       public function loadClasses ($basePath, array $ignoreList = array() ) {
+       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 our class loader ignores by default while
-               // deep-scanning the directory structure.
-               $ignoreList[] = ".";
-               $ignoreList[] = "..";
-               $ignoreList[] = ".htaccess";
-               $ignoreList[] = ".svn";
+               /*
+                * Directories which this class loader ignores by default while
+                * scanning the whole directory structure starting from given base
+                * path.
+                */
+               array_push($ignoreList, '.');
+               array_push($ignoreList, '..');
+               array_push($ignoreList, '.htaccess');
 
                // 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
-               // find the correct files and dirs.
+               /*
+                * 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
+                * find the correct files and dirs.
+                */
                $basePath2 = realpath($basePath);
 
-               // If the basePath is false it is invalid
-               if ($basePath2 === false) {
+               // If the basePath is FALSE it is invalid
+               if ($basePath2 === FALSE) {
                        /* @todo: Do not die here. */
-                       die("Cannot read {$basePath} !");
+                       exit(__METHOD__ . ':Cannot read ' . $basePath . ' !' . PHP_EOL);
                } else {
                        // Set base path
                        $basePath = $basePath2;
@@ -245,18 +327,20 @@ class ClassLoader {
 
                // 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) {
+               $iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($basePath));
+
+               foreach ($iterator as $entry) {
                        // Get filename from iterator
                        $fileName = $entry->getFileName();
 
+                       // Get the FQFN and add it to our class list
+                       $fqfn = $entry->getRealPath();
+
                        // Is this file wanted?
                        //* DEBUG: */ echo "FOUND:{$fileName}<br />\n";
-                       if ((!in_array($fileName, $this->ignoreList)) && (substr($fileName, 0, $this->prefixLen) == $this->prefix) && (substr($fileName, -$this->suffixLen, $this->suffixLen) == $this->suffix)) {
-                               // Get the FQFN and add it to our class list
-                               $fqfn = $entry->getRealPath();
+                       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";
+                               // Add it to the list
                                $this->classes[$fileName] = $fqfn;
                        } // END - if
                } // END - foreach
@@ -272,22 +356,19 @@ class ClassLoader {
                $oldPrefix = $this->prefix;
 
                // Set new prefix (temporary!)
-               $this->prefix = "config-";
-               $this->prefixLen = strlen($this->prefix);
+               $this->prefix = 'config-';
 
                // Set base directory
-               $basePath = sprintf("%sinc/config/", $this->cfgInstance->readConfig('base_path'));
+               $basePath = $this->configInstance->getConfigEntry('base_path') . 'inc/config/';
 
                // Load all classes from the config directory
-               $this->loadClasses($basePath);
+               $this->scanClassPath($basePath);
 
                // Include these extra configs now
                $this->includeExtraConfigs();
 
-               // Set the prefix back
+               // Set back the old prefix
                $this->prefix = $oldPrefix;
-               $this->prefixLen = strlen($this->prefix);
-
        }
 
        /**
@@ -313,7 +394,7 @@ class ClassLoader {
                        $this->total++;
 
                        // Mark this class as loaded
-                       $this->loadedClasses[] = $this->classes[$fileName];
+                       array_push($this->loadedClasses, $this->classes[$fileName]);
 
                        // Remove it from classes list
                        unset($this->classes[$fileName]);
@@ -321,7 +402,7 @@ class ClassLoader {
                        // Developer mode excludes caching (better debugging)
                        if (!defined('DEVELOPER')) {
                                // Reset cache
-                               $this->classesCached = false;
+                               $this->classesCached = FALSE;
                        } // END - if
                } // END - if
        }
@@ -335,7 +416,7 @@ class ClassLoader {
                // Run through all class names (should not be much)
                foreach ($this->classes as $fileName => $fqfn) {
                        // Is this a config?
-                       if (substr($fileName, 0, $this->prefixLen) == $this->prefix) {
+                       if (substr($fileName, 0, strlen($this->prefix)) == $this->prefix) {
                                // Then include it
                                require($fqfn);
 
@@ -361,9 +442,9 @@ class ClassLoader {
         */
        public function getPrintableIncludeList () {
                // Prepare the list
-               $includeList = "";
+               $includeList = '';
                foreach ($this->loadedClasses as $classFile) {
-                       $includeList .= basename($classFile)."<br />\n";
+                       $includeList .= basename($classFile) . '<br />' . PHP_EOL;
                } // END - foreach
 
                // And return it