rpmorrow Posted January 17, 2010 Share Posted January 17, 2010 Hi, I have a DB table with the following columns [id] [parent_id] 1 0 6 0 7 9 8 9 9 10 10 0 I want to read from the DB and output it like a hierarchical structure. I keep trying with arrays and foreach loops but am failing. There is just some logic I'm overlooking I think. The output should look like this 1 6 10 9 7 Can anyone help me please? Link to comment https://forums.phpfreaks.com/topic/188801-organising-hierarchical-data-in-an-array-using-foreach/ Share on other sites More sharing options...
Catfish Posted January 17, 2010 Share Posted January 17, 2010 i dont get what you are trying to do. Link to comment https://forums.phpfreaks.com/topic/188801-organising-hierarchical-data-in-an-array-using-foreach/#findComment-996740 Share on other sites More sharing options...
rpmorrow Posted January 17, 2010 Author Share Posted January 17, 2010 It is for creating a menu (each row represents an item in the menu). "parent_id" contains a value representing the "id" of the menu level above that row. Anything with a "parent_id" of 0 is a top level item. id=9 is a sublevel of id=10 id=7 and id=8 are sublevels of id=9 I missed a digit from the ouptut in my first post It should be; The output should look like this 1 6 10 9 7 8 Link to comment https://forums.phpfreaks.com/topic/188801-organising-hierarchical-data-in-an-array-using-foreach/#findComment-996747 Share on other sites More sharing options...
ignace Posted January 17, 2010 Share Posted January 17, 2010 Use the composite pattern to achieve this: $root = new MenuComposite(); while ($row = mysql_fetch_array($result, MYSQL_ASSOC)) { $mc = new MenuLeaf($row); $root->addItem($mc); } print $root->render(); abstract class MenuComponent { private $_data; public function __construct(array $data) { $this->_data = new ArrayObject($data, ArrayObject::ARRAY_AS_PROPS); } public function getData() { return $this->_data; } public function getId() { return $this->getData()->id; } public function getParentId() { return $this->getData()->parent_id; } public function addItem(MenuComponent $mc) {} public function render() { return ''; } } class MenuComposite extends MenuComponent { private $_items; public function getItems() { if (null === $this->_items) { $this->_items = new ArrayObject(); } return $this->_items; } public function addItem(MenuComponent $mc) { if (0 !== $mc->getParentId()) { // composite $this->getItems()->offsetSet($mc->getId(), $mc); } else if ($this->getItems()->offsetExists($mc->getParentId())) { // leaf $p = $this->getItems()->offsetGet($mc->getParentId()); if ($p instanceof MenuComposite) { $p->addItem($mc); } else { // convert MenuLeaf to MenuComposite $p = new MenuComposite($p->getData()); $p->addItem($mc); $this->getItems()->offsetSet($mc->getParentId(), $p); } } else { throw new Exception('Parent item with id ' . $mc->getParentId() . ' does not exist.'); } } public function render() { $list = '<ul>'; foreach ($this->_items as $id => $mc) { $list .= '<li>' . $mc->render() . '</li>'; } $list .= '<ul>'; return $list; } } class MenuLeaf extends MenuComponent { public function render() { return '<a href="' . $this->getData()->href . '">' . $this->getData()->label . '</a>'; } } Link to comment https://forums.phpfreaks.com/topic/188801-organising-hierarchical-data-in-an-array-using-foreach/#findComment-996798 Share on other sites More sharing options...
ignace Posted January 17, 2010 Share Posted January 17, 2010 Here's an improved version: $rows = array(); while ($row = mysql_fetch_array($result, MYSQL_ASSOC)) { $pid = intval($row['parent_id']); $rows[$pid][] = $row; } $root = new Menu(); foreach ($rows as $pid => $array) { foreach ($array as $row) { $id = intval($row['id']); if (!isset($rows[$id])) { $root->add(new MenuLeaf($row)); } else { $root->add(new MenuComposite($row)); } } } print $root->render(); abstract class MenuComponent { private $data = array(); public function __construct($data = array()) { $this->data = $data; } abstract public function render(); } class MenuComposite extends MenuComponent { private $components = array(); public function add($key, MenuComponent $item) { $this->components[$key] = $item; } public function render() { if (!sizeof($this->components)) return ''; $html = '<a href="#">' . $this->data['label'] . '</a><ul>'; foreach ($this->components as $component) { $html .= '<li>' . $component->render() . '</li>'; } return $html . '</ul></a>'; } } class Menu extends MenuComposite { public function render() { if (!sizeof($this->components)) return ''; $html = '<ul>'; foreach ($this->components as $component) { $html .= '<li>' . $component->render() . '</li>'; } return $html . '</ul>'; } } class MenuLeaf extends MenuComponent { public function render() { $data = $this->getData(); return '<a href="#">' . $data['label'] . '</a>'; } } Link to comment https://forums.phpfreaks.com/topic/188801-organising-hierarchical-data-in-an-array-using-foreach/#findComment-996805 Share on other sites More sharing options...
rpmorrow Posted January 17, 2010 Author Share Posted January 17, 2010 Thanks! I'm pretty new to the OO stuff, but that looks good. Unfortunatley I'm getting a parse error.... Parse error: syntax error, unexpected T_CLASS ... refering to the line starting with abstract class MenuComponent { I can't see any missing parentheses or semicolons. Any ideas why I'd get the error? EDIT: In fact, if I delete all code before that point, I still get the error. Link to comment https://forums.phpfreaks.com/topic/188801-organising-hierarchical-data-in-an-array-using-foreach/#findComment-996812 Share on other sites More sharing options...
ignace Posted January 17, 2010 Share Posted January 17, 2010 Well these only serve the purpose of an example and I am not going to correct any error because you shouldn't be using them in production environments they are not meant to. An alternate solution production ready may be Zend_Navigation. Easy to use http://framework.zend.com/manual/en/zend.navigation.html Link to comment https://forums.phpfreaks.com/topic/188801-organising-hierarchical-data-in-an-array-using-foreach/#findComment-996815 Share on other sites More sharing options...
rpmorrow Posted January 17, 2010 Author Share Posted January 17, 2010 erm... If It shouldn't be used, and the code does not work anyway, then it only serves an an example of how NOT to do it. Thanks anyway Link to comment https://forums.phpfreaks.com/topic/188801-organising-hierarchical-data-in-an-array-using-foreach/#findComment-996817 Share on other sites More sharing options...
ignace Posted January 17, 2010 Share Posted January 17, 2010 Written code only serves as an example and may not fit your current project requirements. The example just gives you a basic idea of what may accomplish your goal. My code has a lot missing and it's up to you to fill in the blanks and properly test it before using it in a production environment. Link to comment https://forums.phpfreaks.com/topic/188801-organising-hierarchical-data-in-an-array-using-foreach/#findComment-996844 Share on other sites More sharing options...
Recommended Posts
Archived
This topic is now archived and is closed to further replies.