* @link https://TheTempusProject.com/libraries/Hermes * @license https://opensource.org/licenses/MIT [MIT LICENSE] */ namespace TheTempusProject\Hermes\Classes; class Autoloader { protected static $namespaces = []; protected $rootFolder = ''; /** * Automatically requires all the files within a given directory. * * @param {string} [$directory] * @param {bool} [$includeRoot] */ public function includeFolder( $directory = '', $includeRoot = true ) { $base_dir = str_replace( '\\', DIRECTORY_SEPARATOR, $directory ); $base_dir = str_replace( '/', DIRECTORY_SEPARATOR, $base_dir ); $base_dir = rtrim( $base_dir, DIRECTORY_SEPARATOR ) . DIRECTORY_SEPARATOR; // should require all the files in the specific folder if ( $includeRoot ) { $base_dir = $this->rootFolder . $base_dir; } if ( !is_dir( $base_dir ) ) { return false; } $files = scandir( $base_dir ); array_shift( $files ); array_shift( $files ); foreach ( $files as $key => $value ) { if ( stripos( $value, '.php' ) ) { include_once $base_dir . $value; } } return true; } /** * Adds a namespace and corresponding directory to the autoload list. * * @param {string} [$namespace] * @param {string} [$directory] * @param {bool} [$includeRoot] */ public function addNamespace( $namespace, $directory = '', $includeRoot = true ) { // normalize namespace prefix $prefix = trim( $namespace, '\\' ) . '\\'; // normalize directory $base_dir = str_replace( '\\', DIRECTORY_SEPARATOR, $directory ); $base_dir = str_replace( '/', DIRECTORY_SEPARATOR, $base_dir ); $base_dir = rtrim( $base_dir, DIRECTORY_SEPARATOR ) . DIRECTORY_SEPARATOR; if ( $base_dir === DIRECTORY_SEPARATOR ) { $base_dir = ''; } if ( empty( self::$namespaces[ $prefix ] ) ) { self::$namespaces[ $prefix ] = []; } // retain the base directory for the namespace prefix if ( $includeRoot ) { $base_dir = $this->rootFolder . $base_dir; } array_push( self::$namespaces[ $prefix ], $base_dir ); } /** * This is the main method for the autoloader. It will cycle through * possible locations and load the first available file. * * @param {string} [$class] */ public function loadClass( $class ) { $class = trim( $class, '\\' ); $namespace_array = explode( '\\', $class ); $class_name = array_pop( $namespace_array ); $namespace = implode( '\\', $namespace_array ) . '\\'; if ( empty( self::$namespaces[ $namespace ] ) ) { return false; } $file = convertClassNameToFileName( $class_name ); $possible_locations = []; foreach ( self::$namespaces[ $namespace ] as $key => $folder ) { if ( file_exists( $folder . $file ) ) { $possible_locations[] = $folder . $file; break; } elseif ( file_exists( $folder . ucfirst( $file ) ) ) { $possible_locations[] = $folder . ucfirst( $file ); break; } $newFile = ''; $exploded = explode( '_', $file ); foreach ( $exploded as &$value ) { $newFile .= ucfirst( $value ); } if ( file_exists( $folder . $newFile ) ) { $possible_locations[] = $folder . $newFile; break; } elseif ( file_exists( $folder . ucfirst( $newFile ) ) ) { $possible_locations[] = $folder . ucfirst( $newFile ); break; } } if ( !empty( $possible_locations ) ) { require_once $possible_locations[0]; return; } } /** * Tests the class to see if it can be loaded. * * @param {string} [$class] */ public static function testLoad( $class ) { $class = trim( $class, '\\' ); $namespace_array = explode( '\\', $class ); $class_name = array_pop( $namespace_array ); $namespace = implode( '\\', $namespace_array ) . '\\'; if ( class_exists( $class ) ) { return true; } if ( empty( self::$namespaces[ $namespace ] ) ) { return false; } $file = convertClassNameToFileName( $class_name ); $possible_locations = []; foreach ( self::$namespaces[ $namespace ] as $key => $folder ) { if ( file_exists( $folder . $file ) ) { $possible_locations[] = $folder . $file; } } if ( !empty( $possible_locations ) ) { return true; } return false; } /** * Sets the root folder for file paths. * * @param {string} [$folder] */ public function setRootFolder( $folder ) { $this->rootFolder = rtrim( $folder, DIRECTORY_SEPARATOR ) . DIRECTORY_SEPARATOR; } /** * Registers a new autoloader that should serve the currently defined namespaces. */ public function register() { spl_autoload_register( [ $this, 'loadClass' ] ); } /** * Retrieves the currently defined namespaces. */ public function getNamespaces() { return self::$namespaces; } /** * Retrieves the currently defined root folder. */ public function getRootFolder() { return $this->rootFolder; } }