Login | Register
My pages Projects Community openCollabNet

Discussions > dev > Re: [propel-dev] Re: News about NestedSet support in Propel ?

propel
Discussion topic

Back to topic list

Re: [propel-dev] Re: News about NestedSet support in Propel ?

Reply

Author Thomas Rabaix <thomas at rabaix dot net>
Full name Thomas Rabaix <thomas at rabaix dot net>
Date 2006-12-28 07:31:08 PST
Message I will try to explain how work the caching system in my application. I have this table : tree_line_id, parent_id, tree_id, other fields ... - each line of a same tree share the same tree_id - I load the tree data with 1 query SELECT * FROM table where tree_id = 1 - I have added to my propel object TreeLine::addChild, TreeLine::setParent and TreeLine::removeChild methods - I have added to my propel peer object TreeLinePeer::_loadTree, TreeLinePeer::loadTree, TreeLinePeer::saveTree, TreeLinePeer::addChild, TreeLinePeer::deleteChild - In the loop to assign child and parent, I also create an hash array with reference to my propel object, so I can get a node with $array[$id] - This code is used with propel 1.2 For the following code I have this relation : Estimate > EstimateLine (nested set). The root node id is always -1 The load function look like this, the nested set is on the EstimateLine object: private static function &_loadTree(Estimate $estimate) { $c = new Criteria; $c->add(EstimateLinePeer::ESTIMATE_ID, $estimate->getEstimateId(), Criteria::EQUAL); $lines = EstimateLinePeer::doSelect($c); $aLines = array(); foreach($lines as &$line) { $pId = $line->getParentId(); $id = $line->getEstimateLineId(); if(!$aLines[$pId]) { $aLines[$pId] = new EstimateLine; $aLines[$pId]->setEstimateId($estimate->getEstimateId()); $aLines[$pId]->setEstimateLineId($pId); $aLines[$pId]->setNew(false); } if(!($aLines[$id] instanceof EstimateLine)) { $aLines[$id] =& $line; } else { $line->copyInto($aLines[$id]); $aLines[$id]->setNew(false); $aLines[$id]->setEstimateLineId($id); } $aLines[$pId]->addChild($aLines[$id]); $aLines[$id]->setParent($aLines[$pId]); } if(count($aLines) == 0) { // create the default one $aLines[-1] = new EstimateLine; $aLines[-1]->setEstimateId($estimate->getEstimateId()); $aLines[-1]->setEstimateLineId(-1); } if(!($aLines[-1] instanceof EstimateLine)) { throw new OreoException('Consistancy error, no root node for thre current estimate (id='.$estimate->getEstimateId().')'); } $aLines[-1]->setDescription(__('Estimate').' '.$estimate- >getReference()); return $aLines; } The tree is stored in a static variable in the Peer class. In order to get the nodes you just provide the tree_id the method loadTree check if a cache version exist or not and return the reference to the array public static function &loadTree(Estimate $estimate) { @mkdir(MORO_DATA_MODULES_PATH.'/estimates/cache/', 0777, true); $file_name = MORO_DATA_MODULES_PATH.'/estimates/cache/'.$estimate- >getEstimateId().'_estimate_lines.cache'; if(self::$tree[$estimate->getEstimateId()]) { return self::$tree[$estimate->getEstimateId()]; } else if(is_file($file_name)) { Syslog::debug('Reload from serialization, estimate_id='.$estimate- >getEstimateId()); self::$tree[$estimate->getEstimateId()] = unserialize (file_get_contents($file_name)); } else { Syslog::debug('Serialize + cache, estimate_id='.$estimate- >getEstimateId()); self::$tree[$estimate->getEstimateId()] =& EstimatePeer::_loadTree ($estimate); self::saveTree($estimate); } return self::$tree[$estimate->getEstimateId()]; } When you make any change to one object you have to save the tree public function saveTree(Estimate &$estimate) { @mkdir(MORO_DATA_MODULES_PATH.'/estimates/cache/', 0777, true); $file_name = MORO_DATA_MODULES_PATH.'/estimates/cache/'.$estimate- >getEstimateId().'_estimate_lines.cache'; Syslog::debug('Saving Cache, estimate_id='.$estimate->getEstimateId ()); file_put_contents($file_name,serialize(self::$tree[$estimate- >getEstimateId()])); } When you delete an object or add a child you have to update the database and the cache public function addChild($estimate, &$child) { if($estimate instanceof Estimate) { $id = $estimate->getEstimateId(); } else { $id = $estimate; } self::$tree[$id][$child->getEstimateLineId()] =& $child; } public function deleteChild($estimateLine) { $parent =& $estimateLine->getParent(); $idx = array_merge($estimateLine->getIdxChild(), array ($estimateLine->getEstimateLineId())); $estimate = EstimatePeer::retrieveByPK($estimateLine->getEstimateId ()); if(!($estimate instanceof Estimate)) { throw new OreoException('Unable get the estimate', OREO_ERROR_CHECK); } $c = new Criteria; $c->add(EstimateLinePeer::ESTIMATE_LINE_ID, $idx, Criteria::IN); EstimateLinePeer::doDelete($c); // Update the cache tree foreach($idx as $idChild) { syslog::debug('Delete node from cache tree : estimate_id='. $estimate->getEstimateId().' , estimate_line_id='.$idChild); // remove parent reference $parent = self::$tree[$estimate->getEstimateId()][$idChild]- >getParent(); if($parent instanceof EstimateLine) { $parent->removeChild(self::$tree[$estimate->getEstimateId()] [$idChild]); } unset(self::$tree[$estimate->getEstimateId()][$idChild]); } EstimatePeer::saveTree($estimate); } you can reimplement the retrievebypk method : public static function &retrieveByPk($pk) { $line = parent::retrieveByPk($pk); $estimate = EstimatePeer::retrieveByPk($line->getEstimateId()); $lines =& EstimatePeer::loadTree($estimate); return $lines[$pk]; } Of course you have to implement save and delete method in your object. So when you use this cache system it is transparency in your action : $estimate = new Estimate; $estimate->save(); $estimate2 = new Estimate; $estimate2->save(); $estimate->addChild($estimate2); $estimate->save(); $estimate2->delete(); Other important points : - this optimization improves processing speed if you have to load 1000 objects. Up to 10x faster and it is very easy to access to any point of the nested set. However it is very easy to get lost with references. And you have to make sure you always use the reference object and not a copy. - If you have a complex nested set relation, ie : margin calculation over nested set with up and down propagation. I suppose that your database contains always correct values, the propagation/ cascade update is not required when loading from database. You may find usefull in the loading method to set a state variable to not cascade information over child or/and parent. function setMargin($val) { parent::setMargin($val); if(self::$propagation) { $this->getParent()->updateMargin(); } } - the caching solution rely on the filesystem as the serialization is store in a file. Depends on the load and disk access this method can be worth that reloading from database. If you have APC installed on your server you can also use the share memory to store the cache array. I hope these few lines can help you to create a caching solution for your nested set. Thomas. On 27 déc. 06, at 23:46, Eric Fredj wrote: > Thomas, > > Have you some hints to share with us to implement some caching > system for Nested Set ? > I am interested in implement a common caching system for trees > implementations (Nested Set or Materialized Path). > > ErIC >

« Previous message in topic | 20 of 20 | Next message in topic »

Messages

Show all messages in topic

News about NestedSet support in Propel ? Eric Fredj <eofredj at gmail dot com> Eric Fredj <eofredj at gmail dot com> 2006-12-17 04:35:07 PST
     Re: News about NestedSet support in Propel ? Eric Fredj <eofredj at gmail dot com> Eric Fredj <eofredj at gmail dot com> 2006-12-18 04:39:14 PST
         Re: [propel-dev] Re: News about NestedSet support in Propel ? hlellelid Hans Lellelid 2006-12-18 06:20:10 PST
             Re: [propel-dev] Re: News about NestedSet support in Propel ? hlellelid Hans Lellelid 2006-12-18 06:23:03 PST
                 RE: [propel-dev] Re: News about NestedSet support in Propel ? Soenke Ruempler - NorthClick <soenke dot ruempler at northclick dot de> Soenke Ruempler - NorthClick <soenke dot ruempler at northclick dot de> 2006-12-18 06:29:39 PST
                     Re: [propel-dev] trac/mod_python memory (was Re: News about NestedSet support in Propel ?) hlellelid Hans Lellelid 2006-12-18 06:29:49 PST
                         Re: [propel-dev] trac/mod_python memory (was Re: News about NestedSet support in Propel ?) Alan Pinstein <apinstein at mac dot com> Alan Pinstein <apinstein at mac dot com> 2006-12-18 07:45:57 PST
             Re: [propel-dev] Re: News about NestedSet support in Propel ? Eric Fredj <eofredj at gmail dot com> Eric Fredj <eofredj at gmail dot com> 2006-12-18 12:09:53 PST
                 Re: [propel-dev] Re: News about NestedSet support in Propel ? Eric Fredj <eofredj at gmail dot com> Eric Fredj <eofredj at gmail dot com> 2006-12-18 12:10:50 PST
                     Re: [propel-dev] Re: News about NestedSet support in Propel ? hlellelid Hans Lellelid 2006-12-18 12:11:32 PST
                         Re: [propel-dev] Re: News about NestedSet support in Propel ? Eric Fredj <eofredj at gmail dot com> Eric Fredj <eofredj at gmail dot com> 2006-12-18 12:26:43 PST
                             Re: [propel-dev] Re: News about NestedSet support in Propel ? Eric Fredj <eofredj at gmail dot com> Eric Fredj <eofredj at gmail dot com> 2006-12-24 02:52:40 PST
                                 Re: [propel-dev] Re: News about NestedSet support in Propel ? Eric Fredj <eofredj at gmail dot com> Eric Fredj <eofredj at gmail dot com> 2006-12-24 03:34:48 PST
                                     Re: [propel-dev] Re: News about NestedSet support in Propel ? hlellelid Hans Lellelid 2006-12-24 05:37:01 PST
                                         Re: [propel-dev] Re: News about NestedSet support in Propel ? hlellelid Hans Lellelid 2006-12-24 09:30:04 PST
                                             Re: [propel-dev] Re: News about NestedSet support in Propel ? Eric Fredj <eofredj at gmail dot com> Eric Fredj <eofredj at gmail dot com> 2006-12-25 03:40:17 PST
                                                 Re: [propel-dev] Re: News about NestedSet support in Propel ? hlellelid Hans Lellelid 2006-12-25 04:57:26 PST
                                 Re: [propel-dev] Re: News about NestedSet support in Propel ? Thomas Rabaix <thomas at rabaix dot net> Thomas Rabaix <thomas at rabaix dot net> 2006-12-24 06:17:51 PST
                                     Re: [propel-dev] Re: News about NestedSet support in Propel ? Eric Fredj <eofredj at gmail dot com> Eric Fredj <eofredj at gmail dot com> 2006-12-27 14:46:50 PST
                                         Re: [propel-dev] Re: News about NestedSet support in Propel ? Thomas Rabaix <thomas at rabaix dot net> Thomas Rabaix <thomas at rabaix dot net> 2006-12-28 07:31:08 PST
Messages per page: