mirror of
https://github.com/kamilwylegala/cakephp2-php8.git
synced 2025-01-31 09:06:17 +00:00
Merge branch 'feature/set-nest' into 2.1
Conflicts: lib/Cake/Model/Model.php
This commit is contained in:
commit
a5240e23ab
4 changed files with 516 additions and 50 deletions
|
@ -2812,44 +2812,10 @@ 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);
|
||||
|
||||
if (isset($results[0][$this->alias]) && !array_key_exists('parent_id', $results[0][$this->alias])) {
|
||||
trigger_error(
|
||||
__d('cake_dev', 'You cannot use find("threaded") on models without a "parent_id" field.'),
|
||||
E_USER_WARNING
|
||||
);
|
||||
return $return;
|
||||
}
|
||||
|
||||
foreach ($results as $result) {
|
||||
$result['children'] = array();
|
||||
$id = $result[$this->alias][$this->primaryKey];
|
||||
$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(
|
||||
'idPath' => '/' . $this->alias . '/' . $this->primaryKey,
|
||||
'parentPath' => '/' . $this->alias . '/parent_id'
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
*
|
||||
|
|
|
@ -3137,4 +3137,420 @@ class SetTest extends CakeTestCase {
|
|||
$expected = array('one' => array('a', 'b', 'c' => 'cee'), 'two' => 2, 'three' => null);
|
||||
$this->assertEquals($expected, $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* test Set nest with a normal model result set. For kicks rely on Set nest detecting the key names
|
||||
* automatically
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testNestModel() {
|
||||
$input = array(
|
||||
array(
|
||||
'ModelName' => array(
|
||||
'id' => 1,
|
||||
'parent_id' => null
|
||||
),
|
||||
),
|
||||
array(
|
||||
'ModelName' => array(
|
||||
'id' => 2,
|
||||
'parent_id' => 1
|
||||
),
|
||||
),
|
||||
array(
|
||||
'ModelName' => array(
|
||||
'id' => 3,
|
||||
'parent_id' => 1
|
||||
),
|
||||
),
|
||||
array(
|
||||
'ModelName' => array(
|
||||
'id' => 4,
|
||||
'parent_id' => 1
|
||||
),
|
||||
),
|
||||
array(
|
||||
'ModelName' => array(
|
||||
'id' => 5,
|
||||
'parent_id' => 1
|
||||
),
|
||||
),
|
||||
array(
|
||||
'ModelName' => array(
|
||||
'id' => 6,
|
||||
'parent_id' => null
|
||||
),
|
||||
),
|
||||
array(
|
||||
'ModelName' => array(
|
||||
'id' => 7,
|
||||
'parent_id' => 6
|
||||
),
|
||||
),
|
||||
array(
|
||||
'ModelName' => array(
|
||||
'id' => 8,
|
||||
'parent_id' => 6
|
||||
),
|
||||
),
|
||||
array(
|
||||
'ModelName' => array(
|
||||
'id' => 9,
|
||||
'parent_id' => 6
|
||||
),
|
||||
),
|
||||
array(
|
||||
'ModelName' => array(
|
||||
'id' => 10,
|
||||
'parent_id' => 6
|
||||
)
|
||||
)
|
||||
);
|
||||
$expected = array(
|
||||
array(
|
||||
'ModelName' => array(
|
||||
'id' => 1,
|
||||
'parent_id' => null
|
||||
),
|
||||
'children' => array(
|
||||
array(
|
||||
'ModelName' => array(
|
||||
'id' => 2,
|
||||
'parent_id' => 1
|
||||
),
|
||||
'children' => array()
|
||||
),
|
||||
array(
|
||||
'ModelName' => array(
|
||||
'id' => 3,
|
||||
'parent_id' => 1
|
||||
),
|
||||
'children' => array()
|
||||
),
|
||||
array(
|
||||
'ModelName' => array(
|
||||
'id' => 4,
|
||||
'parent_id' => 1
|
||||
),
|
||||
'children' => array()
|
||||
),
|
||||
array(
|
||||
'ModelName' => array(
|
||||
'id' => 5,
|
||||
'parent_id' => 1
|
||||
),
|
||||
'children' => array()
|
||||
),
|
||||
|
||||
)
|
||||
),
|
||||
array(
|
||||
'ModelName' => array(
|
||||
'id' => 6,
|
||||
'parent_id' => null
|
||||
),
|
||||
'children' => array(
|
||||
array(
|
||||
'ModelName' => array(
|
||||
'id' => 7,
|
||||
'parent_id' => 6
|
||||
),
|
||||
'children' => array()
|
||||
),
|
||||
array(
|
||||
'ModelName' => array(
|
||||
'id' => 8,
|
||||
'parent_id' => 6
|
||||
),
|
||||
'children' => array()
|
||||
),
|
||||
array(
|
||||
'ModelName' => array(
|
||||
'id' => 9,
|
||||
'parent_id' => 6
|
||||
),
|
||||
'children' => array()
|
||||
),
|
||||
array(
|
||||
'ModelName' => array(
|
||||
'id' => 10,
|
||||
'parent_id' => 6
|
||||
),
|
||||
'children' => array()
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
$result = Set::nest($input);
|
||||
$this->assertEquals($expected, $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* test Set nest with a normal model result set, and a nominated root id
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testNestModelExplicitRoot() {
|
||||
$input = array(
|
||||
array(
|
||||
'ModelName' => array(
|
||||
'id' => 1,
|
||||
'parent_id' => null
|
||||
),
|
||||
),
|
||||
array(
|
||||
'ModelName' => array(
|
||||
'id' => 2,
|
||||
'parent_id' => 1
|
||||
),
|
||||
),
|
||||
array(
|
||||
'ModelName' => array(
|
||||
'id' => 3,
|
||||
'parent_id' => 1
|
||||
),
|
||||
),
|
||||
array(
|
||||
'ModelName' => array(
|
||||
'id' => 4,
|
||||
'parent_id' => 1
|
||||
),
|
||||
),
|
||||
array(
|
||||
'ModelName' => array(
|
||||
'id' => 5,
|
||||
'parent_id' => 1
|
||||
),
|
||||
),
|
||||
array(
|
||||
'ModelName' => array(
|
||||
'id' => 6,
|
||||
'parent_id' => null
|
||||
),
|
||||
),
|
||||
array(
|
||||
'ModelName' => array(
|
||||
'id' => 7,
|
||||
'parent_id' => 6
|
||||
),
|
||||
),
|
||||
array(
|
||||
'ModelName' => array(
|
||||
'id' => 8,
|
||||
'parent_id' => 6
|
||||
),
|
||||
),
|
||||
array(
|
||||
'ModelName' => array(
|
||||
'id' => 9,
|
||||
'parent_id' => 6
|
||||
),
|
||||
),
|
||||
array(
|
||||
'ModelName' => array(
|
||||
'id' => 10,
|
||||
'parent_id' => 6
|
||||
)
|
||||
)
|
||||
);
|
||||
$expected = array(
|
||||
array(
|
||||
'ModelName' => array(
|
||||
'id' => 6,
|
||||
'parent_id' => null
|
||||
),
|
||||
'children' => array(
|
||||
array(
|
||||
'ModelName' => array(
|
||||
'id' => 7,
|
||||
'parent_id' => 6
|
||||
),
|
||||
'children' => array()
|
||||
),
|
||||
array(
|
||||
'ModelName' => array(
|
||||
'id' => 8,
|
||||
'parent_id' => 6
|
||||
),
|
||||
'children' => array()
|
||||
),
|
||||
array(
|
||||
'ModelName' => array(
|
||||
'id' => 9,
|
||||
'parent_id' => 6
|
||||
),
|
||||
'children' => array()
|
||||
),
|
||||
array(
|
||||
'ModelName' => array(
|
||||
'id' => 10,
|
||||
'parent_id' => 6
|
||||
),
|
||||
'children' => array()
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
$result = Set::nest($input, array('root' => 6));
|
||||
$this->assertEquals($expected, $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* test Set nest with a 1d array - this method should be able to handle any type of array input
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testNest1Dimensional() {
|
||||
$input = array(
|
||||
array(
|
||||
'id' => 1,
|
||||
'parent_id' => null
|
||||
),
|
||||
array(
|
||||
'id' => 2,
|
||||
'parent_id' => 1
|
||||
),
|
||||
array(
|
||||
'id' => 3,
|
||||
'parent_id' => 1
|
||||
),
|
||||
array(
|
||||
'id' => 4,
|
||||
'parent_id' => 1
|
||||
),
|
||||
array(
|
||||
'id' => 5,
|
||||
'parent_id' => 1
|
||||
),
|
||||
array(
|
||||
'id' => 6,
|
||||
'parent_id' => null
|
||||
),
|
||||
array(
|
||||
'id' => 7,
|
||||
'parent_id' => 6
|
||||
),
|
||||
array(
|
||||
'id' => 8,
|
||||
'parent_id' => 6
|
||||
),
|
||||
array(
|
||||
'id' => 9,
|
||||
'parent_id' => 6
|
||||
),
|
||||
array(
|
||||
'id' => 10,
|
||||
'parent_id' => 6
|
||||
)
|
||||
);
|
||||
$expected = array(
|
||||
array(
|
||||
'id' => 1,
|
||||
'parent_id' => null,
|
||||
'children' => array(
|
||||
array(
|
||||
'id' => 2,
|
||||
'parent_id' => 1,
|
||||
'children' => array()
|
||||
),
|
||||
array(
|
||||
'id' => 3,
|
||||
'parent_id' => 1,
|
||||
'children' => array()
|
||||
),
|
||||
array(
|
||||
'id' => 4,
|
||||
'parent_id' => 1,
|
||||
'children' => array()
|
||||
),
|
||||
array(
|
||||
'id' => 5,
|
||||
'parent_id' => 1,
|
||||
'children' => array()
|
||||
),
|
||||
|
||||
)
|
||||
),
|
||||
array(
|
||||
'id' => 6,
|
||||
'parent_id' => null,
|
||||
'children' => array(
|
||||
array(
|
||||
'id' => 7,
|
||||
'parent_id' => 6,
|
||||
'children' => array()
|
||||
),
|
||||
array(
|
||||
'id' => 8,
|
||||
'parent_id' => 6,
|
||||
'children' => array()
|
||||
),
|
||||
array(
|
||||
'id' => 9,
|
||||
'parent_id' => 6,
|
||||
'children' => array()
|
||||
),
|
||||
array(
|
||||
'id' => 10,
|
||||
'parent_id' => 6,
|
||||
'children' => array()
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
$result = Set::nest($input, array('idPath' => '/id', 'parentPath' => '/parent_id'));
|
||||
$this->assertEquals($expected, $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* test Set nest with no specified parent data.
|
||||
*
|
||||
* The result should be the same as the input.
|
||||
* For an easier comparison, unset all the empty children arrays from the result
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testMissingParent() {
|
||||
$input = array(
|
||||
array(
|
||||
'id' => 1,
|
||||
),
|
||||
array(
|
||||
'id' => 2,
|
||||
),
|
||||
array(
|
||||
'id' => 3,
|
||||
),
|
||||
array(
|
||||
'id' => 4,
|
||||
),
|
||||
array(
|
||||
'id' => 5,
|
||||
),
|
||||
array(
|
||||
'id' => 6,
|
||||
),
|
||||
array(
|
||||
'id' => 7,
|
||||
),
|
||||
array(
|
||||
'id' => 8,
|
||||
),
|
||||
array(
|
||||
'id' => 9,
|
||||
),
|
||||
array(
|
||||
'id' => 10,
|
||||
)
|
||||
);
|
||||
|
||||
$result = Set::nest($input, array('idPath' => '/id', 'parentPath' => '/parent_id'));
|
||||
foreach($result as &$row) {
|
||||
if (empty($row['children'])) {
|
||||
unset($row['children']);
|
||||
}
|
||||
}
|
||||
$this->assertEquals($input, $result);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1114,4 +1114,100 @@ class Set {
|
|||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes in a flat array and returns a nested array
|
||||
*
|
||||
* @param mixed $data
|
||||
* @param array $options Options are:
|
||||
* children - the key name to use in the resultset for children
|
||||
* idPath - the path to a key that identifies each entry
|
||||
* parentPath - the path to a key that identifies the parent of each entry
|
||||
* root - the id of the desired top-most result
|
||||
* @return array of results, nested
|
||||
* @link
|
||||
*/
|
||||
public static function nest($data, $options = array()) {
|
||||
if (!$data) {
|
||||
return $data;
|
||||
}
|
||||
|
||||
$alias = key(current($data));
|
||||
$options += array(
|
||||
'idPath' => "/$alias/id",
|
||||
'parentPath' => "/$alias/parent_id",
|
||||
'children' => 'children',
|
||||
'root' => null
|
||||
);
|
||||
|
||||
$return = $idMap = array();
|
||||
$ids = Set::extract($data, $options['idPath']);
|
||||
$idKeys = explode('/', trim($options['idPath'], '/'));
|
||||
$parentKeys = explode('/', trim($options['parentPath'], '/'));
|
||||
|
||||
foreach ($data as $result) {
|
||||
$result[$options['children']] = array();
|
||||
|
||||
$id = Set::get($result, $idKeys);
|
||||
$parentId = Set::get($result, $parentKeys);
|
||||
|
||||
if (isset($idMap[$id][$options['children']])) {
|
||||
$idMap[$id] = array_merge($result, (array)$idMap[$id]);
|
||||
} else {
|
||||
$idMap[$id] = array_merge($result, array($options['children'] => array()));
|
||||
}
|
||||
if (!$parentId || !in_array($parentId, $ids)) {
|
||||
$return[] =& $idMap[$id];
|
||||
} else {
|
||||
$idMap[$parentId][$options['children']][] =& $idMap[$id];
|
||||
}
|
||||
}
|
||||
|
||||
if ($options['root']) {
|
||||
$root = $options['root'];
|
||||
} else {
|
||||
$root = Set::get($return[0], $parentKeys);
|
||||
}
|
||||
|
||||
foreach ($return as $i => $result) {
|
||||
$id = Set::get($result, $idKeys);
|
||||
$parentId = Set::get($result, $parentKeys);
|
||||
if ($id !== $root && $parentId != $root) {
|
||||
unset($return[$i]);
|
||||
}
|
||||
}
|
||||
|
||||
return array_values($return);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the value at the specified position
|
||||
*
|
||||
* @param mixed $input an array
|
||||
* @param mixed $path string or array of array keys
|
||||
* @return the value at the specified position or null if it doesn't exist
|
||||
*/
|
||||
public static function get($input, $path = null) {
|
||||
if (is_string($path)) {
|
||||
if (strpos($path, '/') !== false) {
|
||||
$keys = explode('/', trim($path, '/'));
|
||||
} else {
|
||||
$keys = explode('.', trim($path, '.'));
|
||||
}
|
||||
} else {
|
||||
$keys = $path;
|
||||
}
|
||||
if (!$keys) {
|
||||
return $input;
|
||||
}
|
||||
|
||||
$return = $input;
|
||||
foreach($keys as $key) {
|
||||
if (!isset($return[$key])) {
|
||||
return null;
|
||||
}
|
||||
$return = $return[$key];
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue