pictcode / lib / Cake / Model / Behavior / ContainableBehavior.php @ f4a6dc2c
履歴 | 表示 | アノテート | ダウンロード (14.132 KB)
| 1 | 635eef61 | spyder1211 | <?php
 | 
      
|---|---|---|---|
| 2 | /**
 | 
      ||
| 3 |  * Behavior for binding management.
 | 
      ||
| 4 |  *
 | 
      ||
| 5 |  * Behavior to simplify manipulating a model's bindings when doing a find operation
 | 
      ||
| 6 |  *
 | 
      ||
| 7 |  * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
 | 
      ||
| 8 |  * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
 | 
      ||
| 9 |  *
 | 
      ||
| 10 |  * Licensed under The MIT License
 | 
      ||
| 11 |  * For full copyright and license information, please see the LICENSE.txt
 | 
      ||
| 12 |  * Redistributions of files must retain the above copyright notice.
 | 
      ||
| 13 |  *
 | 
      ||
| 14 |  * @copyright     Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
 | 
      ||
| 15 |  * @link          http://cakephp.org CakePHP(tm) Project
 | 
      ||
| 16 |  * @package       Cake.Model.Behavior
 | 
      ||
| 17 |  * @since         CakePHP(tm) v 1.2.0.5669
 | 
      ||
| 18 |  * @license       http://www.opensource.org/licenses/mit-license.php MIT License
 | 
      ||
| 19 |  */
 | 
      ||
| 20 | |||
| 21 | App::uses('ModelBehavior', 'Model');  | 
      ||
| 22 | |||
| 23 | /**
 | 
      ||
| 24 |  * Behavior to allow for dynamic and atomic manipulation of a Model's associations
 | 
      ||
| 25 |  * used for a find call. Most useful for limiting the amount of associations and
 | 
      ||
| 26 |  * data returned.
 | 
      ||
| 27 |  *
 | 
      ||
| 28 |  * @package       Cake.Model.Behavior
 | 
      ||
| 29 |  * @link http://book.cakephp.org/2.0/en/core-libraries/behaviors/containable.html
 | 
      ||
| 30 |  */
 | 
      ||
