* @copyright Copyright (c) 2013 - 2019, TechFuze. (http://techfuze.net) */ class Models { use ComponentPathsTrait; /** * Get a model. * * Supply the name and the model will be loaded from the supplied directory, * or from one of the modelPaths (which you can add). * * @param string $modelName Name of the model * @param array $modelPaths Alternative paths to use to load the model * @param string $namespace Alternative namespace for the model. Defaults to \Application\Model * @param mixed %arguments,... Arguments to be provided to the constructor [...] * @return Model * @throws NotFoundException * @throws ModelException */ public function get(string $modelName, array $modelPaths = [], string $namespace = '\Application\Model\\'): Model { if (empty($modelName)) throw new ModelException("Could not load model. No name provided", 1); // First get the directories where the model can be located $modelPaths = (empty($modelPaths) ? $this->componentPaths : [3 => $modelPaths]); // Get arguments for constructor if (func_num_args() > 3) $arguments = array_slice(func_get_args(), 3); else $arguments = []; // Fire a model load event /** @var ModelGetEvent $event */ try { $event = Events::fireEvent('modelGetEvent', $modelName, $modelPaths, $namespace, $arguments); } catch (EventException $e) { throw new ModelException("Could not load model. modelGetEvent threw exception: '".$e->getMessage()."'"); } // If the event is cancelled, stop loading if ($event->isCancelled()) throw new ModelException("Could not load model. Model cancelled by modelGetEvent."); // And attempt to load the model return $this->loadModel($event->modelName, $event->modelPaths, $event->namespace, $event->arguments); } /** * Load and return a model. * * Supply the name and the model will be loaded from one of the supplied directories * * @param string $modelName Name of the model * @param array $modelPaths * @param string $namespace * @param array $arguments * @return Model The Model object * @throws ModelException * @throws NotFoundException */ protected function loadModel(string $modelName, array $modelPaths, string $namespace, array $arguments): Model { // Now figure out the className and subdir $class = trim($modelName, '/'); if (($last_slash = strrpos($class, '/')) !== FALSE) { // Extract the path $subdir = substr($class, 0, ++$last_slash); // Get the filename from the path $class = substr($class, $last_slash); } else { $subdir = ''; } // If the class already exists, return a new instance directly $class = ucfirst($class); $className = $namespace . $class . 'Model'; if (class_exists($className, false)) { $model = new $className(...$arguments); if (!$model instanceof Model) throw new ModelException("Could not load model. Provided modelName is not instance of \FuzeWorks\Model"); return $model; } // Search for the model file for ($i=Priority::getHighestPriority(); $i<=Priority::getLowestPriority(); $i++) { if (!isset($modelPaths[$i])) continue; foreach ($modelPaths[$i] as $directory) { // Determine the file $file = $directory . DS . $subdir . "model." . strtolower($class) . '.php'; // If it doesn't, try and load the file if (file_exists($file)) { include_once($file); // Test if provided class is instance of Model $model = new $className(...$arguments); if (!$model instanceof Model) throw new ModelException("Could not load model. Provided modelName is not instance of \FuzeWorks\Model"); return $model; } } } // Maybe it's in a subdirectory with the same name as the class if ($subdir === '') { return $this->loadModel($class . "/" . $class, $modelPaths, $namespace, $arguments); } throw new NotFoundException("Could not load model. Model was not found", 1); } }