Skip to content
This repository
Browse code

Move nest() over

Make get() able to take arrays for $path.
  • Loading branch information...
commit 239f52c48ca124ee51820a04619778a5f176c0ea 1 parent afa0329
Mark Story authored February 22, 2012
419  lib/Cake/Test/Case/Utility/Set2Test.php
@@ -179,6 +179,9 @@ public function testGet() {
179 179
 
180 180
 		$result = Set2::get($data, '1.Article');
181 181
 		$this->assertEquals($data[1]['Article'], $result);
  182
+
  183
+		$result = Set2::get($data, array('1', 'Article'));
  184
+		$this->assertEquals($data[1]['Article'], $result);
182 185
 	}
183 186
 
184 187
 /**
@@ -1419,4 +1422,420 @@ public function _mapCallback($value) {
1419 1422
 	public function _reduceCallback($one, $two) {
1420 1423
 		return $one + $two;
1421 1424
 	}
  1425
+
  1426
+/**
  1427
+ * test Set nest with a normal model result set. For kicks rely on Set nest detecting the key names
  1428
+ * automatically
  1429
+ *
  1430
+ * @return void
  1431
+ */
  1432
+	public function testNestModel() {
  1433
+		$input = array(
  1434
+			array(
  1435
+				'ModelName' => array(
  1436
+					'id' => 1,
  1437
+					'parent_id' => null
  1438
+				),
  1439
+			),
  1440
+			array(
  1441
+				'ModelName' => array(
  1442
+					'id' => 2,
  1443
+					'parent_id' => 1
  1444
+				),
  1445
+			),
  1446
+			array(
  1447
+				'ModelName' => array(
  1448
+					'id' => 3,
  1449
+					'parent_id' => 1
  1450
+				),
  1451
+			),
  1452
+			array(
  1453
+				'ModelName' => array(
  1454
+					'id' => 4,
  1455
+					'parent_id' => 1
  1456
+				),
  1457
+			),
  1458
+			array(
  1459
+				'ModelName' => array(
  1460
+					'id' => 5,
  1461
+					'parent_id' => 1
  1462
+				),
  1463
+			),
  1464
+			array(
  1465
+				'ModelName' => array(
  1466
+					'id' => 6,
  1467
+					'parent_id' => null
  1468
+				),
  1469
+			),
  1470
+			array(
  1471
+				'ModelName' => array(
  1472
+					'id' => 7,
  1473
+					'parent_id' => 6
  1474
+				),
  1475
+			),
  1476
+			array(
  1477
+				'ModelName' => array(
  1478
+					'id' => 8,
  1479
+					'parent_id' => 6
  1480
+				),
  1481
+			),
  1482
+			array(
  1483
+				'ModelName' => array(
  1484
+					'id' => 9,
  1485
+					'parent_id' => 6
  1486
+				),
  1487
+			),
  1488
+			array(
  1489
+				'ModelName' => array(
  1490
+					'id' => 10,
  1491
+					'parent_id' => 6
  1492
+				)
  1493
+			)
  1494
+		);
  1495
+		$expected = array(
  1496
+			array(
  1497
+				'ModelName' => array(
  1498
+					'id' => 1,
  1499
+					'parent_id' => null
  1500
+				),
  1501
+				'children' => array(
  1502
+					array(
  1503
+						'ModelName' => array(
  1504
+							'id' => 2,
  1505
+							'parent_id' => 1
  1506
+						),
  1507
+						'children' => array()
  1508
+					),
  1509
+					array(
  1510
+						'ModelName' => array(
  1511
+							'id' => 3,
  1512
+							'parent_id' => 1
  1513
+						),
  1514
+						'children' => array()
  1515
+					),
  1516
+					array(
  1517
+						'ModelName' => array(
  1518
+							'id' => 4,
  1519
+							'parent_id' => 1
  1520
+						),
  1521
+						'children' => array()
  1522
+					),
  1523
+					array(
  1524
+						'ModelName' => array(
  1525
+							'id' => 5,
  1526
+							'parent_id' => 1
  1527
+						),
  1528
+						'children' => array()
  1529
+					),
  1530
+
  1531
+				)
  1532
+			),
  1533
+			array(
  1534
+				'ModelName' => array(
  1535
+					'id' => 6,
  1536
+					'parent_id' => null
  1537
+				),
  1538
+				'children' => array(
  1539
+					array(
  1540
+						'ModelName' => array(
  1541
+							'id' => 7,
  1542
+							'parent_id' => 6
  1543
+						),
  1544
+						'children' => array()
  1545
+					),
  1546
+					array(
  1547
+						'ModelName' => array(
  1548
+							'id' => 8,
  1549
+							'parent_id' => 6
  1550
+						),
  1551
+						'children' => array()
  1552
+					),
  1553
+					array(
  1554
+						'ModelName' => array(
  1555
+							'id' => 9,
  1556
+							'parent_id' => 6
  1557
+						),
  1558
+						'children' => array()
  1559
+					),
  1560
+					array(
  1561
+						'ModelName' => array(
  1562
+							'id' => 10,
  1563
+							'parent_id' => 6
  1564
+						),
  1565
+						'children' => array()
  1566
+					)
  1567
+				)
  1568
+			)
  1569
+		);
  1570
+		$result = Set2::nest($input);
  1571
+		$this->assertEquals($expected, $result);
  1572
+	}
  1573