| 31 | class ContainableBehavior extends ModelBehavior {  | 
      ||
| 32 | |||
| 33 | /**
 | 
      ||
| 34 |  * Types of relationships available for models
 | 
      ||
| 35 |  *
 | 
      ||
| 36 |  * @var array
 | 
      ||
| 37 |  */
 | 
      ||
| 38 | public $types = array('belongsTo', 'hasOne', 'hasMany', 'hasAndBelongsToMany');  | 
      ||
| 39 | |||
| 40 | /**
 | 
      ||
| 41 |  * Runtime configuration for this behavior
 | 
      ||
| 42 |  *
 | 
      ||
| 43 |  * @var array
 | 
      ||
| 44 |  */
 | 
      ||
| 45 | public $runtime = array();  | 
      ||
| 46 | |||
| 47 | /**
 | 
      ||
| 48 |  * Initiate behavior for the model using specified settings.
 | 
      ||
| 49 |  *
 | 
      ||
| 50 |  * Available settings:
 | 
      ||
| 51 |  *
 | 
      ||
| 52 |  * - recursive: (boolean, optional) set to true to allow containable to automatically
 | 
      ||
| 53 |  *   determine the recursiveness level needed to fetch specified models,
 | 
      ||
| 54 |  *   and set the model recursiveness to this level. setting it to false
 | 
      ||
| 55 |  *   disables this feature. DEFAULTS TO: true
 | 
      ||
| 56 |  * - notices: (boolean, optional) issues E_NOTICES for bindings referenced in a
 | 
      ||
| 57 |  *   containable call that are not valid. DEFAULTS TO: true
 | 
      ||
| 58 |  * - autoFields: (boolean, optional) auto-add needed fields to fetch requested
 | 
      ||
| 59 |  *   bindings. DEFAULTS TO: true
 | 
      ||
| 60 |  *
 | 
      ||
| 61 |  * @param Model $Model Model using the behavior
 | 
      ||
| 62 |  * @param array $settings Settings to override for model.
 | 
      ||
| 63 |  * @return void
 | 
      ||
| 64 |  */
 | 
      ||
| 65 | public function setup(Model $Model, $settings = array()) {  | 
      ||
| 66 | if (!isset($this->settings[$Model->alias])) {  | 
      ||
| 67 | $this->settings[$Model->alias] = array('recursive' => true, 'notices' => true, 'autoFields' => true);  | 
      ||
| 68 | }  | 
      ||
| 69 | $this->settings[$Model->alias] = array_merge($this->settings[$Model->alias], $settings);  | 
      ||
| 70 | }  | 
      ||
| 71 | |||
| 72 | /**
 | 
      ||
| 73 |  * Runs before a find() operation. Used to allow 'contain' setting
 | 
      ||
| 74 |  * as part of the find call, like this:
 | 
      ||
| 75 |  *
 | 
      ||
| 76 |  * `Model->find('all', array('contain' => array('Model1', 'Model2')));`
 | 
      ||
| 77 |  *
 | 
      ||
| 78 |  * ```
 | 
      ||
| 79 |  * Model->find('all', array('contain' => array(
 | 
      ||
| 80 |  *         'Model1' => array('Model11', 'Model12'),
 | 
      ||
| 81 |  *         'Model2',
 | 
      ||
| 82 |  *         'Model3' => array(
 | 
      ||
| 83 |  *                 'Model31' => 'Model311',
 | 
      ||
| 84 |  *                 'Model32',
 | 
      ||
| 85 |  *                 'Model33' => array('Model331', 'Model332')
 | 
      ||
| 86 |  * )));
 | 
      ||
| 87 |  * ```
 | 
      ||
| 88 |  *
 | 
      ||
| 89 |  * @param Model $Model Model using the behavior
 | 
      ||
| 90 |  * @param array $query Query parameters as set by cake
 | 
      ||
| 91 |  * @return array
 | 
      ||
| 92 |  */
 | 
      ||
| 93 | public function beforeFind(Model $Model, $query) {  | 
      ||
| 94 | $reset = (isset($query['reset']) ? $query['reset'] : true);  | 
      ||
| 95 | $noContain = false;  | 
      ||
| 96 | $contain = array();  | 
      ||
| 97 | |||
| 98 | if (isset($this->runtime[$Model->alias]['contain'])) {  | 
      ||
| 99 | $noContain = empty($this->runtime[$Model->alias]['contain']);  | 
      ||
| 100 | $contain = $this->runtime[$Model->alias]['contain'];  | 
      ||
| 101 | unset($this->runtime[$Model->alias]['contain']);  | 
      ||
| 102 | }  | 
      ||
| 103 | |||
| 104 | if (isset($query['contain'])) {  | 
      ||
| 105 | $noContain = $noContain || empty($query['contain']);  | 
      ||
| 106 | if ($query['contain'] !== false) {  | 
      ||
| 107 | $contain = array_merge($contain, (array)$query['contain']);  | 
      ||
| 108 | }  | 
      ||
| 109 | }  | 
      ||
| 110 | $noContain = $noContain && empty($contain);  | 
      ||
| 111 | |||
| 112 | if ($noContain || empty($contain)) {  | 
      ||
| 113 | if ($noContain) {  | 
      ||
| 114 | $query['recursive'] = -1;  | 
      ||
| 115 | }  | 
      ||
| 116 | return $query;  | 
      ||
| 117 | }  | 
      ||
| 118 | if ((isset($contain[0]) && is_bool($contain[0])) || is_bool(end($contain))) {  | 
      ||
| 119 | $reset = is_bool(end($contain))  | 
      ||
| 120 | ? array_pop($contain)  | 
      ||
| 121 | : array_shift($contain);  | 
      ||
| 122 | }  | 
      ||
| 123 | $containments = $this->containments($Model, $contain);  | 
      ||
| 124 | $map = $this->containmentsMap($containments);  | 
      ||
| 125 | |||
| 126 | $mandatory = array();  | 
      ||
| 127 | foreach ($containments['models'] as $model) {  | 
      ||
| 128 | $instance = $model['instance'];  | 
      ||
| 129 | $needed = $this->fieldDependencies($instance, $map, false);  | 
      ||
| 130 | if (!empty($needed)) {  | 
      ||
| 131 | $mandatory = array_merge($mandatory, $needed);  | 
      ||
| 132 | }  | 
      ||
| 133 | if ($contain) {  | 
      ||
| 134 | $backupBindings = array();  | 
      ||
| 135 | foreach ($this->types as $relation) {  | 
      ||
| 136 | if (!empty($instance->__backAssociation[$relation])) {  | 
      ||
| 137 | $backupBindings[$relation] = $instance->__backAssociation[$relation];  | 
      ||
| 138 |                                         } else {
 | 
      ||
| 139 | $backupBindings[$relation] = $instance->{$relation};  | 
      ||
| 140 | }  | 
      ||
| 141 | }  | 
      ||
| 142 | foreach ($this->types as $type) {  | 
      ||
| 143 | $unbind = array();  | 
      ||
| 144 | foreach ($instance->{$type} as $assoc => $options) {  | 
      ||
| 145 | if (!isset($model['keep'][$assoc])) {  | 
      ||
| 146 | $unbind[] = $assoc;  | 
      ||
| 147 | }  | 
      ||
| 148 | }  | 
      ||
| 149 | if (!empty($unbind)) {  | 
      ||
| 150 | if (!$reset && empty($instance->__backOriginalAssociation)) {  | 
      ||
| 151 | $instance->__backOriginalAssociation = $backupBindings;  | 
      ||
| 152 | }  | 
      ||
| 153 | $instance->unbindModel(array($type => $unbind), $reset);  | 
      ||
| 154 | }  | 
      ||
| 155 | foreach ($instance->{$type} as $assoc => $options) {  | 
      ||
| 156 | if (isset($model['keep'][$assoc]) && !empty($model['keep'][$assoc])) {  | 
      ||
| 157 | if (isset($model['keep'][$assoc]['fields'])) {  | 
      ||
| 158 | $model['keep'][$assoc]['fields'] = $this->fieldDependencies($containments['models'][$assoc]['instance'], $map, $model['keep'][$assoc]['fields']);  | 
      ||
| 159 | }  | 
      ||
| 160 | if (!$reset && empty($instance->__backOriginalAssociation)) {  | 
      ||
| 161 | $instance->__backOriginalAssociation = $backupBindings;  | 
      ||
| 162 | } elseif ($reset) {  | 
      ||
| 163 | $instance->__backAssociation[$type] = $backupBindings[$type];  | 
      ||
| 164 | }  | 
      ||
| 165 | $instance->{$type}[$assoc] = array_merge($instance->{$type}[$assoc], $model['keep'][$assoc]);  | 
      ||
| 166 | }  | 
      ||
| 167 | if (!$reset) {  | 
      ||
| 168 | $instance->__backInnerAssociation[] = $assoc;  | 
      ||
| 169 | }  | 
      ||
| 170 | }  | 
      ||
| 171 | }  | 
      ||
| 172 | }  | 
      ||
| 173 | }  | 
      ||
| 174 | |||
| 175 | if ($this->settings[$Model->alias]['recursive']) {  | 
      ||
| 176 | $query['recursive'] = (isset($query['recursive'])) ? max($query['recursive'], $containments['depth']) : $containments['depth'];  | 
      ||
| 177 | }  | 
      ||
| 178 | |||
| 179 | $autoFields = ($this->settings[$Model->alias]['autoFields']  | 
      ||
| 180 | && !in_array($Model->findQueryType, array('list', 'count'))  | 
      ||
| 181 | && !empty($query['fields']));  | 
      ||
| 182 | |||
| 183 | if (!$autoFields) {  | 
      ||
| 184 | return $query;  | 
      ||
| 185 | }  | 
      ||
| 186 | |||
| 187 | $query['fields'] = (array)$query['fields'];  | 
      ||
| 188 | foreach (array('hasOne', 'belongsTo') as $type) {  | 
      ||
| 189 | if (!empty($Model->{$type})) {  | 
      ||
| 190 | foreach ($Model->{$type} as $assoc => $data) {  | 
      ||
| 191 | if ($Model->useDbConfig === $Model->{$assoc}->useDbConfig && !empty($data['fields'])) {  | 
      ||
| 192 | foreach ((array)$data['fields'] as $field) {  | 
      ||
| 193 | $query['fields'][] = (strpos($field, '.') === false ? $assoc . '.' : '') . $field;  | 
      ||
| 194 | }  | 
      ||
| 195 | }  | 
      ||
| 196 | }  | 
      ||
| 197 | }  | 
      ||
| 198 | }  | 
      ||
| 199 | |||
| 200 | if (!empty($mandatory[$Model->alias])) {  | 
      ||
| 201 | foreach ($mandatory[$Model->alias] as $field) {  | 
      ||
| 202 | if ($field === '--primaryKey--') {  | 
      ||
| 203 | $field = $Model->primaryKey;  | 
      ||
| 204 | } elseif (preg_match('/^.+\.\-\-[^-]+\-\-$/', $field)) {  | 
      ||
| 205 | list($modelName, $field) = explode('.', $field);  | 
      ||
| 206 | if ($Model->useDbConfig === $Model->{$modelName}->useDbConfig) {  | 
      ||
| 207 | $field = $modelName . '.' . (  | 
      ||
| 208 | ($field === '--primaryKey--') ? $Model->$modelName->primaryKey : $field  | 
      ||
| 209 | );  | 
      ||
| 210 |                                         } else {
 | 
      ||
| 211 | $field = null;  | 
      ||
| 212 | }  | 
      ||
| 213 | }  | 
      ||
| 214 | if ($field !== null) {  | 
      ||
| 215 | $query['fields'][] = $field;  | 
      ||
| 216 | }  | 
      ||
| 217 | }  | 
      ||
| 218 | }  | 
      ||
| 219 | $query['fields'] = array_unique($query['fields']);  | 
      ||
| 220 | return $query;  | 
      ||
| 221 | }  | 
      ||
| 222 | |||
| 223 | /**
 | 
      ||
| 224 |  * Unbinds all relations from a model except the specified ones. Calling this function without
 | 
      ||
| 225 |  * parameters unbinds all related models.
 | 
      ||
| 226 |  *
 | 
      ||
| 227 |  * @param Model $Model Model on which binding restriction is being applied
 | 
      ||
| 228 |  * @return void
 | 
      ||
| 229 |  * @link http://book.cakephp.org/2.0/en/core-libraries/behaviors/containable.html#using-containable
 | 
      ||
| 230 |  */
 | 
      ||
| 231 | public function contain(Model $Model) {  | 
      ||
| 232 | $args = func_get_args();  | 
      ||
| 233 | $contain = call_user_func_array('am', array_slice($args, 1));  | 
      ||
| 234 | $this->runtime[$Model->alias]['contain'] = $contain;  | 
      ||
| 235 | }  | 
      ||
| 236 | |||
| 237 | /**
 | 
      ||
| 238 |  * Permanently restore the original binding settings of given model, useful
 | 
      ||
| 239 |  * for restoring the bindings after using 'reset' => false as part of the
 | 
      ||
| 240 |  * contain call.
 | 
      ||
| 241 |  *
 | 
      ||
| 242 |  * @param Model $Model Model on which to reset bindings
 | 
      ||
| 243 |  * @return void
 | 
      ||
| 244 |  */
 | 
      ||
| 245 | public function resetBindings(Model $Model) {  | 
      ||
| 246 | if (!empty($Model->__backOriginalAssociation)) {  | 
      ||
| 247 | $Model->__backAssociation = $Model->__backOriginalAssociation;  | 
      ||
| 248 | unset($Model->__backOriginalAssociation);  | 
      ||
| 249 | }  | 
      ||
| 250 |                 $Model->resetAssociations();
 | 
      ||
| 251 | if (!empty($Model->__backInnerAssociation)) {  | 
      ||
| 252 | $assocs = $Model->__backInnerAssociation;  | 
      ||
| 253 | $Model->__backInnerAssociation = array();  | 
      ||
| 254 | foreach ($assocs as $currentModel) {  | 
      ||
| 255 | $this->resetBindings($Model->$currentModel);  | 
      ||
| 256 | }  | 
      ||
| 257 | }  | 
      ||
| 258 | }  | 
      ||
| 259 | |||
| 260 | /**
 | 
      ||
| 261 |  * Process containments for model.
 | 
      ||
| 262 |  *
 | 
      ||
| 263 |  * @param Model $Model Model on which binding restriction is being applied
 | 
      ||
| 264 |  * @param array $contain Parameters to use for restricting this model
 | 
      ||
| 265 |  * @param array $containments Current set of containments
 | 
      ||
| 266 |  * @param bool $throwErrors Whether non-existent bindings show throw errors
 | 
      ||
| 267 |  * @return array Containments
 | 
      ||
| 268 |  */
 | 
      ||
| 269 | public function containments(Model $Model, $contain, $containments = array(), $throwErrors = null) {  | 
      ||
| 270 | $options = array('className', 'joinTable', 'with', 'foreignKey', 'associationForeignKey', 'conditions', 'fields', 'order', 'limit', 'offset', 'unique', 'finderQuery');  | 
      ||
| 271 | $keep = array();  | 
      ||
| 272 | if ($throwErrors === null) {  | 
      ||
| 273 | $throwErrors = (empty($this->settings[$Model->alias]) ? true : $this->settings[$Model->alias]['notices']);  | 
      ||
| 274 | }  | 
      ||
| 275 | foreach ((array)$contain as $name => $children) {  | 
      ||
| 276 | if (is_numeric($name)) {  | 
      ||
| 277 | $name = $children;  | 
      ||
| 278 | $children = array();  | 
      ||
| 279 | }  | 
      ||
| 280 | if (preg_match('/(?<!\.)\(/', $name)) {  | 
      ||
| 281 | $name = str_replace('(', '.(', $name);  | 
      ||
| 282 | }  | 
      ||
| 283 | if (strpos($name, '.') !== false) {  | 
      ||
| 284 | $chain = explode('.', $name);  | 
      ||
| 285 | $name = array_shift($chain);  | 
      ||
| 286 | $children = array(implode('.', $chain) => $children);  | 
      ||
| 287 | }  | 
      ||
| 288 | |||
| 289 | $children = (array)$children;  | 
      ||
| 290 | foreach ($children as $key => $val) {  | 
      ||
| 291 | if (is_string($key) && is_string($val) && !in_array($key, $options, true)) {  | 
      ||
| 292 | $children[$key] = (array)$val;  | 
      ||
| 293 | }  | 
      ||
| 294 | }  | 
      ||
| 295 | |||
| 296 | $keys = array_keys($children);  | 
      ||
| 297 | if ($keys && isset($children[0])) {  | 
      ||
| 298 | $keys = array_merge(array_values($children), $keys);  | 
      ||
| 299 | }  | 
      ||
| 300 | |||
| 301 | foreach ($keys as $i => $key) {  | 
      ||
| 302 | if (is_array($key)) {  | 
      ||
| 303 |                                         continue;
 | 
      ||
| 304 | }  | 
      ||
| 305 | $optionKey = in_array($key, $options, true);  | 
      ||
| 306 | if (!$optionKey && is_string($key) && preg_match('/^[a-z(]/', $key) && (!isset($Model->{$key}) || !is_object($Model->{$key}))) {  | 
      ||
| 307 | $option = 'fields';  | 
      ||
| 308 | $val = array($key);  | 
      ||
| 309 | if ($key{0} === '(') {  | 
      ||
| 310 | $val = preg_split('/\s*,\s*/', substr($key, 1, -1));  | 
      ||
| 311 | } elseif (preg_match('/ASC|DESC$/', $key)) {  | 
      ||
| 312 | $option = 'order';  | 
      ||
| 313 | $val = $Model->{$name}->alias . '.' . $key;  | 
      ||
| 314 | } elseif (preg_match('/[ =!]/', $key)) {  | 
      ||
| 315 | $option = 'conditions';  | 
      ||
| 316 | $val = $Model->{$name}->alias . '.' . $key;  | 
      ||
| 317 | }  | 
      ||
| 318 | $children[$option] = is_array($val) ? $val : array($val);  | 
      ||
| 319 | $newChildren = null;  | 
      ||
| 320 | if (!empty($name) && !empty($children[$key])) {  | 
      ||
| 321 | $newChildren = $children[$key];  | 
      ||
| 322 | }  | 
      ||
| 323 | unset($children[$key], $children[$i]);  | 
      ||
| 324 | $key = $option;  | 
      ||
| 325 | $optionKey = true;  | 
      ||
| 326 | if (!empty($newChildren)) {  | 
      ||
| 327 | $children = Hash::merge($children, $newChildren);  | 
      ||
| 328 | }  | 
      ||
| 329 | }  | 
      ||
| 330 | if ($optionKey && isset($children[$key])) {  | 
      ||
| 331 | if (!empty($keep[$name][$key]) && is_array($keep[$name][$key])) {  | 
      ||
| 332 | $keep[$name][$key] = array_merge((isset($keep[$name][$key]) ? $keep[$name][$key] : array()), (array)$children[$key]);  | 
      ||
| 333 |                                         } else {
 | 
      ||
| 334 | $keep[$name][$key] = $children[$key];  | 
      ||
| 335 | }  | 
      ||
| 336 | unset($children[$key]);  | 
      ||
| 337 | }  | 
      ||
| 338 | }  | 
      ||
| 339 | |||
| 340 | if (!isset($Model->{$name}) || !is_object($Model->{$name})) {  | 
      ||
| 341 | if ($throwErrors) {  | 
      ||
| 342 | trigger_error(__d('cake_dev', 'Model "%s" is not associated with model "%s"', $Model->alias, $name), E_USER_WARNING);  | 
      ||
| 343 | }  | 
      ||
| 344 |                                 continue;
 | 
      ||
| 345 | }  | 
      ||
| 346 | |||
| 347 | $containments = $this->containments($Model->{$name}, $children, $containments);  | 
      ||
| 348 | $depths[] = $containments['depth'] + 1;  | 
      ||
| 349 | if (!isset($keep[$name])) {  | 
      ||
| 350 | $keep[$name] = array();  | 
      ||
| 351 | }  | 
      ||
| 352 | }  | 
      ||
| 353 | |||
| 354 | if (!isset($containments['models'][$Model->alias])) {  | 
      ||
| 355 | $containments['models'][$Model->alias] = array('keep' => array(), 'instance' => &$Model);  | 
      ||
| 356 | }  | 
      ||
| 357 | |||
| 358 | $containments['models'][$Model->alias]['keep'] = array_merge($containments['models'][$Model->alias]['keep'], $keep);  | 
      ||
| 359 | $containments['depth'] = empty($depths) ? 0 : max($depths);  | 
      ||
| 360 | return $containments;  | 
      ||
| 361 | }  | 
      ||
| 362 | |||
| 363 | /**
 | 
      ||
| 364 |  * Calculate needed fields to fetch the required bindings for the given model.
 | 
      ||
| 365 |  *
 | 
      ||
| 366 |  * @param Model $Model Model
 | 
      ||
| 367 |  * @param array $map Map of relations for given model
 | 
      ||
| 368 |  * @param array|bool $fields If array, fields to initially load, if false use $Model as primary model
 | 
      ||
| 369 |  * @return array Fields
 | 
      ||
| 370 |  */
 | 
      ||
| 371 | public function fieldDependencies(Model $Model, $map, $fields = array()) {  | 
      ||
| 372 | if ($fields === false) {  | 
      ||
| 373 | foreach ($map as $parent => $children) {  | 
      ||
| 374 | foreach ($children as $type => $bindings) {  | 
      ||
| 375 | foreach ($bindings as $dependency) {  | 
      ||
| 376 | if ($type === 'hasAndBelongsToMany') {  | 
      ||
| 377 | $fields[$parent][] = '--primaryKey--';  | 
      ||
| 378 | } elseif ($type === 'belongsTo') {  | 
      ||
| 379 | $fields[$parent][] = $dependency . '.--primaryKey--';  | 
      ||
| 380 | }  | 
      ||
| 381 | }  | 
      ||
| 382 | }  | 
      ||
| 383 | }  | 
      ||
| 384 | return $fields;  | 
      ||
| 385 | }  | 
      ||
| 386 | if (empty($map[$Model->alias])) {  | 
      ||
| 387 | return $fields;  | 
      ||
| 388 | }  | 
      ||
| 389 | foreach ($map[$Model->alias] as $type => $bindings) {  | 
      ||
| 390 | foreach ($bindings as $dependency) {  | 
      ||
| 391 | $innerFields = array();  | 
      ||
| 392 | switch ($type) {  | 
      ||
| 393 | case 'belongsTo':  | 
      ||
| 394 | $fields[] = $Model->{$type}[$dependency]['foreignKey'];  | 
      ||
| 395 |                                                 break;
 | 
      ||
| 396 | case 'hasOne':  | 
      ||
| 397 | case 'hasMany':  | 
      ||
| 398 | $innerFields[] = $Model->$dependency->primaryKey;  | 
      ||
| 399 | $fields[] = $Model->primaryKey;  | 
      ||
| 400 |                                                 break;
 | 
      ||
| 401 | }  | 
      ||
| 402 | if (!empty($innerFields) && !empty($Model->{$type}[$dependency]['fields'])) {  | 
      ||
| 403 | $Model->{$type}[$dependency]['fields'] = array_unique(array_merge($Model->{$type}[$dependency]['fields'], $innerFields));  | 
      ||
| 404 | }  | 
      ||
| 405 | }  | 
      ||
| 406 | }  | 
      ||
| 407 | return array_unique($fields);  | 
      ||
| 408 | }  | 
      ||
| 409 | |||
| 410 | /**
 | 
      ||
| 411 |  * Build the map of containments
 | 
      ||
| 412 |  *
 | 
      ||
| 413 |  * @param array $containments Containments
 | 
      ||
| 414 |  * @return array Built containments
 | 
      ||
| 415 |  */
 | 
      ||
| 416 | public function containmentsMap($containments) {  | 
      ||
| 417 | $map = array();  | 
      ||
| 418 | foreach ($containments['models'] as $name => $model) {  | 
      ||
| 419 | $instance = $model['instance'];  | 
      ||
| 420 | foreach ($this->types as $type) {  | 
      ||
| 421 | foreach ($instance->{$type} as $assoc => $options) {  | 
      ||
| 422 | if (isset($model['keep'][$assoc])) {  | 
      ||
| 423 | $map[$name][$type] = isset($map[$name][$type]) ? array_merge($map[$name][$type], (array)$assoc) : (array)$assoc;  | 
      ||
| 424 | }  | 
      ||
| 425 | }  | 
      ||
| 426 | }  | 
      ||
| 427 | }  | 
      ||
| 428 | return $map;  | 
      ||
| 429 | }  | 
      ||
| 430 | |||
| 431 | }  |