diff --git a/cake/libs/configure.php b/cake/libs/configure.php
index c8ae0e31c..f600b1772 100644
--- a/cake/libs/configure.php
+++ b/cake/libs/configure.php
@@ -249,8 +249,14 @@ class Configure extends Object {
  * Usage
  * Configure::write('One.key1', 'value of the Configure::One[key1]');
  * Configure::write(array('One.key1' => 'value of the Configure::One[key1]'));
- * Configure::write('One', array('key1'=>'value of the Configure::One[key1]', 'key2'=>'value of the Configure::One[key2]');
- * Configure::write(array('One.key1' => 'value of the Configure::One[key1]', 'One.key2' => 'value of the Configure::One[key2]'));
+ * Configure::write('One', array(
+ *     'key1' => 'value of the Configure::One[key1]',
+ *     'key2' => 'value of the Configure::One[key2]'
+ * );
+ * Configure::write(array(
+ *     'One.key1' => 'value of the Configure::One[key1]',
+ *     'One.key2' => 'value of the Configure::One[key2]'
+ * ));
  *
  * @link          http://book.cakephp.org/view/412/write
  * @param array $config Name of var to write
@@ -379,7 +385,8 @@ class Configure extends Object {
  * Usage Configure::load('configure_file');
  *
  * @link          http://book.cakephp.org/view/415/load
- * @param string $fileName name of file to load, extension must be .php and only the name should be used, not the extenstion
+ * @param string $fileName name of file to load, extension must be .php and only the name
+ *                         should be used, not the extenstion
  * @return mixed false if file not found, void if load successful
  * @access public
  */
@@ -407,7 +414,8 @@ class Configure extends Object {
 		}
 
 		if (!isset($config)) {
-			trigger_error(sprintf(__("Configure::load() - no variable \$config found in %s.php", true), $fileName), E_USER_WARNING);
+			$error = __("Configure::load() - no variable \$config found in %s.php", true);
+			trigger_error(sprintf($error, $fileName), E_USER_WARNING);
 			return false;
 		}
 		return Configure::write($config);
@@ -433,7 +441,9 @@ class Configure extends Object {
 /**
  * Used to write a config file to disk.
  *
- * Configure::store('Model', 'class.paths', array('Users' => array('path' => 'users', 'plugin' => true)));
+ * Configure::store('Model', 'class.paths', array('Users' => array(
+ *      'path' => 'users', 'plugin' => true
+ * )));
  *
  * @param string $type Type of config file to write, ex: Models, Controllers, Helpers, Components
  * @param string $name file name.
@@ -470,7 +480,8 @@ class Configure extends Object {
  * Returns a key/value list of all paths where core libs are found.
  * Passing $type only returns the values for a given value of $key.
  *
- * @param string $type valid values are: 'model', 'behavior', 'controller', 'component', 'view', 'helper', 'libs', and 'cake'
+ * @param string $type valid values are: 'model', 'behavior', 'controller', 'component',
+ *                      'view', 'helper', 'datasource', 'libs', and 'cake'
  * @return array numeric keyed array of core lib paths
  * @access public
  */
@@ -589,7 +600,8 @@ class Configure extends Object {
 			'plugin' => array(APP . 'plugins' . DS),
 			'vendor' => array(APP . 'vendors' . DS, VENDORS),
 			'locale' => array(APP . 'locale' . DS),
-			'shell' => array()
+			'shell' => array(),
+			'datasource' => array(MODELS . 'datasources')
 		);
 
 		foreach ($basePaths as $type => $default) {
@@ -609,7 +621,9 @@ class Configure extends Object {
 			$_this->{$pathsVar} = $default;
 
 			if (isset($paths[$pathsVar]) && !empty($paths[$pathsVar])) {
-				$path = array_flip(array_flip((array_merge($_this->{$pathsVar}, (array)$paths[$pathsVar], $merge))));
+				$path = array_flip(array_flip((array_merge(
+					$_this->{$pathsVar}, (array)$paths[$pathsVar], $merge
+				))));
 				$_this->{$pathsVar} = array_values($path);
 			} else {
 				$path = array_flip(array_flip((array_merge($_this->{$pathsVar}, $merge))));
@@ -676,7 +690,10 @@ class Configure extends Object {
 				}
 				Cache::config('default');
 			}
-			Configure::buildPaths(compact('modelPaths', 'viewPaths', 'controllerPaths', 'helperPaths', 'componentPaths', 'behaviorPaths', 'pluginPaths', 'vendorPaths', 'localePaths', 'shellPaths'));
+			Configure::buildPaths(compact(
+				'modelPaths', 'viewPaths', 'controllerPaths', 'helperPaths', 'componentPaths',
+				'behaviorPaths', 'pluginPaths', 'vendorPaths', 'localePaths', 'shellPaths'
+			));
 		}
 	}
 /**
@@ -745,13 +762,17 @@ class App extends Object {
  * Finds classes based on $name or specific file(s) to search.
  *
  * @link          http://book.cakephp.org/view/529/Using-App-import
- * @param mixed $type The type of Class if passed as a string, or all params can be passed as an single array to $type,
+ * @param mixed $type The type of Class if passed as a string, or all params can be passed as
+ *                    an single array to $type,
  * @param string $name Name of the Class or a unique name for the file
- * @param mixed $parent boolean true if Class Parent should be searched, accepts key => value array('parent' => $parent ,'file' => $file, 'search' => $search, 'ext' => '$ext');
- *  $ext allows setting the extension of the file name based on Inflector::underscore($name) . ".$ext";
+ * @param mixed $parent boolean true if Class Parent should be searched, accepts key => value
+ *              array('parent' => $parent ,'file' => $file, 'search' => $search, 'ext' => '$ext');
+ *              $ext allows setting the extension of the file name
+ *              based on Inflector::underscore($name) . ".$ext";
  * @param array $search paths to search for files, array('path 1', 'path 2', 'path 3');
  * @param string $file full name of the file to search for including extension
- * @param boolean $return, return the loaded file, the file must have a return statement in it to work: return $variable;
+ * @param boolean $return, return the loaded file, the file must have a return
+ *                         statement in it to work: return $variable;
  * @return boolean true if Class is already in memory or if file is found and loaded, false if not
  * @access public
  */
diff --git a/cake/libs/model/connection_manager.php b/cake/libs/model/connection_manager.php
index 8654b785c..524d2bd36 100644
--- a/cake/libs/model/connection_manager.php
+++ b/cake/libs/model/connection_manager.php
@@ -174,7 +174,8 @@ class ConnectionManager extends Object {
 		} elseif (fileExistsInPath(LIBS . 'model' . DS . 'datasources' . DS . $conn['filename'] . '.php')) {
 			require (LIBS . 'model' . DS . 'datasources' . DS . $conn['filename'] . '.php');
 		} else {
-			trigger_error(sprintf(__('Unable to load DataSource file %s.php', true), $conn['filename']), E_USER_ERROR);
+		    $error = __('Unable to load DataSource file %s.php', true);
+			trigger_error(sprintf($error, $conn['filename']), E_USER_ERROR);
 			return null;
 		}
 	}
diff --git a/cake/libs/model/model.php b/cake/libs/model/model.php
index 8e9496c46..f3f9eb721 100644
--- a/cake/libs/model/model.php
+++ b/cake/libs/model/model.php
@@ -1141,8 +1141,9 @@ class Model extends Overloadable {
 
 		foreach ($dateFields as $updateCol) {
 			if ($this->hasField($updateCol) && !in_array($updateCol, $fields)) {
-				$colType = array_merge(array('formatter' => 'date'), $db->columns[$this->getColumnType($updateCol)]);
-				if (!array_key_exists('formatter', $colType) || !array_key_exists('format', $colType)) {
+				$default = array('formatter' => 'date');
+				$colType = array_merge($default, $db->columns[$this->getColumnType($updateCol)]);
+				if (!array_key_exists('format', $colType)) {
 					$time = strtotime('now');
 				} else {
 					$time = $colType['formatter']($colType['format']);
@@ -1155,7 +1156,10 @@ class Model extends Overloadable {
 		}
 
 		if ($options['callbacks'] === true || $options['callbacks'] === 'before') {
-			if (!$this->Behaviors->trigger($this, 'beforeSave', array($options), array('break' => true, 'breakOn' => false)) || !$this->beforeSave($options)) {
+			$result = $this->Behaviors->trigger($this, 'beforeSave', array($options), array(
+				'break' => true, 'breakOn' => false
+			));
+			if (!$result || !$this->beforeSave($options)) {
 				$this->whitelist = $_whitelist;
 				return false;
 			}
@@ -1197,15 +1201,18 @@ class Model extends Overloadable {
 		$created = false;
 
 		if ($count > 0) {
+			$cache = $this->_prepareUpdateFields(array_combine($fields, $values));
+
 			if (!empty($this->id)) {
-				if (!$db->update($this, $fields, $values)) {
-					$success = false;
-				}
+				$success = (bool)$db->update($this, $fields, $values);
 			} else {
 				foreach ($this->_schema as $field => $properties) {
 					if ($this->primaryKey === $field) {
-						$isUUID = ($this->_schema[$field]['type'] === 'string' && $this->_schema[$field]['length'] === 36)
-								|| ($this->_schema[$field]['type'] === 'binary' && $this->_schema[$field]['length'] === 16);
+						$fInfo = $this->_schema[$field];
+						$isUUID = (
+							($fInfo['type'] === 'string' && $fInfo['length'] === 36) ||
+							($fInfo['type'] === 'binary' && $fInfo['length'] === 16)
+						);
 						if (empty($this->data[$this->alias][$this->primaryKey]) && $isUUID) {
 							list($fields[], $values[]) = array($this->primaryKey, String::uuid());
 						}
@@ -1219,10 +1226,10 @@ class Model extends Overloadable {
 					$created = true;
 				}
 			}
-		}
 
-		if (!empty($this->belongsTo)) {
-			$this->updateCounterCache(array(), $created);
+			if ($success && !empty($this->belongsTo)) {
+				$this->updateCounterCache($cache, $created);
+			}
 		}
 
 		if (!empty($joined) && $success === true) {
@@ -1334,32 +1341,80 @@ class Model extends Overloadable {
  * @access public
  */
 	function updateCounterCache($keys = array(), $created = false) {
-		if (empty($keys)) {
-			$keys = $this->data[$this->alias];
-		}
+		$keys = empty($keys) ? $this->data[$this->alias] : $keys;
+		$keys['old'] = isset($keys['old']) ? $keys['old'] : array();
+
 		foreach ($this->belongsTo as $parent => $assoc) {
+			$foreignKey = $assoc['foreignKey'];
+			$fkQuoted = $this->escapeField($assoc['foreignKey']);
+
 			if (!empty($assoc['counterCache'])) {
 				if ($assoc['counterCache'] === true) {
 					$assoc['counterCache'] = Inflector::underscore($this->alias) . '_count';
 				}
-				if (!isset($keys[$assoc['foreignKey']]) || empty($keys[$assoc['foreignKey']])) {
-					$keys[$assoc['foreignKey']] = $this->field($assoc['foreignKey']);
+				if (!$this->{$parent}->hasField($assoc['counterCache'])) {
+					continue;
 				}
-				if ($this->{$parent}->hasField($assoc['counterCache'])) {
-					$conditions = array($this->escapeField($assoc['foreignKey']) => $keys[$assoc['foreignKey']]);
-					$recursive = -1;
-					if (isset($assoc['counterScope'])) {
-						$conditions = array_merge($conditions, (array)$assoc['counterScope']);
-						$recursive = 1;
+
+				if (!array_key_exists($foreignKey, $keys)) {
+					$keys[$foreignKey] = $this->field($foreignKey);
+				}
+				$recursive = (isset($assoc['counterScope']) ? 1 : -1);
+				$conditions = ($recursive == 1) ? (array)$assoc['counterScope'] : array();
+
+				if (isset($keys['old'][$foreignKey])) {
+					if ($keys['old'][$foreignKey] == $keys[$foreignKey]) {
+						continue;
 					}
+					$conditions[$fkQuoted] = $keys['old'][$foreignKey];
+					$count = intval($this->find('count', compact('conditions', 'recursive')));
+
 					$this->{$parent}->updateAll(
-						array($assoc['counterCache'] => intval($this->find('count', compact('conditions', 'recursive')))),
-						array($this->{$parent}->escapeField() => $keys[$assoc['foreignKey']])
+						array($assoc['counterCache'] => $count),
+						array($this->{$parent}->escapeField() => $keys['old'][$foreignKey])
 					);
 				}
+				$conditions[$fkQuoted] = $keys[$foreignKey];
+
+				if ($recursive == 1) {
+					$conditions = array_merge($conditions, (array)$assoc['counterScope']);
+				}
+				$count = intval($this->find('count', compact('conditions', 'recursive')));
+
+				$this->{$parent}->updateAll(
+					array($assoc['counterCache'] => $count),
+					array($this->{$parent}->escapeField() => $keys[$foreignKey])
+				);
 			}
 		}
 	}
+/**
+ * Helper method for Model::updateCounterCache().  Checks the fields to be updated for
+ *
+ * @param array $data The fields of the record that will be updated
+ * @return array Returns updated foreign key values, along with an 'old' key containing the old
+ *               values, or empty if no foreign keys are updated.
+ * @access protected
+ */
+	function _prepareUpdateFields($data) {
+		$foreignKeys = array();
+		foreach ($this->belongsTo as $assoc => $info) {
+			if ($info['counterCache']) {
+				$foreignKeys[$assoc] = $info['foreignKey'];
+			}
+		}
+		$included = array_intersect($foreignKeys, array_keys($data));
+
+		if (empty($included) || empty($this->id)) {
+			return array();
+		}
+		$old = $this->find('first', array(
+			'conditions' => array('id' => $this->id),
+			'fields' => array_values($included),
+			'recursive' => -1
+		));
+		return array_merge($data, array('old' => $old[$this->alias]));
+	}
 /**
  * Saves multiple individual records for a single model; Also works with a single record, as well as
  * all its associated records.
@@ -2419,6 +2474,7 @@ class Model extends Overloadable {
  *
  * @return string The name of the display field for this Model (i.e. 'name', 'title').
  * @access public
+ * @deprecated
  */
 	function getDisplayField() {
 		return $this->displayField;
diff --git a/cake/libs/set.php b/cake/libs/set.php
index 360aed74d..e2ebf8d7c 100644
--- a/cake/libs/set.php
+++ b/cake/libs/set.php
@@ -406,7 +406,7 @@ class Set extends Object {
 					if (count($context['trace']) == 1) {
 						$context['trace'][] = $context['key'];
 					}
-					$parent = join('/', $context['trace']).'/.';
+					$parent = join('/', $context['trace']) . '/.';
 					$context['item'] = Set::extract($parent, $data);
 					$context['key'] = array_pop($context['trace']);
 					if (isset($context['trace'][1]) && $context['trace'][1] > 0) {
@@ -455,7 +455,7 @@ class Set extends Object {
 					$filtered = array();
 					$length = count($matches);
 					foreach ($matches as $i => $match) {
-						if (Set::matches(array($condition), $match['item'], $i+1, $length)) {
+						if (Set::matches(array($condition), $match['item'], $i + 1, $length)) {
 							$filtered[] = $match;
 						}
 					}
diff --git a/cake/tests/cases/libs/model/model.test.php b/cake/tests/cases/libs/model/model.test.php
index 0f69534c2..b588e86a5 100644
--- a/cake/tests/cases/libs/model/model.test.php
+++ b/cake/tests/cases/libs/model/model.test.php
@@ -65,7 +65,8 @@ class ModelTest extends CakeTestCase {
 		'core.dependency', 'core.story', 'core.stories_tag', 'core.cd', 'core.book', 'core.basket',
 		'core.overall_favorite', 'core.account', 'core.content', 'core.content_account',
 		'core.film_file', 'core.test_plugin_article', 'core.test_plugin_comment', 'core.uuiditem',
-		'core.uuidportfolio', 'core.uuiditems_uuidportfolio', 'core.uuiditems_uuidportfolio_numericid'
+		'core.counter_cache_user', 'core.counter_cache_post', 'core.uuidportfolio',
+		'core.uuiditems_uuidportfolio', 'core.uuiditems_uuidportfolio_numericid'
 	);
 /**
  * start method
@@ -190,7 +191,8 @@ class ModelTest extends CakeTestCase {
 		$this->assertTrue(isset($TestModel->Behaviors->Tree));
 
 		$TestModel =& ClassRegistry::init('MergeVarPluginComment');
-		$this->assertEqual($TestModel->actsAs, array('Containable', 'Containable' => array('some_settings')));
+		$expected = array('Containable', 'Containable' => array('some_settings'));
+		$this->assertEqual($TestModel->actsAs, $expected);
 		$this->assertTrue(isset($TestModel->Behaviors->Containable));
 	}
 /**
@@ -1073,13 +1075,15 @@ class ModelTest extends CakeTestCase {
 		$TestModel->id = 7;
 		$result = $TestModel->read();
 		$expected = array(
-				'CategoryThread' => array('id' => 7, 'parent_id' => 6, 'name' => 'Category 2.1', 'created' => '2007-03-18 15:30:23', 'updated' => '2007-03-18 15:32:31'),
-						'ParentCategory' => array('id' => 6, 'parent_id' => 5, 'name' => 'Category 2', 'created' => '2007-03-18 15:30:23', 'updated' => '2007-03-18 15:32:31',
-						'ParentCategory' => array('id' => 5, 'parent_id' => 4, 'name' => 'Category 1.1.1.1', 'created' => '2007-03-18 15:30:23', 'updated' => '2007-03-18 15:32:31',
-						'ParentCategory' => array('id' => 4, 'parent_id' => 3, 'name' => 'Category 1.1.2', 'created' => '2007-03-18 15:30:23', 'updated' => '2007-03-18 15:32:31',
-						'ParentCategory' => array('id' => 3, 'parent_id' => 2, 'name' => 'Category 1.1.1', 'created' => '2007-03-18 15:30:23', 'updated' => '2007-03-18 15:32:31',
-						'ParentCategory' => array('id' => 2, 'parent_id' => 1, 'name' => 'Category 1.1', 'created' => '2007-03-18 15:30:23', 'updated' => '2007-03-18 15:32:31',
-						'ParentCategory' => array('id' => 1, 'parent_id' => 0, 'name' => 'Category 1', 'created' => '2007-03-18 15:30:23', 'updated' => '2007-03-18 15:32:31')))))));
+			'CategoryThread' => array('id' => 7, 'parent_id' => 6, 'name' => 'Category 2.1', 'created' => '2007-03-18 15:30:23', 'updated' => '2007-03-18 15:32:31'),
+				'ParentCategory' => array('id' => 6, 'parent_id' => 5, 'name' => 'Category 2', 'created' => '2007-03-18 15:30:23', 'updated' => '2007-03-18 15:32:31',
+				'ParentCategory' => array('id' => 5, 'parent_id' => 4, 'name' => 'Category 1.1.1.1', 'created' => '2007-03-18 15:30:23', 'updated' => '2007-03-18 15:32:31',
+				'ParentCategory' => array('id' => 4, 'parent_id' => 3, 'name' => 'Category 1.1.2', 'created' => '2007-03-18 15:30:23', 'updated' => '2007-03-18 15:32:31',
+				'ParentCategory' => array('id' => 3, 'parent_id' => 2, 'name' => 'Category 1.1.1', 'created' => '2007-03-18 15:30:23', 'updated' => '2007-03-18 15:32:31',
+				'ParentCategory' => array('id' => 2, 'parent_id' => 1, 'name' => 'Category 1.1', 'created' => '2007-03-18 15:30:23', 'updated' => '2007-03-18 15:32:31',
+				'ParentCategory' => array('id' => 1, 'parent_id' => 0, 'name' => 'Category 1', 'created' => '2007-03-18 15:30:23', 'updated' => '2007-03-18 15:32:31')))))
+			)
+		);
 		$this->db->fullDebug = $fullDebug;
 		$this->assertEqual($result, $expected);
 	}
@@ -1099,13 +1103,15 @@ class ModelTest extends CakeTestCase {
 		$result = $TestModel->find(array('CategoryThread.id' => 7));
 
 		$expected = array(
-				'CategoryThread' => array('id' => 7, 'parent_id' => 6, 'name' => 'Category 2.1', 'created' => '2007-03-18 15:30:23', 'updated' => '2007-03-18 15:32:31'),
-						'ParentCategory' => array('id' => 6, 'parent_id' => 5, 'name' => 'Category 2', 'created' => '2007-03-18 15:30:23', 'updated' => '2007-03-18 15:32:31',
-						'ParentCategory' => array('id' => 5, 'parent_id' => 4, 'name' => 'Category 1.1.1.1', 'created' => '2007-03-18 15:30:23', 'updated' => '2007-03-18 15:32:31',
-						'ParentCategory' => array('id' => 4, 'parent_id' => 3, 'name' => 'Category 1.1.2', 'created' => '2007-03-18 15:30:23', 'updated' => '2007-03-18 15:32:31',
-						'ParentCategory' => array('id' => 3, 'parent_id' => 2, 'name' => 'Category 1.1.1', 'created' => '2007-03-18 15:30:23', 'updated' => '2007-03-18 15:32:31',
-						'ParentCategory' => array('id' => 2, 'parent_id' => 1, 'name' => 'Category 1.1', 'created' => '2007-03-18 15:30:23', 'updated' => '2007-03-18 15:32:31',
-						'ParentCategory' => array('id' => 1, 'parent_id' => 0, 'name' => 'Category 1', 'created' => '2007-03-18 15:30:23', 'updated' => '2007-03-18 15:32:31')))))));
+			'CategoryThread' => array('id' => 7, 'parent_id' => 6, 'name' => 'Category 2.1', 'created' => '2007-03-18 15:30:23', 'updated' => '2007-03-18 15:32:31'),
+				'ParentCategory' => array('id' => 6, 'parent_id' => 5, 'name' => 'Category 2', 'created' => '2007-03-18 15:30:23', 'updated' => '2007-03-18 15:32:31',
+				'ParentCategory' => array('id' => 5, 'parent_id' => 4, 'name' => 'Category 1.1.1.1', 'created' => '2007-03-18 15:30:23', 'updated' => '2007-03-18 15:32:31',
+				'ParentCategory' => array('id' => 4, 'parent_id' => 3, 'name' => 'Category 1.1.2', 'created' => '2007-03-18 15:30:23', 'updated' => '2007-03-18 15:32:31',
+				'ParentCategory' => array('id' => 3, 'parent_id' => 2, 'name' => 'Category 1.1.1', 'created' => '2007-03-18 15:30:23', 'updated' => '2007-03-18 15:32:31',
+				'ParentCategory' => array('id' => 2, 'parent_id' => 1, 'name' => 'Category 1.1', 'created' => '2007-03-18 15:30:23', 'updated' => '2007-03-18 15:32:31',
+				'ParentCategory' => array('id' => 1, 'parent_id' => 0, 'name' => 'Category 1', 'created' => '2007-03-18 15:30:23', 'updated' => '2007-03-18 15:32:31')))))
+			)
+		);
 		$this->db->fullDebug = $fullDebug;
 		$this->assertEqual($result, $expected);
 	}
@@ -3681,7 +3687,70 @@ class ModelTest extends CakeTestCase {
 		$this->assertIdentical($result['Syfile']['item_count'], '2');
 
 		$result = $TestModel->findById(2);
-		$this->assertIdentical($result['Syfile']['item_count'], null);
+		$this->assertIdentical($result['Syfile']['item_count'], '0');
+	}
+/**
+ * Tests that counter caches are updated when records are added
+ *
+ * @access public
+ * @return void
+ */
+	function testCounterCacheIncrease() {
+		$this->loadFixtures('CounterCacheUser', 'CounterCachePost');
+		$User = new CounterCacheUser();
+		$Post = new CounterCachePost();
+		$data = array('Post' => array('title' => 'New Post', 'user_id' => 66));
+
+		$Post->save($data);
+		$user = $User->find('first', array(
+			'conditions' => array('id' => 66),'recursive' => -1
+		));
+
+		$result = $user[$User->alias]['post_count'];
+		$expected = 3;
+		$this->assertEqual($result, $expected);
+	
+	}
+/**
+ * Tests that counter caches are updated when records are deleted
+ *
+ * @access public
+ * @return void
+ */
+	function testCounterCacheDecrease() {
+		$this->loadFixtures('CounterCacheUser', 'CounterCachePost');
+		$User = new CounterCacheUser();
+		$Post = new CounterCachePost();
+
+		$Post->del(2);
+		$user = $User->find('first', array(
+			'conditions' => array('id' => 66),'recursive' => -1
+		));
+
+		$result = $user[$User->alias]['post_count'];
+		$expected = 1;
+		$this->assertEqual($result, $expected);
+	}
+/**
+ * Tests that counter caches are updated when foreign keys of counted records change
+ *
+ * @access public
+ * @return void
+ */
+	function testCounterCacheUpdated() {
+		$this->loadFixtures('CounterCacheUser', 'CounterCachePost');
+		$User = new CounterCacheUser();
+		$Post = new CounterCachePost();
+
+		$data = $Post->find('first', array(
+			'conditions' => array('id' => 1),'recursive' => -1
+		));
+		$data[$Post->alias]['user_id'] = 301;
+		$Post->save($data);
+
+		$users = $User->find('all',array('order' => 'User.id'));
+		$this->assertEqual($users[0]['User']['post_count'], 1);
+		$this->assertEqual($users[1]['User']['post_count'], 2);
 	}
 /**
  * test Counter Cache With Self Joining table
diff --git a/cake/tests/cases/libs/model/models.php b/cake/tests/cases/libs/model/models.php
index b89da27f2..b9e5063b4 100644
--- a/cake/tests/cases/libs/model/models.php
+++ b/cake/tests/cases/libs/model/models.php
@@ -2840,6 +2840,29 @@ class TranslatedArticle extends CakeTestModel {
 	var $belongsTo = array('User');
 }
 
+class CounterCacheUser extends CakeTestModel {
+	var $name = 'CounterCacheUser';
+	var $alias = 'User';
+	var $fixture = 'counter_cache_user';
+
+	var $hasMany = array('Post' => array(
+		'className' => 'CounterCachePost',
+		'foreignKey' => 'user_id'
+	));
+}
+
+class CounterCachePost extends CakeTestModel {
+	var $name = 'CounterCachePost';
+	var $alias = 'Post';
+	var $fixture = 'counter_cache_user';
+
+	var $belongsTo = array('User' => array(
+		'className' => 'CounterCacheUser',
+		'foreignKey' => 'user_id',
+		'counterCache' => true
+	));
+}
+
 class ArticleB extends CakeTestModel {
 	var $name = 'ArticleB';
 	var $useTable = 'articles';
@@ -2848,8 +2871,9 @@ class ArticleB extends CakeTestModel {
 			'className' => 'TagB',
 			'joinTable' => 'articles_tags',
 			'foreignKey' => 'article_id',
-			'associationForeignKey' => 'tag_id')
-			);
+			'associationForeignKey' => 'tag_id'
+		)
+	);
 }
 
 class TagB extends CakeTestModel {
@@ -2860,7 +2884,9 @@ class TagB extends CakeTestModel {
 			'className' => 'ArticleB',
 			'joinTable' => 'articles_tags',
 			'foreignKey' => 'tag_id',
-			'associationForeignKey' => 'article_id')
-			);
+			'associationForeignKey' => 'article_id'
+		)
+	);
 }
-?>
\ No newline at end of file
+
+?>
diff --git a/cake/tests/cases/libs/set.test.php b/cake/tests/cases/libs/set.test.php
index a4b702442..218b4b84b 100644
--- a/cake/tests/cases/libs/set.test.php
+++ b/cake/tests/cases/libs/set.test.php
@@ -395,28 +395,13 @@ class SetTest extends CakeTestCase {
 		);
 		$b = array('Deep' => $a[0]['Deep']);
 		$c = array(
-			array(
-				'a' => array(
-					'I' => array(
-						'a' => 1
-					)
-				)
-			),
+			array('a' => array('I' => array('a' => 1))),
 			array(
 				'a' => array(
 					2
 				)
 			),
-			array(
-				'a' => array(
-					'II' => array(
-						'a' => 3,
-						'III' => array(
-							'a' => array('foo' => 4)
-						)
-					)
-				)
-			),
+			array('a' => array('II' => array('a' => 3, 'III' => array('a' => array('foo' => 4))))),
 		);
 		
 		$nonSequential = array(
@@ -447,9 +432,25 @@ class SetTest extends CakeTestCase {
 		$this->assertEqual(Set::extract('/User/id', $a), $expected);
 		$this->assertEqual(Set::extract('/User/id', $nonSequential), $expected);
 
-		$this->assertEqual(Set::extract('/User/id', $nonZero), $expected, 'Failed non zero array key extract');
+		$result = Set::extract('/User/id', $nonZero);
+		$this->assertEqual($result, $expected, 'Failed non zero array key extract');
+		Configure::write('foo', null);
+
+		// $expected = array(
+		// 	array('id' => 1), array('id' => 2), array('id' => 3), array('id' => 4), array('id' => 5)
+		// );
+
+		$expected = array(1, 2, 3, 4, 5);
+		$this->assertEqual(Set::extract('/User/id', $a), $expected);
+		$this->assertEqual(Set::extract('/User/id', $nonSequential), $expected);
+
+		$result = Set::extract('/User/id', $nonZero);
+		$this->assertEqual($result, $expected, 'Failed non zero array key extract');
+
+		$expected = array(
+			array('id' => 1), array('id' => 2), array('id' => 3), array('id' => 4), array('id' => 5)
+		);
 
-		$expected = array(array('id' => 1), array('id' => 2), array('id' => 3), array('id' => 4), array('id' => 5));
 		$r = Set::extract('/User/id', $a, array('flatten' => false));
 		$this->assertEqual($r, $expected);
 
@@ -701,6 +702,103 @@ class SetTest extends CakeTestCase {
 		$this->assertEqual($r[1]['Comment']['User']['name'], 'dan');
 		$this->assertEqual(count($r), 2);
 
+		$r = Set::extract('/Comment/User[name=/bob|tod/]/..', $habtm);
+		$this->assertEqual($r[0]['Comment']['User']['name'], 'bob');
+
+		$this->assertEqual($r[1]['Comment']['User']['name'], 'tod');
+		$this->assertEqual(count($r), 2);
+
+		$tree = array(
+			array(
+				'Category' => array('name' => 'Category 1'),
+				'children' => array(array('Category' => array('name' => 'Category 1.1')))
+			),
+			array(
+				'Category' => array('name' => 'Category 2'),
+				'children' => array(
+					array('Category' => array('name' => 'Category 2.1')),
+					array('Category' => array('name' => 'Category 2.2'))
+				)
+			),
+			array(
+				'Category' => array('name' => 'Category 3'),
+				'children' => array(array('Category' => array('name' => 'Category 3.1')))
+			)
+		);
+
+		$expected = array(array('Category' => $tree[1]['Category']));
+		$r = Set::extract('/Category[name=Category 2]', $tree);
+		$this->assertEqual($r, $expected);
+
+		$expected = array(
+			array('Category' => $tree[1]['Category'], 'children' => $tree[1]['children'])
+		);
+		$r = Set::extract('/Category[name=Category 2]/..', $tree);
+		$this->assertEqual($r, $expected);
+
+		$expected = array(
+			array('children' => $tree[1]['children'][0]),
+			array('children' => $tree[1]['children'][1])
+		);
+		$r = Set::extract('/Category[name=Category 2]/../children', $tree);
+		$this->assertEqual($r, $expected);
+
+		$habtm = array(
+			array(
+				'Post' => array(
+					'id' => 1,
+					'title' => 'great post',
+				),
+				'Comment' => array(
+					array(
+						'id' => 1,
+						'text' => 'foo',
+						'User' => array(
+							'id' => 1,
+							'name' => 'bob'
+						),
+					),
+					array(
+						'id' => 2,
+						'text' => 'bar',
+						'User' => array(
+							'id' => 2,
+							'name' => 'tod'
+						),
+					),
+				),
+			),
+			array(
+				'Post' => array(
+					'id' => 2,
+					'title' => 'fun post',
+				),
+				'Comment' => array(
+					array(
+						'id' => 3,
+						'text' => '123',
+						'User' => array(
+							'id' => 3,
+							'name' => 'dan'
+						),
+					),
+					array(
+						'id' => 4,
+						'text' => '987',
+						'User' => array(
+							'id' => 4,
+							'name' => 'jim'
+						),
+					),
+				),
+			),
+		);
+
+		$r = Set::extract('/Comment/User[name=/bob|dan/]/..', $habtm);
+		$this->assertEqual($r[0]['Comment']['User']['name'], 'bob');
+		$this->assertEqual($r[1]['Comment']['User']['name'], 'dan');
+		$this->assertEqual(count($r), 2);
+
 		$r = Set::extract('/Comment/User[name=/bob|tod/]/..', $habtm);
 		$this->assertEqual($r[0]['Comment']['User']['name'], 'bob');
 		// Currently failing, needs fix
@@ -773,7 +871,8 @@ class SetTest extends CakeTestCase {
 		$a = array(
 			array('Article' => array('id' => 1, 'title' => 'Article 1')),
 			array('Article' => array('id' => 2, 'title' => 'Article 2')),
-			array('Article' => array('id' => 3, 'title' => 'Article 3')));
+			array('Article' => array('id' => 3, 'title' => 'Article 3'))
+		);
 
 		$this->assertTrue(Set::matches(array('id=2'), $a[1]['Article']));
 		$this->assertFalse(Set::matches(array('id>2'), $a[1]['Article']));
@@ -805,7 +904,8 @@ class SetTest extends CakeTestCase {
 		$a = array(
 			array('Article' => array('id' => 1, 'title' => 'Article 1')),
 			array('Article' => array('id' => 2, 'title' => 'Article 2')),
-			array('Article' => array('id' => 3, 'title' => 'Article 3')));
+			array('Article' => array('id' => 3, 'title' => 'Article 3'))
+		);
 
 		$result = Set::extract($a, '{n}.Article.id');
 		$expected = array( 1, 2, 3 );
@@ -824,12 +924,19 @@ class SetTest extends CakeTestCase {
 		$this->assertIdentical($result, $expected);
 
 		$a = array(
-			array('Article' => array('id' => 1, 'title' => 'Article 1',
-				'User' => array('id' => 1, 'username' => 'mariano.iglesias'))),
-			array('Article' => array('id' => 2, 'title' => 'Article 2',
-				'User' => array('id' => 1, 'username' => 'mariano.iglesias'))),
-			array('Article' => array('id' => 3, 'title' => 'Article 3',
-				'User' => array('id' => 2, 'username' => 'phpnut'))));
+			array(
+				'Article' => array('id' => 1, 'title' => 'Article 1',
+				'User' => array('id' => 1, 'username' => 'mariano.iglesias'))
+			),
+			array(
+				'Article' => array('id' => 2, 'title' => 'Article 2',
+				'User' => array('id' => 1, 'username' => 'mariano.iglesias'))
+			),
+			array(
+				'Article' => array('id' => 3, 'title' => 'Article 3',
+				'User' => array('id' => 2, 'username' => 'phpnut'))
+			)
+		);
 
 		$result = Set::extract($a, '{n}.Article.User.username');
 		$expected = array( 'mariano.iglesias', 'mariano.iglesias', 'phpnut' );
@@ -852,7 +959,11 @@ class SetTest extends CakeTestCase {
 		$this->assertIdentical($result, $expected);
 
 		$result = Set::extract($a, '{n}.Article.Comment.{n}.title');
-		$expected = array (array('Comment 10', 'Comment 11', 'Comment 12'), array('Comment 13', 'Comment 14'), null);
+		$expected = array(
+			array('Comment 10', 'Comment 11', 'Comment 12'),
+			array('Comment 13', 'Comment 14'),
+			null
+		);
 		$this->assertIdentical($result, $expected);
 
 		$a = array(array('1day' => '20 sales'), array('1day' => '2 sales'));
@@ -885,7 +996,12 @@ class SetTest extends CakeTestCase {
 		$this->assertIdentical($result, $expected);
 
 		$result = Set::extract($a,'{\w+}.{\w+}.name');
-		$expected = array(array('pages' => 'page'), array('fruites' => 'fruit'), 'test' => array('jippi'), 'dot.test' => array('jippi'));
+		$expected = array(
+			array('pages' => 'page'),
+			array('fruites' => 'fruit'),
+			'test' => array('jippi'),
+			'dot.test' => array('jippi')
+		);
 		$this->assertIdentical($result, $expected);
 
 		$result = Set::extract($a,'{\d+}.{\w+}.name');
@@ -905,7 +1021,10 @@ class SetTest extends CakeTestCase {
 		$this->assertIdentical($result, $expected);
 
 		$result = Set::extract($a,'{[a-z]}');
-		$expected = array('test' => array(array('name' => 'jippi')), 'dot.test' => array(array('name' => 'jippi')));
+		$expected = array(
+			'test' => array(array('name' => 'jippi')),
+			'dot.test' => array(array('name' => 'jippi'))
+		);
 		$this->assertIdentical($result, $expected);
 
 		$result = Set::extract($a, '{dot\.test}.{n}');
diff --git a/cake/tests/fixtures/counter_cache_post_fixture.php b/cake/tests/fixtures/counter_cache_post_fixture.php
new file mode 100644
index 000000000..fdbb5a39c
--- /dev/null
+++ b/cake/tests/fixtures/counter_cache_post_fixture.php
@@ -0,0 +1,50 @@
+<?php
+/* SVN FILE: $Id: counter_cache_fixture.php 7848 2008-11-08 02:58:37Z nate $ */
+/**
+ * Short description for file.
+ *
+ * Long description for file
+ *
+ * PHP versions 4 and 5
+ *
+ * CakePHP(tm) Tests <https://trac.cakephp.org/wiki/Developement/TestSuite>
+ * Copyright 2005-2008, Cake Software Foundation, Inc. (http://www.cakefoundation.org)
+ *
+ *  Licensed under The Open Group Test Suite License
+ *  Redistributions of files must retain the above copyright notice.
+ *
+ * @filesource
+ * @copyright     Copyright 2005-2008, Cake Software Foundation, Inc. (http://www.cakefoundation.org)
+ * @link          https://trac.cakephp.org/wiki/Developement/TestSuite CakePHP(tm) Tests
+ * @package       cake.tests
+ * @subpackage    cake.tests.fixtures
+ * @since         CakePHP(tm) v 1.2.0.4667
+ * @version       $Revision: 7848 $
+ * @modifiedby    $LastChangedBy: renan.saddam $
+ * @lastmodified  $Date: 2008-11-07 21:58:37 -0500 (Fri, 07 Nov 2008) $
+ * @license       http://www.opensource.org/licenses/opengroup.php The Open Group Test Suite License
+ */
+/**
+ * Short description for class.
+ *
+ * @package       cake.tests
+ * @subpackage    cake.tests.fixtures
+ */
+class CounterCachePostFixture extends CakeTestFixture {
+
+	var $name = 'CounterCachePost';
+    
+	var $fields = array(
+		'id' => array('type' => 'integer', 'key' => 'primary'),
+		'title' => array('type' => 'string', 'length' => 255, 'null' => false),
+		'user_id' => array('type' => 'integer', 'null' => true),
+	);
+
+    var $records = array(
+		array('id' => 1, 'title' => 'Rock and Roll',  'user_id' => 66),
+		array('id' => 2, 'title' => 'Music',   'user_id' => 66),
+		array('id' => 3, 'title' => 'Food',   'user_id' => 301),
+    );
+}
+
+?>
\ No newline at end of file
diff --git a/cake/tests/fixtures/counter_cache_user_fixture.php b/cake/tests/fixtures/counter_cache_user_fixture.php
new file mode 100644
index 000000000..3ee6ec954
--- /dev/null
+++ b/cake/tests/fixtures/counter_cache_user_fixture.php
@@ -0,0 +1,49 @@
+<?php
+/* SVN FILE: $Id: counter_cache_user_fixture.php 7848 2008-11-08 02:58:37Z nate $ */
+/**
+ * Short description for file.
+ *
+ * Long description for file
+ *
+ * PHP versions 4 and 5
+ *
+ * CakePHP(tm) Tests <https://trac.cakephp.org/wiki/Developement/TestSuite>
+ * Copyright 2005-2008, Cake Software Foundation, Inc. (http://www.cakefoundation.org)
+ *
+ *  Licensed under The Open Group Test Suite License
+ *  Redistributions of files must retain the above copyright notice.
+ *
+ * @filesource
+ * @copyright     Copyright 2005-2008, Cake Software Foundation, Inc. (http://www.cakefoundation.org)
+ * @link          https://trac.cakephp.org/wiki/Developement/TestSuite CakePHP(tm) Tests
+ * @package       cake.tests
+ * @subpackage    cake.tests.fixtures
+ * @since         CakePHP(tm) v 1.2.0.4667
+ * @version       $Revision: 7848 $
+ * @modifiedby    $LastChangedBy: renan.saddam $
+ * @lastmodified  $Date: 2008-11-07 21:58:37 -0500 (Fri, 07 Nov 2008) $
+ * @license       http://www.opensource.org/licenses/opengroup.php The Open Group Test Suite License
+ */
+/**
+ * Short description for class.
+ *
+ * @package       cake.tests
+ * @subpackage    cake.tests.fixtures
+ */
+class CounterCacheUserFixture extends CakeTestFixture {
+
+	var $name = 'CounterCacheUser';
+
+	var $fields = array(
+		'id' => array('type' => 'integer', 'key' => 'primary'),
+		'name' => array('type' => 'string', 'length' => 255, 'null' => false),
+		'post_count' => array('type' => 'integer', 'null' => true)
+	);
+
+	var $records = array(
+		array('id' => 66, 'name' => 'Alexander','post_count' => 2),
+		array('id' => 301, 'name' => 'Steven','post_count' => 1),
+	);
+}
+
+?>
\ No newline at end of file