+
  1574
+/**
  1575
+ * test Set nest with a normal model result set, and a nominated root id
  1576
+ *
  1577
+ * @return void
  1578
+ */
  1579
+	public function testNestModelExplicitRoot() {
  1580
+		$input = array(
  1581
+			array(
  1582
+				'ModelName' => array(
  1583
+					'id' => 1,
  1584
+					'parent_id' => null
  1585
+				),
  1586
+			),
  1587
+			array(
  1588
+				'ModelName' => array(
  1589
+					'id' => 2,
  1590
+					'parent_id' => 1
  1591
+				),
  1592
+			),
  1593
+			array(
  1594
+				'ModelName' => array(
  1595
+					'id' => 3,
  1596
+					'parent_id' => 1
  1597
+				),
  1598
+			),
  1599
+			array(
  1600
+				'ModelName' => array(
  1601
+					'id' => 4,
  1602
+					'parent_id' => 1
  1603
+				),
  1604
+			),
  1605
+			array(
  1606
+				'ModelName' => array(
  1607
+					'id' => 5,
  1608
+					'parent_id' => 1
  1609
+				),
  1610
+			),
  1611
+			array(
  1612
+				'ModelName' => array(
  1613
+					'id' => 6,
  1614
+					'parent_id' => null
  1615
+				),
  1616
+			),
  1617
+			array(
  1618
+				'ModelName' => array(
  1619
+					'id' => 7,
  1620
+					'parent_id' => 6
  1621
+				),
  1622
+			),
  1623
+			array(
  1624
+				'ModelName' => array(
  1625
+					'id' => 8,
  1626
+					'parent_id' => 6
  1627
+				),
  1628
+			),
  1629
+			array(
  1630
+				'ModelName' => array(
  1631
+					'id' => 9,
  1632
+					'parent_id' => 6
  1633
+				),
  1634
+			),
  1635
+			array(
  1636
+				'ModelName' => array(
  1637
+					'id' => 10,
  1638
+					'parent_id' => 6
  1639
+				)
  1640
+			)
  1641
+		);
  1642
+		$expected = array(
  1643
+			array(
  1644
+				'ModelName' => array(
  1645
+					'id' => 6,
  1646
+					'parent_id' => null
  1647
+				),
  1648
+				'children' => array(
  1649
+					array(
  1650
+						'ModelName' => array(
  1651
+							'id' => 7,
  1652
+							'parent_id' => 6
  1653
+						),
  1654
+						'children' => array()
  1655
+					),
  1656
+					array(
  1657
+						'ModelName' => array(
  1658
+							'id' => 8,
  1659
+							'parent_id' => 6
  1660
+						),
  1661
+						'children' => array()
  1662
+					),
  1663
+					array(
  1664
+						'ModelName' => array(
  1665
+							'id' => 9,
  1666
+							'parent_id' => 6
  1667
+						),
  1668
+						'children' => array()
  1669
+					),
  1670
+					array(
  1671
+						'ModelName' => array(
  1672
+							'id' => 10,
  1673
+							'parent_id' => 6
  1674
+						),
  1675
+						'children' => array()
  1676
+					)
  1677
+				)
  1678
+			)
  1679
+		);
  1680
+		$result = Set2::nest($input, array('root' => 6));
  1681
+		$this->assertEquals($expected, $result);
  1682
+	}
  1683
