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? Quote 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. Quote 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 Quote 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>'; } } Quote 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>'; } } Quote 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. Quote 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 Quote 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 Quote 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. Quote 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
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.