*/ protected array $_modelFactories = []; /** * The model type to use. * * @var string */ protected string $_modelType = 'Table'; /** * Set the modelClass property based on conventions. * * If the property is already set it will not be overwritten * * @param string $name Class name. * @return void */ protected function _setModelClass(string $name): void { $this->modelClass ??= $name; } /** * Fetch or construct a model instance from a locator. * * Uses a modelFactory based on `$modelType` to fetch and construct a `RepositoryInterface` * and return it. The default `modelType` can be defined with `setModelType()`. * * Unlike `loadModel()` this method will *not* set an object property. * * If a repository provider does not return an object a MissingModelException will * be thrown. * * @param string|null $modelClass Name of model class to load. Defaults to $this->modelClass. * The name can be an alias like `'Post'` or FQCN like `App\Model\Table\PostsTable::class`. * @param string|null $modelType The type of repository to load. Defaults to the getModelType() value. * @return \Cake\Datasource\RepositoryInterface The model instance created. * @throws \Cake\Datasource\Exception\MissingModelException If the model class cannot be found. * @throws \UnexpectedValueException If $modelClass argument is not provided * and ModelAwareTrait::$modelClass property value is empty. */ public function fetchModel(?string $modelClass = null, ?string $modelType = null): RepositoryInterface { $modelClass ??= $this->modelClass; if (!$modelClass) { throw new UnexpectedValueException('Default modelClass is empty'); } $modelType ??= $this->getModelType(); $options = []; if (!str_contains($modelClass, '\\')) { [, $alias] = pluginSplit($modelClass, true); } else { $options['className'] = $modelClass; $alias = substr( $modelClass, strrpos($modelClass, '\\') + 1, -strlen($modelType), ); $modelClass = $alias; } $factory = $this->_modelFactories[$modelType] ?? FactoryLocator::get($modelType); if ($factory instanceof LocatorInterface) { $instance = $factory->get($modelClass, $options); } else { $instance = $factory($modelClass, $options); } if ($instance) { return $instance; } throw new MissingModelException([$modelClass, $modelType]); } /** * Override a existing callable to generate repositories of a given type. * * @param string $type The name of the repository type the factory function is for. * @param \Cake\Datasource\Locator\LocatorInterface|callable $factory The factory function used to create instances. * @return void */ public function modelFactory(string $type, LocatorInterface|callable $factory): void { $this->_modelFactories[$type] = $factory; } /** * Get the model type to be used by this class * * @return string */ public function getModelType(): string { return $this->_modelType; } /** * Set the model type to be used by this class * * @param string $modelType The model type * @return $this */ public function setModelType(string $modelType) { $this->_modelType = $modelType; return $this; } }