+
  1684
+/**
  1685
+ * test Set nest with a 1d array - this method should be able to handle any type of array input
  1686
+ *
  1687
+ * @return void
  1688
+ */
  1689
+	public function testNest1Dimensional() {
  1690
+		$input = array(
  1691
+			array(
  1692
+				'id' => 1,
  1693
+				'parent_id' => null
  1694
+			),
  1695
+			array(
  1696
+				'id' => 2,
  1697
+				'parent_id' => 1
  1698
+			),
  1699
+			array(
  1700
+				'id' => 3,
  1701
+				'parent_id' => 1
  1702
+			),
  1703
+			array(
  1704
+				'id' => 4,
  1705
+				'parent_id' => 1
  1706
+			),
  1707
+			array(
  1708
+				'id' => 5,
  1709
+				'parent_id' => 1
  1710
+			),
  1711
+			array(
  1712
+				'id' => 6,
  1713
+				'parent_id' => null
  1714
+			),
  1715
+			array(
  1716
+				'id' => 7,
  1717
+				'parent_id' => 6
  1718
+			),
  1719
+			array(
  1720
+				'id' => 8,
  1721
+				'parent_id' => 6
  1722
+			),
  1723
+			array(
  1724
+				'id' => 9,
  1725
+				'parent_id' => 6
  1726
+			),
  1727
+			array(
  1728
+				'id' => 10,
  1729
+				'parent_id' => 6
  1730
+			)
  1731
+		);
  1732
+		$expected = array(
  1733
+			array(
  1734
+				'id' => 1,
  1735
+				'parent_id' => null,
  1736
+				'children' => array(
  1737
+					array(
  1738
+						'id' => 2,
  1739
+						'parent_id' => 1,
  1740
+						'children' => array()
  1741
+					),
  1742
+					array(
  1743
+						'id' => 3,
  1744
+						'parent_id' => 1,
  1745
+						'children' => array()
  1746
+					),
  1747
+					array(
  1748
+						'id' => 4,
  1749
+						'parent_id' => 1,
  1750
+						'children' => array()
  1751
+					),
  1752
+					array(
  1753
+						'id' => 5,
  1754
+						'parent_id' => 1,
  1755
+						'children' => array()
  1756
+					),
  1757
+
  1758
+				)
  1759
+			),
  1760
+			array(
  1761
+				'id' => 6,
  1762
+				'parent_id' => null,
  1763
+				'children' => array(
  1764
+					array(
  1765
+						'id' => 7,
  1766
+						'parent_id' => 6,
  1767
+						'children' => array()
  1768
+					),
  1769
+					array(
  1770
+						'id' => 8,
  1771
+						'parent_id' => 6,
  1772
+						'children' => array()
  1773
+					),
  1774
+					array(
  1775
+						'id' => 9,
  1776
+						'parent_id' => 6,
  1777
+						'children' => array()
  1778
+					),
  1779
+					array(
  1780
+						'id' => 10,
  1781
+						'parent_id' => 6,
  1782
+						'children' => array()
  1783
+					)
  1784
+				)
  1785
+			)
  1786
+		);
  1787
+		$result = Set2::nest($input, array('idPath' => '{n}.id', 'parentPath' => '{n}.parent_id'));
  1788
+		$this->assertEquals($expected, $result);
  1789
+	}
  1790
+
  1791
+/**
  1792
+ * test Set nest with no specified parent data.
  1793
+ *
  1794
+ * The result should be the same as the input.
  1795
+ * For an easier comparison, unset all the empty children arrays from the result
  1796
+ *
  1797
+ * @return void
  1798
+ */
  1799
+	public function testMissingParent() {
  1800
+		$input = array(
  1801
+			array(
  1802
+				'id' => 1,
  1803
+			),
  1804
+			array(
  1805
+				'id' => 2,
  1806
+			),
  1807
+			array(
  1808
+				'id' => 3,
  1809
+			),
  1810
+			array(
  1811
+				'id' => 4,
  1812
+			),
  1813
+			array(
  1814
+				'id' => 5,
  1815
+			),
  1816
+			array(
  1817
+				'id' => 6,
  1818
+			),
  1819
+			array(
  1820
+				'id' => 7,
  1821
+			),
  1822
+			array(
  1823
+				'id' => 8,
  1824
+			),
  1825
+			array(
  1826
+				'id' => 9,
  1827
+			),
  1828
+			array(
  1829
+				'id' => 10,
  1830
+			)
  1831
+		);
  1832
+
  1833
+		$result = Set2::nest($input, array('idPath' => '{n}.id', 'parentPath' => '{n}.parent_id'));
  1834
+		foreach($result as &$row) {
  1835
+			if (empty($row['children'])) {
  1836
+				unset($row['children']);
  1837
+			}
  1838
+		}
  1839
+		$this->assertEquals($input, $result);
  1840
+	}
1422 1841
 }
74  lib/Cake/Utility/Set2.php
@@ -43,7 +43,11 @@ public static function get(array $data, $path) {
43 43
 		if (empty($data) || empty($path)) {
44 44
 			return null;
45 45
 		}
46  
-		$parts = explode('.', $path);
  46
+		if (is_string($path)) {
  47
+			$parts = explode('.', $path);
  48
+		} else {
  49
+			$parts = $path;
  50
+		}
47 51
 		while (($key = array_shift($parts)) !== null) {
48 52
 			if (is_array($data) && isset($data[$key])) {
49 53
 				$data =& $data[$key];
@@ -810,4 +814,72 @@ public static function normalize(array $data, $assoc = true) {
810 814
 		return $data;
811 815
 	}
812 816
 
  817
+/**
  818
+ * Takes in a flat array and returns a nested array
  819
+ *
  820
+ * @param mixed $data
  821
+ * @param array $options Options are:
  822
+ *      children   - the key name to use in the resultset for children
  823
+ *      idPath     - the path to a key that identifies each entry
  824
+ *      parentPath - the path to a key that identifies the parent of each entry
  825
+ *      root       - the id of the desired top-most result
  826
+ * @return array of results, nested
  827
+ * @link
  828
+ */
  829
+	public static function nest($data, $options = array()) {
  830
+		if (!$data) {
  831
+			return $data;
  832
+		}
  833
+
  834
+		$alias = key(current($data));
  835
+		$options += array(
  836
+			'idPath' => "{n}.$alias.id",
  837
+			'parentPath' => "{n}.$alias.parent_id",
  838
+			'children' => 'children',
  839
+			'root' => null
  840
+		);
  841
+
  842
+		$return = $idMap = array();
  843
+		$ids = self::extract($data, $options['idPath']);
  844
+
  845
+		$idKeys = explode('.', $options['idPath']);
  846
+		array_shift($idKeys);
  847
+
  848
+		$parentKeys = explode('.', $options['parentPath']);
  849
+		array_shift($parentKeys);
  850
+
  851
+		foreach ($data as $result) {
  852
+			$result[$options['children']] = array();
  853
+
  854
+			$id = self::get($result, $idKeys);
  855
+			$parentId = self::get($result, $parentKeys);
  856
+
  857
+			if (isset($idMap[$id][$options['children']])) {
  858
+				$idMap[$id] = array_merge($result, (array)$idMap[$id]);
  859
+			} else {
  860
+				$idMap[$id] = array_merge($result, array($options['children'] => array()));
  861
+			}
  862
+			if (!$parentId || !in_array($parentId, $ids)) {
  863
+				$return[] =& $idMap[$id];
  864
+			} else {
  865
+				$idMap[$parentId][$options['children']][] =& $idMap[$id];
  866
+			}
  867
+		}
  868
+
  869
+		if ($options['root']) {
  870
+			$root = $options['root'];
  871
+		} else {
  872
+			$root = self::get($return[0], $parentKeys);
  873
+		}
  874
+
  875
+		foreach ($return as $i => $result) {
  876
+			$id = self::get($result, $idKeys);
  877
+			$parentId = self::get($result, $parentKeys);
  878
+			if ($id !== $root && $parentId != $root) {
  879
+				unset($return[$i]);
  880
+			}
  881
+		}
  882
+		return array_values($return);
  883
+	}
  884
+
813 885
 }

0 notes on commit 239f52c

Please sign in to comment.
Something went wrong with that request. Please try again.