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: */
15: namespace Cake\Datasource;
16:
17: use Cake\Datasource\Exception\MissingModelException;
18: use 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: */
27: trait 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: *
162: * @return $this
163: */
164: public function setModelType($modelType)
165: {
166: $this->_modelType = $modelType;
167:
168: return $this;
169: }
170:
171: /**
172: * Set or get the model type to be used by this class
173: *
174: * @deprecated 3.5.0 Use getModelType()/setModelType() instead.
175: * @param string|null $modelType The model type or null to retrieve the current
176: *
177: * @return string|$this
178: */
179: public function modelType($modelType = null)
180: {
181: deprecationWarning(
182: get_called_class() . '::modelType() is deprecated. ' .
183: 'Use setModelType()/getModelType() instead.'
184: );
185: if ($modelType === null) {
186: return $this->_modelType;
187: }
188:
189: $this->_modelType = $modelType;
190:
191: return $this;
192: }
193: }
194: