1<?php 2/** 3 * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) 4 * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) 5 * 6 * Licensed under The MIT License 7 * For full copyright and license information, please see the LICENSE.txt 8 * Redistributions of files must retain the above copyright notice. 9 * 10 * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) 11 * @link https://cakephp.org CakePHP(tm) Project 12 * @since 3.0.0 13 * @license https://opensource.org/licenses/mit-license.php MIT License 14 */ 15namespace Cake\Datasource; 16 17use Cake\Datasource\Exception\MissingModelException; 18use UnexpectedValueException; 19 20/** 21 * Provides functionality for loading table classes 22 * and other repositories onto properties of the host object. 23 * 24 * Example users of this trait are Cake\Controller\Controller and 25 * Cake\Console\Shell. 26 */ 27trait ModelAwareTrait 28{ 29 /** 30 * This object's primary model class name. Should be a plural form. 31 * CakePHP will not inflect the name. 32 * 33 * Example: For an object named 'Comments', the modelClass would be 'Comments'. 34 * Plugin classes should use `Plugin.Comments` style names to correctly load 35 * models from the correct plugin. 36 * 37 * Use false to not use auto-loading on this object. Null auto-detects based on 38 * controller name. 39 * 40 * @var string|false|null 41 */ 42 public $modelClass; 43 44 /** 45 * A list of overridden model factory functions. 46 * 47 * @var array 48 */ 49 protected $_modelFactories = []; 50 51 /** 52 * The model type to use. 53 * 54 * @var string 55 */ 56 protected $_modelType = 'Table'; 57 58 /** 59 * Set the modelClass and modelKey properties based on conventions. 60 * 61 * If the properties are already set they will not be overwritten 62 * 63 * @param string $name Class name. 64 * @return void 65 */ 66 protected function _setModelClass($name) 67 { 68 if ($this->modelClass === null) { 69 $this->modelClass = $name; 70 } 71 } 72 73 /** 74 * Loads and constructs repository objects required by this object 75 * 76 * Typically used to load ORM Table objects as required. Can 77 * also be used to load other types of repository objects your application uses. 78 * 79 * If a repository provider does not return an object a MissingModelException will 80 * be thrown. 81 * 82 * @param string|null $modelClass Name of model class to load. Defaults to $this->modelClass. 83 * The name can be an alias like `'Post'` or FQCN like `App\Model\Table\PostsTable::class`. 84 * @param string|null $modelType The type of repository to load. Defaults to the modelType() value. 85 * @return \Cake\Datasource\RepositoryInterface The model instance created. 86 * @throws \Cake\Datasource\Exception\MissingModelException If the model class cannot be found. 87 * @throws \InvalidArgumentException When using a type that has not been registered. 88 * @throws \UnexpectedValueException If no model type has been defined 89 */ 90 public function loadModel($modelClass = null, $modelType = null) 91 { 92 if ($modelClass === null) { 93 $modelClass = $this->modelClass; 94 } 95 if ($modelType === null) { 96 $modelType = $this->getModelType(); 97 98 if ($modelType === null) { 99 throw new UnexpectedValueException('No model type has been defined'); 100 } 101 } 102 103 $alias = null; 104 $options = []; 105 if (strpos($modelClass, '\\') === false) { 106 list(, $alias) = pluginSplit($modelClass, true); 107 } else { 108 $options['className'] = $modelClass; 109 $alias = substr( 110 $modelClass, 111 strrpos($modelClass, '\\') + 1, 112 -strlen($modelType) 113 ); 114 $modelClass = $alias; 115 } 116 117 if (isset($this->{$alias})) { 118 return $this->{$alias}; 119 } 120 121 if (isset($this->_modelFactories[$modelType])) { 122 $factory = $this->_modelFactories[$modelType]; 123 } 124 if (!isset($factory)) { 125 $factory = FactoryLocator::get($modelType); 126 } 127 $this->{$alias} = $factory($modelClass, $options); 128 if (!$this->{$alias}) { 129 throw new MissingModelException([$modelClass, $modelType]); 130 } 131 132 return $this->{$alias}; 133 } 134 135 /** 136 * Override a existing callable to generate repositories of a given type. 137 * 138 * @param string $type The name of the repository type the factory function is for. 139 * @param callable $factory The factory function used to create instances. 140 * @return void 141 */ 142 public function modelFactory($type, callable $factory) 143 { 144 $this->_modelFactories[$type] = $factory; 145 } 146 147 /** 148 * Get the model type to be used by this class 149 * 150 * @return string 151 */ 152 public function getModelType() 153 { 154 return $this->_modelType; 155 } 156 157 /** 158 * Set the model type to be used by this class 159 * 160 * @param string $modelType The model type 161 * @return $this 162 */ 163 public function setModelType($modelType) 164 { 165 $this->_modelType = $modelType; 166 167 return $this; 168 } 169 170 /** 171 * Set or get the model type to be used by this class 172 * 173 * @deprecated 3.5.0 Use getModelType()/setModelType() instead. 174 * @param string|null $modelType The model type or null to retrieve the current 175 * @return string|$this 176 */ 177 public function modelType($modelType = null) 178 { 179 deprecationWarning( 180 get_called_class() . '::modelType() is deprecated. ' . 181 'Use setModelType()/getModelType() instead.' 182 ); 183 if ($modelType === null) { 184 return $this->_modelType; 185 } 186 187 $this->_modelType = $modelType; 188 189 return $this; 190 } 191} 192