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.2 API

  • Overview
  • Tree
  • Deprecated
  • Version:
    • 1.2
      • 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
  • BehaviorCollection
  • Cache
  • CacheEngine
  • CacheHelper
  • CakeErrorController
  • CakeLog
  • CakeSchema
  • CakeSession
  • CakeSocket
  • ClassRegistry
  • Component
  • Configure
  • ConnectionManager
  • ConsoleShell
  • ContainableBehavior
  • Controller
  • ControllerTask
  • CookieComponent
  • DataSource
  • DbAcl
  • DbAclSchema
  • DbConfigTask
  • DboAdodb
  • DboDb2
  • DboFirebird
  • DboMssql
  • DboMysql
  • DboMysqlBase
  • DboMysqli
  • DboOdbc
  • DboOracle
  • DboPostgres
  • DboSource
  • DboSqlite
  • DboSybase
  • Debugger
  • EmailComponent
  • ErrorHandler
  • ExtractTask
  • File
  • FileEngine
  • Flay
  • Folder
  • FormHelper
  • Helper
  • HtmlHelper
  • HttpSocket
  • I18n
  • I18nModel
  • i18nSchema
  • I18nShell
  • Inflector
  • IniAcl
  • JavascriptHelper
  • JsHelper
  • JsHelperObject
  • L10n
  • MagicDb
  • MagicFileResource
  • MediaView
  • MemcacheEngine
  • Model
  • ModelBehavior
  • ModelTask
  • Multibyte
  • NumberHelper
  • Object
  • Overloadable
  • Overloadable2
  • PagesController
  • PaginatorHelper
  • Permission
  • PluginTask
  • ProjectTask
  • RequestHandlerComponent
  • Router
  • RssHelper
  • Sanitize
  • Scaffold
  • ScaffoldView
  • SchemaShell
  • Security
  • SecurityComponent
  • SessionComponent
  • SessionHelper
  • SessionsSchema
  • Set
  • Shell
  • String
  • TestSuiteShell
  • TestTask
  • TextHelper
  • ThemeView
  • TimeHelper
  • TranslateBehavior
  • TreeBehavior
  • Validation
  • View
  • ViewTask
  • XcacheEngine
  • Xml
  • XmlElement
  • XmlHelper
  • XmlManager
  • XmlNode
  • XmlTextNode

Functions

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