Browse Source

Optimize conditionals and reduce lookups.
Also, make the code easier to read removing unneded indentations.

Ber Clausen 12 years ago
parent
commit
1fbe9c0021
1 changed files with 275 additions and 260 deletions
  1. 275 260
      lib/Cake/Model/Model.php

+ 275 - 260
lib/Cake/Model/Model.php

@@ -987,30 +987,32 @@ class Model extends Object implements CakeEventListener {
  */
 	protected function _createLinks() {
 		foreach ($this->_associations as $type) {
-			if (!is_array($this->{$type})) {
-				$this->{$type} = explode(',', $this->{$type});
+			$association =& $this->{$type};
 
-				foreach ($this->{$type} as $i => $className) {
+			if (!is_array($association)) {
+				$association = explode(',', $association);
+
+				foreach ($association as $i => $className) {
 					$className = trim($className);
-					unset ($this->{$type}[$i]);
-					$this->{$type}[$className] = array();
+					unset ($association[$i]);
+					$association[$className] = array();
 				}
 			}
 
-			if (!empty($this->{$type})) {
-				foreach ($this->{$type} as $assoc => $value) {
+			if (!empty($association)) {
+				foreach ($association as $assoc => $value) {
 					$plugin = null;
 
 					if (is_numeric($assoc)) {
-						unset($this->{$type}[$assoc]);
+						unset($association[$assoc]);
 						$assoc = $value;
 						$value = array();
 
 						if (strpos($assoc, '.') !== false) {
 							list($plugin, $assoc) = pluginSplit($assoc, true);
-							$this->{$type}[$assoc] = array('className' => $plugin . $assoc);
+							$association[$assoc] = array('className' => $plugin . $assoc);
 						} else {
-							$this->{$type}[$assoc] = $value;
+							$association[$assoc] = $value;
 						}
 					}
 
@@ -1066,9 +1068,10 @@ class Model extends Object implements CakeEventListener {
 	protected function _generateAssociation($type, $assocKey) {
 		$class = $assocKey;
 		$dynamicWith = false;
+		$assoc =& $this->{$type}[$assocKey];
 
 		foreach ($this->_associationKeys[$type] as $key) {
-			if (!isset($this->{$type}[$assocKey][$key]) || $this->{$type}[$assocKey][$key] === null) {
+			if (!isset($assoc[$key]) || $assoc[$key] === null) {
 				$data = '';
 
 				switch ($key) {
@@ -1085,7 +1088,7 @@ class Model extends Object implements CakeEventListener {
 						break;
 
 					case 'with':
-						$data = Inflector::camelize(Inflector::singularize($this->{$type}[$assocKey]['joinTable']));
+						$data = Inflector::camelize(Inflector::singularize($assoc['joinTable']));
 						$dynamicWith = true;
 						break;
 
@@ -1104,11 +1107,11 @@ class Model extends Object implements CakeEventListener {
 						break;
 				}
 
-				$this->{$type}[$assocKey][$key] = $data;
+				$assoc[$key] = $data;
 			}
 
 			if ($dynamicWith) {
-				$this->{$type}[$assocKey]['dynamicWith'] = true;
+				$assoc['dynamicWith'] = true;
 			}
 		}
 	}
@@ -1180,24 +1183,22 @@ class Model extends Object implements CakeEventListener {
 		}
 
 		foreach ($data as $modelName => $fieldSet) {
-			if (is_array($fieldSet)) {
-				foreach ($fieldSet as $fieldName => $fieldValue) {
-					if (isset($this->validationErrors[$fieldName])) {
-						unset($this->validationErrors[$fieldName]);
-					}
+			if (!is_array($fieldSet)) {
+				continue;
+			}
 
-					if ($modelName === $this->alias) {
-						if ($fieldName === $this->primaryKey) {
-							$this->id = $fieldValue;
-						}
-					}
+			foreach ($fieldSet as $fieldName => $fieldValue) {
+				unset($this->validationErrors[$fieldName]);
 
-					if (is_array($fieldValue) || is_object($fieldValue)) {
-						$fieldValue = $this->deconstruct($fieldName, $fieldValue);
-					}
+				if ($modelName === $this->alias && $fieldName === $this->primaryKey) {
+					$this->id = $fieldValue;
+				}
 
-					$this->data[$modelName][$fieldName] = $fieldValue;
+				if (is_array($fieldValue) || is_object($fieldValue)) {
+					$fieldValue = $this->deconstruct($fieldName, $fieldValue);
 				}
+
+				$this->data[$modelName][$fieldName] = $fieldValue;
 			}
 		}
 
@@ -1744,20 +1745,22 @@ class Model extends Object implements CakeEventListener {
 		$now = time();
 
 		foreach ($dateFields as $updateCol) {
-			if ($this->hasField($updateCol) && !in_array($updateCol, $fields)) {
-				$default = array('formatter' => 'date');
-				$colType = array_merge($default, $db->columns[$this->getColumnType($updateCol)]);
-				if (!array_key_exists('format', $colType)) {
-					$time = $now;
-				} else {
-					$time = call_user_func($colType['formatter'], $colType['format']);
-				}
+			if (in_array($updateCol, $fields) || !$this->hasField($updateCol)) {
+				continue;
+			}
 
-				if (!empty($this->whitelist)) {
-					$this->whitelist[] = $updateCol;
-				}
-				$this->set($updateCol, $time);
+			$default = array('formatter' => 'date');
+			$colType = array_merge($default, $db->columns[$this->getColumnType($updateCol)]);
+
+			$time = $now;
+			if (array_key_exists('format', $colType)) {
+				$time = call_user_func($colType['formatter'], $colType['format']);
+			}
+
+			if (!empty($this->whitelist)) {
+				$this->whitelist[] = $updateCol;
 			}
+			$this->set($updateCol, $time);
 		}
 
 		if ($options['callbacks'] === true || $options['callbacks'] === 'before') {
@@ -1783,18 +1786,16 @@ class Model extends Object implements CakeEventListener {
 					$v = $v[$n];
 				}
 				$joined[$n] = $v;
-			} else {
-				if ($n === $this->alias) {
-					foreach (array('created', 'updated', 'modified') as $field) {
-						if (array_key_exists($field, $v) && empty($v[$field])) {
-							unset($v[$field]);
-						}
+			} elseif ($n === $this->alias) {
+				foreach (array('created', 'updated', 'modified') as $field) {
+					if (array_key_exists($field, $v) && empty($v[$field])) {
+						unset($v[$field]);
 					}
+				}
 
-					foreach ($v as $x => $y) {
-						if ($this->hasField($x) && (empty($this->whitelist) || in_array($x, $this->whitelist))) {
-							list($fields[], $values[]) = array($x, $y);
-						}
+				foreach ($v as $x => $y) {
+					if ($this->hasField($x) && (empty($this->whitelist) || in_array($x, $this->whitelist))) {
+						list($fields[], $values[]) = array($x, $y);
 					}
 				}
 			}
@@ -1890,117 +1891,123 @@ class Model extends Object implements CakeEventListener {
  */
 	protected function _saveMulti($joined, $id, $db) {
 		foreach ($joined as $assoc => $data) {
-			if (isset($this->hasAndBelongsToMany[$assoc])) {
-				list($join) = $this->joinModel($this->hasAndBelongsToMany[$assoc]['with']);
+			if (!isset($this->hasAndBelongsToMany[$assoc])) {
+				continue;
+			}
 
-				if ($with = $this->hasAndBelongsToMany[$assoc]['with']) {
-					$withModel = is_array($with) ? key($with) : $with;
-					list(, $withModel) = pluginSplit($withModel);
-					$dbMulti = $this->{$withModel}->getDataSource();
-				} else {
-					$dbMulti = $db;
-				}
+			$habtm = $this->hasAndBelongsToMany[$assoc];
 
-				$isUUID = !empty($this->{$join}->primaryKey) && $this->{$join}->_isUUIDField($this->{$join}->primaryKey);
+			list($join) = $this->joinModel($habtm['with']);
 
-				$newData = $newValues = $newJoins = array();
-				$primaryAdded = false;
+			$Model = $this->{$join};
 
-				$fields = array(
-					$dbMulti->name($this->hasAndBelongsToMany[$assoc]['foreignKey']),
-					$dbMulti->name($this->hasAndBelongsToMany[$assoc]['associationForeignKey'])
-				);
+			if (!empty($habtm['with'])) {
+				$withModel = is_array($habtm['with']) ? key($habtm['with']) : $habtm['with'];
+				list(, $withModel) = pluginSplit($withModel);
+				$dbMulti = $this->{$withModel}->getDataSource();
+			} else {
+				$dbMulti = $db;
+			}
 
-				$idField = $db->name($this->{$join}->primaryKey);
-				if ($isUUID && !in_array($idField, $fields)) {
-					$fields[] = $idField;
-					$primaryAdded = true;
-				}
+			$isUUID = !empty($Model->primaryKey) && $Model->_isUUIDField($Model->primaryKey);
 
-				foreach ((array)$data as $row) {
-					if ((is_string($row) && (strlen($row) == 36 || strlen($row) == 16)) || is_numeric($row)) {
-						$newJoins[] = $row;
-						$values = array($id, $row);
+			$newData = $newValues = $newJoins = array();
+			$primaryAdded = false;
 
-						if ($isUUID && $primaryAdded) {
-							$values[] = String::uuid();
-						}
+			$fields = array(
+				$dbMulti->name($habtm['foreignKey']),
+				$dbMulti->name($habtm['associationForeignKey'])
+			);
 
-						$newValues[$row] = $values;
-						unset($values);
-					} elseif (isset($row[$this->hasAndBelongsToMany[$assoc]['associationForeignKey']])) {
-						if (!empty($row[$this->{$join}->primaryKey])) {
-							$newJoins[] = $row[$this->hasAndBelongsToMany[$assoc]['associationForeignKey']];
-						}
+			$idField = $db->name($Model->primaryKey);
+			if ($isUUID && !in_array($idField, $fields)) {
+				$fields[] = $idField;
+				$primaryAdded = true;
+			}
 
-						$newData[] = $row;
-					} elseif (isset($row[$join]) && isset($row[$join][$this->hasAndBelongsToMany[$assoc]['associationForeignKey']])) {
-						if (!empty($row[$join][$this->{$join}->primaryKey])) {
-							$newJoins[] = $row[$join][$this->hasAndBelongsToMany[$assoc]['associationForeignKey']];
-						}
+			foreach ((array)$data as $row) {
+				if ((is_string($row) && (strlen($row) == 36 || strlen($row) == 16)) || is_numeric($row)) {
+					$newJoins[] = $row;
+					$values = array($id, $row);
 
-						$newData[] = $row[$join];
+					if ($isUUID && $primaryAdded) {
+						$values[] = String::uuid();
 					}
-				}
 
-				$keepExisting = $this->hasAndBelongsToMany[$assoc]['unique'] === 'keepExisting';
-				if ($this->hasAndBelongsToMany[$assoc]['unique']) {
-					$conditions = array(
-						$join . '.' . $this->hasAndBelongsToMany[$assoc]['foreignKey'] => $id
-					);
+					$newValues[$row] = $values;
+					unset($values);
+				} elseif (isset($row[$habtm['associationForeignKey']])) {
+					if (!empty($row[$Model->primaryKey])) {
+						$newJoins[] = $row[$habtm['associationForeignKey']];
+					}
 
-					if (!empty($this->hasAndBelongsToMany[$assoc]['conditions'])) {
-						$conditions = array_merge($conditions, (array)$this->hasAndBelongsToMany[$assoc]['conditions']);
+					$newData[] = $row;
+				} elseif (isset($row[$join]) && isset($row[$join][$habtm['associationForeignKey']])) {
+					if (!empty($row[$join][$Model->primaryKey])) {
+						$newJoins[] = $row[$join][$habtm['associationForeignKey']];
 					}
 
-					$associationForeignKey = $this->{$join}->alias . '.' . $this->hasAndBelongsToMany[$assoc]['associationForeignKey'];
-					$links = $this->{$join}->find('all', array(
-						'conditions' => $conditions,
-						'recursive' => empty($this->hasAndBelongsToMany[$assoc]['conditions']) ? -1 : 0,
-						'fields' => $associationForeignKey,
-					));
+					$newData[] = $row[$join];
+				}
+			}
 
-					$oldLinks = Hash::extract($links, "{n}.{$associationForeignKey}");
-					if (!empty($oldLinks)) {
-						if ($keepExisting && !empty($newJoins)) {
-							$conditions[$associationForeignKey] = array_diff($oldLinks, $newJoins);
-						} else {
-							$conditions[$associationForeignKey] = $oldLinks;
-						}
+			$keepExisting = $habtm['unique'] === 'keepExisting';
+			if ($habtm['unique']) {
+				$conditions = array(
+					$join . '.' . $habtm['foreignKey'] => $id
+				);
 
-						$dbMulti->delete($this->{$join}, $conditions);
-					}
+				if (!empty($habtm['conditions'])) {
+					$conditions = array_merge($conditions, (array)$habtm['conditions']);
 				}
 
-				if (!empty($newData)) {
-					foreach ($newData as $data) {
-						$data[$this->hasAndBelongsToMany[$assoc]['foreignKey']] = $id;
-						if (empty($data[$this->{$join}->primaryKey])) {
-							$this->{$join}->create();
-						}
+				$associationForeignKey = $Model->alias . '.' . $habtm['associationForeignKey'];
+				$links = $Model->find('all', array(
+					'conditions' => $conditions,
+					'recursive' => empty($habtm['conditions']) ? -1 : 0,
+					'fields' => $associationForeignKey,
+				));
 
-						$this->{$join}->save($data);
+				$oldLinks = Hash::extract($links, "{n}.{$associationForeignKey}");
+				if (!empty($oldLinks)) {
+					if ($keepExisting && !empty($newJoins)) {
+						$conditions[$associationForeignKey] = array_diff($oldLinks, $newJoins);
+					} else {
+						$conditions[$associationForeignKey] = $oldLinks;
 					}
-				}
 
-				if (!empty($newValues)) {
-					if ($keepExisting && !empty($links)) {
-						foreach ($links as $link) {
-							$oldJoin = $link[$join][$this->hasAndBelongsToMany[$assoc]['associationForeignKey']];
-							if (!in_array($oldJoin, $newJoins)) {
-								$conditions[$associationForeignKey] = $oldJoin;
-								$db->delete($this->{$join}, $conditions);
-							} else {
-								unset($newValues[$oldJoin]);
-							}
-						}
+					$dbMulti->delete($Model, $conditions);
+				}
+			}
 
-						$newValues = array_values($newValues);
+			if (!empty($newData)) {
+				foreach ($newData as $data) {
+					$data[$habtm['foreignKey']] = $id;
+					if (empty($data[$Model->primaryKey])) {
+						$Model->create();
 					}
 
-					if (!empty($newValues)) {
-						$dbMulti->insertMulti($this->{$join}, $fields, $newValues);
+					$Model->save($data);
+				}
+			}
+
+			if (!empty($newValues)) {
+				if ($keepExisting && !empty($links)) {
+					foreach ($links as $link) {
+						$oldJoin = $link[$join][$habtm['associationForeignKey']];
+						if (!in_array($oldJoin, $newJoins)) {
+							$conditions[$associationForeignKey] = $oldJoin;
+							$db->delete($Model, $conditions);
+						} else {
+							unset($newValues[$oldJoin]);
+						}
 					}
+
+					$newValues = array_values($newValues);
+				}
+
+				if (!empty($newValues)) {
+					$dbMulti->insertMulti($Model, $fields, $newValues);
 				}
 			}
 		}
@@ -2019,64 +2026,66 @@ class Model extends Object implements CakeEventListener {
 		$keys['old'] = isset($keys['old']) ? $keys['old'] : array();
 
 		foreach ($this->belongsTo as $parent => $assoc) {
-			if (!empty($assoc['counterCache'])) {
-				if (!is_array($assoc['counterCache'])) {
-					if (isset($assoc['counterScope'])) {
-						$assoc['counterCache'] = array($assoc['counterCache'] => $assoc['counterScope']);
-					} else {
-						$assoc['counterCache'] = array($assoc['counterCache'] => array());
-					}
-				}
-
-				$foreignKey = $assoc['foreignKey'];
-				$fkQuoted = $this->escapeField($assoc['foreignKey']);
-
-				foreach ($assoc['counterCache'] as $field => $conditions) {
-					if (!is_string($field)) {
-						$field = Inflector::underscore($this->alias) . '_count';
-					}
+			if (empty($assoc['counterCache'])) {
+				continue;
+			}
 
-					if (!$this->{$parent}->hasField($field)) {
-						continue;
-					}
+			$Model = $this->{$parent};
 
-					if ($conditions === true) {
-						$conditions = array();
-					} else {
-						$conditions = (array)$conditions;
-					}
+			if (!is_array($assoc['counterCache'])) {
+				if (isset($assoc['counterScope'])) {
+					$assoc['counterCache'] = array($assoc['counterCache'] => $assoc['counterScope']);
+				} else {
+					$assoc['counterCache'] = array($assoc['counterCache'] => array());
+				}
+			}
 
-					if (!array_key_exists($foreignKey, $keys)) {
-						$keys[$foreignKey] = $this->field($foreignKey);
-					}
+			$foreignKey = $assoc['foreignKey'];
+			$fkQuoted = $this->escapeField($assoc['foreignKey']);
 
-					$recursive = (empty($conditions) ? -1 : 0);
+			foreach ($assoc['counterCache'] as $field => $conditions) {
+				if (!is_string($field)) {
+					$field = Inflector::underscore($this->alias) . '_count';
+				}
 
-					if (isset($keys['old'][$foreignKey])) {
-						if ($keys['old'][$foreignKey] != $keys[$foreignKey]) {
-							$conditions[$fkQuoted] = $keys['old'][$foreignKey];
-							$count = intval($this->find('count', compact('conditions', 'recursive')));
+				if (!$Model->hasField($field)) {
+					continue;
+				}
 
-							$this->{$parent}->updateAll(
-								array($field => $count),
-								array($this->{$parent}->escapeField() => $keys['old'][$foreignKey])
-							);
-						}
-					}
+				if ($conditions === true) {
+					$conditions = array();
+				} else {
+					$conditions = (array)$conditions;
+				}
 
-					$conditions[$fkQuoted] = $keys[$foreignKey];
+				if (!array_key_exists($foreignKey, $keys)) {
+					$keys[$foreignKey] = $this->field($foreignKey);
+				}
 
-					if ($recursive === 0) {
-						$conditions = array_merge($conditions, (array)$conditions);
-					}
+				$recursive = (empty($conditions) ? -1 : 0);
 
+				if (isset($keys['old'][$foreignKey]) && $keys['old'][$foreignKey] != $keys[$foreignKey]) {
+					$conditions[$fkQuoted] = $keys['old'][$foreignKey];
 					$count = intval($this->find('count', compact('conditions', 'recursive')));
 
-					$this->{$parent}->updateAll(
+					$Model->updateAll(
 						array($field => $count),
-						array($this->{$parent}->escapeField() => $keys[$foreignKey])
+						array($Model->escapeField() => $keys['old'][$foreignKey])
 					);
 				}
+
+				$conditions[$fkQuoted] = $keys[$foreignKey];
+
+				if ($recursive === 0) {
+					$conditions = array_merge($conditions, (array)$conditions);
+				}
+
+				$count = intval($this->find('count', compact('conditions', 'recursive')));
+
+				$Model->updateAll(
+					array($field => $count),
+					array($Model->escapeField() => $keys[$foreignKey])
+				);
 			}
 		}
 	}
@@ -2341,33 +2350,37 @@ class Model extends Object implements CakeEventListener {
 		$return = array();
 		$validates = true;
 		foreach ($data as $association => $values) {
-			$notEmpty = !empty($values[$association]) || (!isset($values[$association]) && !empty($values));
-			if (isset($associations[$association]) && $associations[$association] === 'belongsTo' && $notEmpty) {
-				$validates = $this->{$association}->create(null) !== null;
-				$saved = false;
-				if ($validates) {
-					if ($options['deep']) {
-						$saved = $this->{$association}->saveAssociated($values, array_merge($options, array('atomic' => false)));
-					} else {
-						$saved = $this->{$association}->save($values, array_merge($options, array('atomic' => false)));
-					}
-					$validates = ($saved === true || (is_array($saved) && !in_array(false, $saved, true)));
-				}
+			$isEmpty = empty($values) || (isset($values[$association]) && empty($values[$association]));
+			if ($isEmpty || !isset($associations[$association]) || $associations[$association] !== 'belongsTo') {
+				continue;
+			}
 
-				if ($validates) {
-					$key = $this->belongsTo[$association]['foreignKey'];
-					if (isset($data[$this->alias])) {
-						$data[$this->alias][$key] = $this->{$association}->id;
-					} else {
-						$data = array_merge(array($key => $this->{$association}->id), $data, array($key => $this->{$association}->id));
-					}
-					$options = $this->_addToWhiteList($key, $options);
+			$Model = $this->{$association};
+
+			$validates = $Model->create(null) !== null;
+			$saved = false;
+			if ($validates) {
+				if ($options['deep']) {
+					$saved = $Model->saveAssociated($values, array_merge($options, array('atomic' => false)));
 				} else {
-					$validationErrors[$association] = $this->{$association}->validationErrors;
+					$saved = $Model->save($values, array_merge($options, array('atomic' => false)));
 				}
+				$validates = ($saved === true || (is_array($saved) && !in_array(false, $saved, true)));
+			}
 
-				$return[$association] = $validates;
+			if ($validates) {
+				$key = $this->belongsTo[$association]['foreignKey'];
+				if (isset($data[$this->alias])) {
+					$data[$this->alias][$key] = $Model->id;
+				} else {
+					$data = array_merge(array($key => $Model->id), $data, array($key => $Model->id));
+				}
+				$options = $this->_addToWhiteList($key, $options);
+			} else {
+				$validationErrors[$association] = $Model->validationErrors;
 			}
+
+			$return[$association] = $validates;
 		}
 
 		if ($validates && !($this->create(null) !== null && $this->save($data, $options))) {
@@ -2381,56 +2394,60 @@ class Model extends Object implements CakeEventListener {
 				break;
 			}
 
-			$notEmpty = !empty($values[$association]) || (!isset($values[$association]) && !empty($values));
-			if (isset($associations[$association]) && $notEmpty) {
-				$type = $associations[$association];
-				$key = $this->{$type}[$association]['foreignKey'];
-				switch ($type) {
-					case 'hasOne':
-						if (isset($values[$association])) {
-							$values[$association][$key] = $this->id;
-						} else {
-							$values = array_merge(array($key => $this->id), $values, array($key => $this->id));
-						}
+			$isEmpty = empty($values) || (isset($values[$association]) && empty($values[$association]));
+			if ($isEmpty || !isset($associations[$association])) {
+				continue;
+			}
 
-						$validates = $this->{$association}->create(null) !== null;
-						$saved = false;
+			$Model = $this->{$association};
 
-						if ($validates) {
-							$options = $this->{$association}->_addToWhiteList($key, $options);
-							if ($options['deep']) {
-								$saved = $this->{$association}->saveAssociated($values, array_merge($options, array('atomic' => false)));
-							} else {
-								$saved = $this->{$association}->save($values, $options);
-							}
-						}
+			$type = $associations[$association];
+			$key = $this->{$type}[$association]['foreignKey'];
+			switch ($type) {
+				case 'hasOne':
+					if (isset($values[$association])) {
+						$values[$association][$key] = $this->id;
+					} else {
+						$values = array_merge(array($key => $this->id), $values, array($key => $this->id));
+					}
 
-						$validates = ($validates && ($saved === true || (is_array($saved) && !in_array(false, $saved, true))));
-						if (!$validates) {
-							$validationErrors[$association] = $this->{$association}->validationErrors;
-						}
+					$validates = $Model->create(null) !== null;
+					$saved = false;
 
-						$return[$association] = $validates;
-						break;
-					case 'hasMany':
-						foreach ($values as $i => $value) {
-							if (isset($values[$i][$association])) {
-								$values[$i][$association][$key] = $this->id;
-							} else {
-								$values[$i] = array_merge(array($key => $this->id), $value, array($key => $this->id));
-							}
+					if ($validates) {
+						$options = $Model->_addToWhiteList($key, $options);
+						if ($options['deep']) {
+							$saved = $Model->saveAssociated($values, array_merge($options, array('atomic' => false)));
+						} else {
+							$saved = $Model->save($values, $options);
 						}
+					}
+
+					$validates = ($validates && ($saved === true || (is_array($saved) && !in_array(false, $saved, true))));
+					if (!$validates) {
+						$validationErrors[$association] = $Model->validationErrors;
+					}
 
-						$options = $this->{$association}->_addToWhiteList($key, $options);
-						$_return = $this->{$association}->saveMany($values, array_merge($options, array('atomic' => false)));
-						if (in_array(false, $_return, true)) {
-							$validationErrors[$association] = $this->{$association}->validationErrors;
-							$validates = false;
+					$return[$association] = $validates;
+					break;
+				case 'hasMany':
+					foreach ($values as $i => $value) {
+						if (isset($values[$i][$association])) {
+							$values[$i][$association][$key] = $this->id;
+						} else {
+							$values[$i] = array_merge(array($key => $this->id), $value, array($key => $this->id));
 						}
+					}
 
-						$return[$association] = $_return;
-						break;
-				}
+					$options = $Model->_addToWhiteList($key, $options);
+					$_return = $Model->saveMany($values, array_merge($options, array('atomic' => false)));
+					if (in_array(false, $_return, true)) {
+						$validationErrors[$association] = $Model->validationErrors;
+						$validates = false;
+					}
+
+					$return[$association] = $_return;
+					break;
 			}
 		}
 		$this->validationErrors = $validationErrors;
@@ -2475,10 +2492,7 @@ class Model extends Object implements CakeEventListener {
 			return $options;
 		}
 
-		if (!empty($options['fieldList']) &&
-			is_array($options['fieldList']) &&
-			Hash::dimensions($options['fieldList']) < 2
-		) {
+		if (!empty($options['fieldList']) && is_array($options['fieldList']) && Hash::dimensions($options['fieldList']) < 2) {
 			$options['fieldList'][] = $key;
 		}
 
@@ -2604,29 +2618,29 @@ class Model extends Object implements CakeEventListener {
 				continue;
 			}
 
-			$model = $this->{$assoc};
+			$Model = $this->{$assoc};
 
-			if ($data['foreignKey'] === false && $data['conditions'] && in_array($this->name, $model->getAssociated('belongsTo'))) {
-				$model->recursive = 0;
+			if ($data['foreignKey'] === false && $data['conditions'] && in_array($this->name, $Model->getAssociated('belongsTo'))) {
+				$Model->recursive = 0;
 				$conditions = array($this->escapeField(null, $this->name) => $id);
 			} else {
-				$model->recursive = -1;
-				$conditions = array($model->escapeField($data['foreignKey']) => $id);
+				$Model->recursive = -1;
+				$conditions = array($Model->escapeField($data['foreignKey']) => $id);
 				if ($data['conditions']) {
 					$conditions = array_merge((array)$data['conditions'], $conditions);
 				}
 			}
 
 			if (isset($data['exclusive']) && $data['exclusive']) {
-				$model->deleteAll($conditions);
+				$Model->deleteAll($conditions);
 			} else {
-				$records = $model->find('all', array(
-					'conditions' => $conditions, 'fields' => $model->primaryKey
+				$records = $Model->find('all', array(
+					'conditions' => $conditions, 'fields' => $Model->primaryKey
 				));
 
 				if (!empty($records)) {
 					foreach ($records as $record) {
-						$model->delete($record[$model->alias][$model->primaryKey]);
+						$Model->delete($record[$Model->alias][$Model->primaryKey]);
 					}
 				}
 			}
@@ -2646,16 +2660,17 @@ class Model extends Object implements CakeEventListener {
 	protected function _deleteLinks($id) {
 		foreach ($this->hasAndBelongsToMany as $data) {
 			list(, $joinModel) = pluginSplit($data['with']);
-			$records = $this->{$joinModel}->find('all', array(
-				'conditions' => array($this->{$joinModel}->escapeField($data['foreignKey']) => $id),
-				'fields' => $this->{$joinModel}->primaryKey,
+			$Model = $this->{$joinModel};
+			$records = $Model->find('all', array(
+				'conditions' => array($Model->escapeField($data['foreignKey']) => $id),
+				'fields' => $Model->primaryKey,
 				'recursive' => -1,
 				'callbacks' => false
 			));
 
 			if (!empty($records)) {
 				foreach ($records as $record) {
-					$this->{$joinModel}->delete($record[$this->{$joinModel}->alias][$this->{$joinModel}->primaryKey]);
+					$Model->delete($record[$Model->alias][$Model->primaryKey]);
 				}
 			}
 		}