layout; * * The Factory class allows the user to replace dependencies on the fly. It is possible for a class * to replace a dependency, like Logger, on the fly by calling the $factory->newInstance('Logger'); or the * $factory->setInstance('Logger', $object); This allows for creative ways to do dependency injection, or keep classes * separated. * * It is also possible to load a cloned instance of the Factory class, so that all properties are independant as well, * all to suit your very needs. * * The Factory class is also extendible. This allows classes that extend Factory to access all it's properties. * * @author TechFuze * @copyright Copyright (c) 2013 - 2019, TechFuze. (http://techfuze.net) */ class Factory { /** * The Factory instance that is shared by default when calling Factory::getInstance(); * * @var Factory Default shared instance */ private static $sharedFactoryInstance; /** * Whether to clone all Factory instances upon calling Factory::getInstance() * * @var bool Clone all Factory instances. */ protected static $cloneInstances = false; /** * Config Object * @var Config */ public $config; /** * Logger Object * @var Logger */ public $logger; /** * Events Object * @var Events */ public $events; /** * Libraries Object * @var Libraries */ public $libraries; /** * Helpers Object * @var Helpers */ public $helpers; /** * Plugins Object * @var Plugins */ public $plugins; /** * Factory instance constructor. Should only really be called once */ public function __construct() { // If there is no sharedFactoryInstance, prepare it if (is_null(self::$sharedFactoryInstance)) { // @codeCoverageIgnoreStart self::$sharedFactoryInstance = $this; $this->config = new Config(); $this->logger = new Logger(); $this->events = new Events(); $this->libraries = new Libraries(); $this->helpers = new Helpers(); $this->plugins = new Plugins(); return; } // @codeCoverageIgnoreEnd // Otherwise, copy the existing instances $x = self::getInstance(); foreach ($x as $key => $value) { $this->{$key} = $value; } return; } /** * Finalizes the Factory and sends out a coreStartEvent * * @return Factory * @throws CoreException */ public function init() { // Load the config file of the FuzeWorks core try { $cfg = $this->config->get('core'); } catch (Exception\ConfigException $e) { throw new CoreException("Could not initiate Factory. Config 'core 'could not be found."); } // Disable events if requested to do so if (!$cfg->enable_events) { Events::disable(); } // Initialize all components foreach ($this as $component) { if (method_exists($component, 'init')) $component->init(); } // Initialize all plugins $this->plugins->loadHeadersFromPluginPaths(); // And fire the coreStartEvent try { Events::fireEvent('coreStartEvent'); } catch (Exception\EventException $e) { throw new CoreException("Could not initiate Factory. coreStartEvent threw exception: ".$e->getMessage()); } return $this; } /** * Get a new instance of the Factory class. * * @param bool $cloneInstance Whether to get a cloned instance (true) or exactly the same instance (false) * @return Factory Instance */ public static function getInstance($cloneInstance = false): Factory { if ($cloneInstance === true || self::$cloneInstances === true) { return clone self::$sharedFactoryInstance; } return self::$sharedFactoryInstance; } /** * Enable cloning all Factory instances upon calling Factory::getInstance() * * @return void */ public static function enableCloneInstances() { self::$cloneInstances = true; } /** * Disable cloning all Factory instances upon calling Factory::getInstance() * * @return void */ public static function disableCloneInstances() { self::$cloneInstances = false; } /** * Create a new instance of one of the loaded classes. * It reloads the class. It does NOT clone it. * * @param string $className The name of the loaded class, WITHOUT the namespace * @param string $namespace Optional namespace. Defaults to 'FuzeWorks\' * @return Factory Instance * @throws FactoryException */ public function newInstance($className, $namespace = 'FuzeWorks\\'): self { // Determine the class to load $instanceName = strtolower($className); $className = $namespace.ucfirst($className); if (!isset($this->{$instanceName})) { throw new FactoryException("Could not load new instance of '".$instanceName."'. Instance was not found.", 1); } elseif (!class_exists($className, false)) { throw new FactoryException("Could not load new instance of '".$instanceName."'. Class not found.", 1); } // Remove the current instance unset($this->{$instanceName}); // And set the new one $this->{$instanceName} = new $className(); // Return itself return $this; } /** * Clone an instance of one of the loaded classes. * It clones the class. It does NOT re-create it. * * @param string $className The name of the loaded class, WITHOUT the namespace * @return Factory Instance * @throws FactoryException */ public function cloneInstance($className): self { // Determine the class to load $instanceName = strtolower($className); if (!isset($this->{$instanceName})) { throw new FactoryException("Could not clone instance of '".$instanceName."'. Instance was not found.", 1); } // Clone the instance $this->{$instanceName} = clone $this->{$instanceName}; // Return itself return $this; } /** * Set an instance of one of the loaded classes with your own $object. * Replace the existing class with one of your own. * * @param string $objectName The name of the loaded class, WITHOUT the namespace * @param mixed $object Object to replace the class with * @return Factory Instance */ public function setInstance($objectName, $object): self { // Determine the instance name $instanceName = strtolower($objectName); // Unset and set unset($this->{$instanceName}); $this->{$instanceName} = $object; // Return itself return $this; } /** * Remove an instance of one of the loaded classes. * * @param string $className The name of the loaded class, WITHOUT the namespace * @return Factory Factory Instance * @throws FactoryException */ public function removeInstance($className): self { // Determine the instance name $instanceName = strtolower($className); if (!isset($this->{$instanceName})) { throw new FactoryException("Could not remove instance of '".$instanceName."'. Instance was not found.", 1); } // Unset unset($this->{$instanceName}); // Return itself return $this; } /** * Returns true if component is part of this Factory. * * @param $componentName * @return bool */ public function instanceIsset($componentName) { return isset($this->{$componentName}); } }