CakePHP
  • Documentation
    • Book
    • API
    • Videos
    • Reporting Security Issues
    • Privacy Policy
    • Logos & Trademarks
  • Business Solutions
  • Swag
  • Road Trip
  • Team
  • Community
    • Community
    • Get Involved
    • Issues (GitHub)
    • Bakery
    • Featured Resources
    • Training
    • Meetups
    • My CakePHP
    • CakeFest
    • Newsletter
    • Linkedin
    • YouTube
    • Facebook
    • Twitter
    • Mastodon
    • Help & Support
    • Forum
    • Stack Overflow
    • Slack
    • Paid Support
CakePHP

C CakePHP 1.3 API

  • Overview
  • Tree
  • Deprecated
  • Version:
    • 1.3
      • 4.2
      • 4.1
      • 4.0
      • 3.9
      • 3.8
      • 3.7
      • 3.6
      • 3.5
      • 3.4
      • 3.3
      • 3.2
      • 3.1
      • 3.0
      • 2.10
      • 2.9
      • 2.8
      • 2.7
      • 2.6
      • 2.5
      • 2.4
      • 2.3
      • 2.2
      • 2.1
      • 2.0
      • 1.3
      • 1.2

Classes

  • AclBase
  • AclBehavior
  • AclComponent
  • AclNode
  • AclShell
  • Aco
  • AcoAction
  • AjaxHelper
  • ApcEngine
  • ApiShell
  • App
  • AppController
  • AppHelper
  • AppModel
  • Aro
  • AuthComponent
  • BakeShell
  • BakeTask
  • BehaviorCollection
  • Cache
  • CacheEngine
  • CacheHelper
  • CakeErrorController
  • CakeLog
  • CakeRoute
  • CakeSchema
  • CakeSession
  • CakeSocket
  • ClassRegistry
  • Component
  • Configure
  • ConnectionManager
  • ConsoleShell
  • ContainableBehavior
  • Controller
  • ControllerTask
  • CookieComponent
  • DataSource
  • DbAcl
  • DbConfigTask
  • DboMssql
  • DboMysql
  • DboMysqlBase
  • DboMysqli
  • DboOracle
  • DboPostgres
  • DboSource
  • DboSqlite
  • Debugger
  • EmailComponent
  • ErrorHandler
  • ExtractTask
  • File
  • FileEngine
  • FileLog
  • FixtureTask
  • Folder
  • FormHelper
  • Helper
  • HtmlHelper
  • HttpSocket
  • I18n
  • I18nModel
  • I18nShell
  • Inflector
  • IniAcl
  • JavascriptHelper
  • JqueryEngineHelper
  • JsBaseEngineHelper
  • JsHelper
  • L10n
  • MagicDb
  • MagicFileResource
  • MediaView
  • MemcacheEngine
  • Model
  • ModelBehavior
  • ModelTask
  • MootoolsEngineHelper
  • Multibyte
  • NumberHelper
  • Object
  • Overloadable
  • Overloadable2
  • PagesController
  • PaginatorHelper
  • Permission
  • PluginShortRoute
  • PluginTask
  • ProjectTask
  • PrototypeEngineHelper
  • RequestHandlerComponent
  • Router
  • RssHelper
  • Sanitize
  • Scaffold
  • ScaffoldView
  • SchemaShell
  • Security
  • SecurityComponent
  • SessionComponent
  • SessionHelper
  • Set
  • Shell
  • String
  • TemplateTask
  • TestSuiteShell
  • TestTask
  • TextHelper
  • ThemeView
  • TimeHelper
  • TranslateBehavior
  • TreeBehavior
  • Validation
  • View
  • ViewTask
  • XcacheEngine
  • Xml
  • XmlElement
  • XmlHelper
  • XmlManager
  • XmlNode
  • XmlTextNode

Functions

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

Generated using CakePHP API Docs