diff --git a/lib/Cake/Model/Model.php b/lib/Cake/Model/Model.php index 8613634a9..4b77d881e 100644 --- a/lib/Cake/Model/Model.php +++ b/lib/Cake/Model/Model.php @@ -2812,43 +2812,12 @@ class Model extends Object implements CakeEventListener { if ($state === 'before') { return $query; } elseif ($state === 'after') { - $return = $idMap = array(); - $ids = Set::extract($results, '{n}.' . $this->alias . '.' . $this->primaryKey); - - foreach ($results as $result) { - $result['children'] = array(); - $id = $result[$this->alias][$this->primaryKey]; - if (!isset($result[$this->alias]['parent_id'])) { - trigger_error( - __d('cake_dev', 'You cannot use find("threaded") on models without a "parent_id" field.'), - E_USER_WARNING - ); - return $return; - } - $parentId = $result[$this->alias]['parent_id']; - if (isset($idMap[$id]['children'])) { - $idMap[$id] = array_merge($result, (array)$idMap[$id]); - } else { - $idMap[$id] = array_merge($result, array('children' => array())); - } - if (!$parentId || !in_array($parentId, $ids)) { - $return[] =& $idMap[$id]; - } else { - $idMap[$parentId]['children'][] =& $idMap[$id]; - } - } - if (count($return) > 1) { - $ids = array_unique(Set::extract('/' . $this->alias . '/parent_id', $return)); - if (count($ids) > 1) { - $root = $return[0][$this->alias]['parent_id']; - foreach ($return as $key => $value) { - if ($value[$this->alias]['parent_id'] != $root) { - unset($return[$key]); - } - } - } - } - return $return; + return Set::nest($results, array( + 'alias' => $this->alias, + 'primaryKey' => $this->primaryKey, + 'parent' => 'parent_id', + 'children' => 'children' + )); } } diff --git a/lib/Cake/Test/Case/Model/ModelReadTest.php b/lib/Cake/Test/Case/Model/ModelReadTest.php index 71072a6a9..8660714da 100644 --- a/lib/Cake/Test/Case/Model/ModelReadTest.php +++ b/lib/Cake/Test/Case/Model/ModelReadTest.php @@ -2990,18 +2990,6 @@ class ModelReadTest extends BaseModelTest { $this->assertEquals($afterFindData, $noAfterFindData); } -/** - * find(threaded) should trigger errors whne there is no parent_id field. - * - * @expectedException PHPUnit_Framework_Error_Warning - * @return void - */ - public function testFindThreadedError() { - $this->loadFixtures('Apple', 'Sample'); - $Apple = new Apple(); - $Apple->find('threaded'); - } - /** * testFindAllThreaded method * diff --git a/lib/Cake/Utility/Set.php b/lib/Cake/Utility/Set.php index a62726708..637ce785d 100644 --- a/lib/Cake/Utility/Set.php +++ b/lib/Cake/Utility/Set.php @@ -1114,4 +1114,64 @@ class Set { } return null; } + +/** + * Takes in a flat 2 dimensional array and returns a nested array + * + * @param mixed $data + * @param array $options Options are: + * alias - the first array key to look for + * primaryKey - the key to use to identify the rows + * parentId - the key to use to identify the parent + * children - the key name to use in the resultset for children + * @return array of results, nested + * @link + */ + public static function nest($data, $options = array()) { + if (!$data) { + return $data; + } + + $options = array( + 'alias' => key(current($data)), + 'primaryKey' => 'id', + 'parentId' => 'parent_id', + 'children' => 'children' + ) + $options; + + $return = $idMap = array(); + $ids = Set::extract($data, '{n}.' . $options['alias'] . '.' . $options['primaryKey']); + + foreach ($data as $result) { + $result[$options['children']] = array(); + $id = $result[$options['alias']][$options['primaryKey']]; + if (isset($result[$options['alias']][$options['parentId']])) { + $parentId = $result[$options['alias']][$options['parentId']]; + } else { + $parentId = null; + } + if (isset($idMap[$id]['children'])) { + $idMap[$id] = array_merge($result, (array)$idMap[$id]); + } else { + $idMap[$id] = array_merge($result, array('children' => array())); + } + if (!$parentId || !in_array($parentId, $ids)) { + $return[] =& $idMap[$id]; + } else { + $idMap[$parentId]['children'][] =& $idMap[$id]; + } + } + if (count($return) > 1) { + $ids = array_unique(Set::extract('/' . $options['alias'] . '/' . $options['parentId'], $return)); + if (count($ids) > 1) { + $root = $return[0][$options['alias']][$options['parentId']]; + foreach ($return as $key => $value) { + if ($value[$options['alias']][$options['parentId']] != $root) { + unset($return[$key]); + } + } + } + } + return $return; + } }