[Beeframework-svn] SF.net SVN: beeframework:[42] trunk
Brought to you by:
b_hartmann,
m_plomer
|
From: <m_p...@us...> - 2013-06-28 14:49:47
|
Revision: 42
http://sourceforge.net/p/beeframework/code/42
Author: m_plomer
Date: 2013-06-28 14:49:43 +0000 (Fri, 28 Jun 2013)
Log Message:
-----------
- Tree-based API of nested set behavior completed
Modified Paths:
--------------
trunk/examples/classes/Treetest/Node.php
trunk/examples/classes/Treetest/TreeDao.php
trunk/examples/index2.php
trunk/framework/Bee/Persistence/Behaviors/NestedSet/IDelegate.php
trunk/framework/Bee/Persistence/Behaviors/NestedSet/ITreeNode.php
trunk/framework/Bee/Persistence/Behaviors/NestedSet/NodeInfo.php
trunk/framework/Bee/Persistence/Behaviors/NestedSet/Strategy.php
trunk/framework/Bee/Persistence/Behaviors/NestedSet/TreeStrategy.php
trunk/framework/Bee/Persistence/Doctrine2/Behaviors/DelegateBase.php
trunk/framework/Bee/Persistence/Doctrine2/Behaviors/GenericNestedSetDelegate.php
trunk/framework/Bee/Persistence/Doctrine2/Log4PHPLogger.php
trunk/framework/Bee/Persistence/Pdo/Behaviors/DelegateBase.php
trunk/framework/Bee/Persistence/Pdo/Behaviors/GenericNestedSetDelegate.php
trunk/tests/Bee/Persistence/Behaviors/NestedSet/DelegateMock.php
trunk/tests/Bee/Persistence/Behaviors/NestedSet/TestTreeNode.php
Modified: trunk/examples/classes/Treetest/Node.php
===================================================================
--- trunk/examples/classes/Treetest/Node.php 2013-06-27 03:18:25 UTC (rev 41)
+++ trunk/examples/classes/Treetest/Node.php 2013-06-28 14:49:43 UTC (rev 42)
@@ -25,11 +25,7 @@
*
* @Entity
* @Table(
- * name="tree_test",
- * uniqueConstraints={
- * @UniqueConstraint(name="grp_lft", columns={"root_id", "lft"}),
- * @UniqueConstraint(name="grp_rgt", columns={"root_id", "rgt"})
- * }
+ * name="tree_test"
* )
*/
class Node implements ITreeNode {
@@ -50,7 +46,7 @@
/**
* @var int
- * @Column(name="root_id", type="integer", nullable=false)
+ * @Column(name="root_id", type="integer", nullable=true)
*/
private $rootId;
@@ -84,9 +80,11 @@
/**
* @param $name string
+ * @param null $rootId
*/
- public function __construct($name) {
+ public function __construct($name, $rootId = null) {
$this->name = $name;
+ $this->rootId = $rootId;
}
/**
@@ -166,18 +164,18 @@
return $this->rootId;
}
-
/**
- * @return ITreeNode
+ * @return ITreeNode[]
*/
- public function getParent() {
- return $this->parent;
+ public function getChildren() {
+ return $this->children;
}
/**
- * @return ITreeNode[]
+ * @param ITreeNode $child
+ * @return void
*/
- public function &getChildren() {
- return $this->children;
+ public function appendChild(ITreeNode $child) {
+ array_push($this->children, $child);
}
}
Modified: trunk/examples/classes/Treetest/TreeDao.php
===================================================================
--- trunk/examples/classes/Treetest/TreeDao.php 2013-06-27 03:18:25 UTC (rev 41)
+++ trunk/examples/classes/Treetest/TreeDao.php 2013-06-28 14:49:43 UTC (rev 42)
@@ -28,15 +28,22 @@
class TreeDao extends DaoBase {
+ const ENTITY_CLASS_NAME = 'Treetest\Node';
+
/**
* @var NestedSetStrategy
*/
private $nestedSetStrategy;
+ /**
+ * @var GenericNestedSetDelegate
+ */
+ private $nestedSetDelegate;
+
public function __construct(EntityManager $entityManager) {
- $delagate = new GenericNestedSetDelegate($entityManager, 'Treetest\Node');
-// $delagate->setGroupFieldName('root_id');
- $this->nestedSetStrategy = new NestedSetStrategy($delagate);
+ $this->setEntityManager($entityManager);
+ $this->nestedSetDelegate = new GenericNestedSetDelegate($entityManager, self::ENTITY_CLASS_NAME);
+ $this->nestedSetStrategy = new NestedSetStrategy($this->nestedSetDelegate);
}
/**
@@ -45,4 +52,22 @@
public function getNestedSetStrategy() {
return $this->nestedSetStrategy;
}
+
+ public function loadTree($rootNodeIdOrEntity) {
+ if(!$rootNodeIdOrEntity instanceof Node) {
+ $rootNodeIdOrEntity = $this->getEntityManager()->find(self::ENTITY_CLASS_NAME, $rootNodeIdOrEntity);
+ }
+
+ // obtain NodeInfo (left / right boundaries + group info) for the tree part rooted at given node
+ $rootNodeInfo = $this->nestedSetDelegate->getNodeInfo($rootNodeIdOrEntity);
+
+ // construct our base query
+ $qb = $this->getEntityManager()->createQueryBuilder()->select('e')->from(self::ENTITY_CLASS_NAME, 'e');
+
+ // augment query with subtree limits
+ $this->nestedSetDelegate->augmentQueryWithSubtreeLimits($qb, $rootNodeInfo);
+
+ // execute query and create tree structure from result
+ return $this->nestedSetStrategy->buildTreeStructure($qb->getQuery()->execute());
+ }
}
Modified: trunk/examples/index2.php
===================================================================
--- trunk/examples/index2.php 2013-06-27 03:18:25 UTC (rev 41)
+++ trunk/examples/index2.php 2013-06-28 14:49:43 UTC (rev 42)
@@ -22,54 +22,62 @@
*/
use Treetest\Node;
+use Bee\Persistence\Behaviors\NestedSet\ITreeNode;
require_once('bootstrap.php');
-function addChild(&$children, Node $node) {
+function addChild(ITreeNode $parent, Node $node) {
global $entityManager;
$entityManager->persist($node);
- array_push($children, $node);
+ $parent->appendChild($node);
}
-$root = new Node('Root Node');
+$treeDao = $ctx->getBean('treeDao', 'Treetest\TreeDao');
+
+$root = new Node('Root Node', 15);
$entityManager->persist($root);
-addChild($root->getChildren(), new Node('Child 1-1'));
-addChild($root->getChildren(), new Node('Child 1-2'));
+addChild($root, new Node('Child 1-1'));
+addChild($root, new Node('Child 1-2'));
$child13 = new Node('Child 1-3');
-addChild($root->getChildren(), $child13);
+addChild($root, $child13);
-addChild($child13->getChildren(), new Node('Child 1-3-1'));
-addChild($child13->getChildren(), new Node('Child 1-3-2'));
+addChild($child13, new Node('Child 1-3-1'));
+addChild($child13, new Node('Child 1-3-2'));
-$treeDao = $ctx->getBean('treeDao', 'Treetest\TreeDao');
-
$treeDao->getNestedSetStrategy()->saveStructure($root);
$entityManager->flush();
$entityManager->close();
+//exit();
+
+
// new EM instance
$entityManager = $ctx->getBean('entityManager');
$c12 = $entityManager->getRepository('Treetest\Node')->findOneBy(array('name' => 'Child 1-2'));
-addChild($c12->getChildren(), new Node('Child 1-2-1'));
-addChild($c12->getChildren(), new Node('Child 1-2-2'));
+addChild($c12, new Node('Child 1-2-1'));
+addChild($c12, new Node('Child 1-2-2'));
$treeDao->getNestedSetStrategy()->saveStructure($c12);
$entityManager->flush();
$entityManager->close();
+//exit();
+
// new EM instance
$entityManager = $ctx->getBean('entityManager');
+//$entityManager = new \Doctrine\ORM\EntityManager();
+
$c12 = $entityManager->getRepository('Treetest\Node')->findOneBy(array('name' => 'Child 1-2'));
-//array_pop($c12->getChildren());
+$treeDao->getNestedSetStrategy()->saveStructure($c12);
-$treeDao->getNestedSetStrategy()->saveStructure($c12);
$entityManager->flush();
$entityManager->close();
+var_dump($treeDao->loadTree($root));
Modified: trunk/framework/Bee/Persistence/Behaviors/NestedSet/IDelegate.php
===================================================================
--- trunk/framework/Bee/Persistence/Behaviors/NestedSet/IDelegate.php 2013-06-27 03:18:25 UTC (rev 41)
+++ trunk/framework/Bee/Persistence/Behaviors/NestedSet/IDelegate.php 2013-06-28 14:49:43 UTC (rev 42)
@@ -44,17 +44,23 @@
* @param NodeInfo $nodeInfo
* @param bool|int $newLft
* @param bool|int $newLvl
- * @param mixed $restriction
- * @return
+ * @return void
*/
- public function setPosition($nestedSetEntity, NodeInfo $nodeInfo, $newLft = false, $newLvl = false, $restriction = false);
+ public function setPosition($nestedSetEntity, NodeInfo $nodeInfo, $newLft = false, $newLvl = false);
/**
+ * @param NodeInfo $parentNodeInfo
+ * @return void
+ */
+ public function unsetChildGroupKeys(NodeInfo $parentNodeInfo);
+
+ /**
* @param mixed $nestedSetEntity
* @param int $delta
* @param int $lowerBoundIncl
* @param int $upperBoundExcl
- * @param mixed $restriction
+ * @param array $groupKey
+ * @return void
*/
- public function shift($nestedSetEntity, $delta, $lowerBoundIncl, $upperBoundExcl, $restriction = false);
+ public function shift($nestedSetEntity, $delta, $lowerBoundIncl, $upperBoundExcl, array $groupKey);
}
Modified: trunk/framework/Bee/Persistence/Behaviors/NestedSet/ITreeNode.php
===================================================================
--- trunk/framework/Bee/Persistence/Behaviors/NestedSet/ITreeNode.php 2013-06-27 03:18:25 UTC (rev 41)
+++ trunk/framework/Bee/Persistence/Behaviors/NestedSet/ITreeNode.php 2013-06-28 14:49:43 UTC (rev 42)
@@ -25,12 +25,13 @@
interface ITreeNode {
/**
- * @return ITreeNode
+ * @return ITreeNode[]
*/
- public function getParent();
+ public function getChildren();
/**
- * @return ITreeNode[]
+ * @param ITreeNode $child
+ * @return void
*/
- public function getChildren();
+ public function appendChild(ITreeNode $child);
}
Modified: trunk/framework/Bee/Persistence/Behaviors/NestedSet/NodeInfo.php
===================================================================
--- trunk/framework/Bee/Persistence/Behaviors/NestedSet/NodeInfo.php 2013-06-27 03:18:25 UTC (rev 41)
+++ trunk/framework/Bee/Persistence/Behaviors/NestedSet/NodeInfo.php 2013-06-28 14:49:43 UTC (rev 42)
@@ -21,7 +21,6 @@
* Date: 07.05.13
* Time: 17:43
*/
-
class NodeInfo {
const LEFT_KEY = 'lft';
@@ -43,6 +42,11 @@
*/
public $lvl;
+ /**
+ * @var array
+ */
+ public $groupKey;
+
public function __construct(array $tuple = null) {
if(!is_null($tuple)) {
$this->lft = is_numeric($tuple[self::LEFT_KEY]) ? $tuple[self::LEFT_KEY] : false;
@@ -97,9 +101,21 @@
return $this->rgt > 0 && $this->lft > 0;
}
- function __toString() {
- return "NodeInfo(lft:{$this->lft}|rgt:{$this->rgt}|lvl:{$this->lvl})";
+ /**
+ * @return array
+ */
+ public function getGroupKey() {
+ return $this->groupKey;
}
+ /**
+ * @param array $groupKey
+ */
+ public function setGroupKey($groupKey) {
+ $this->groupKey = $groupKey;
+ }
+ function __toString() {
+ return "NodeInfo(lft:{$this->lft}|rgt:{$this->rgt}|lvl:{$this->lvl}|group:[".implode(',', $this->groupKey)."])";
+ }
}
Modified: trunk/framework/Bee/Persistence/Behaviors/NestedSet/Strategy.php
===================================================================
--- trunk/framework/Bee/Persistence/Behaviors/NestedSet/Strategy.php 2013-06-27 03:18:25 UTC (rev 41)
+++ trunk/framework/Bee/Persistence/Behaviors/NestedSet/Strategy.php 2013-06-28 14:49:43 UTC (rev 42)
@@ -178,7 +178,7 @@
if ($subjectInfo->isInTree()) {
// ... temporarily move it to a neutral position, so as to avoid any conflicts (e.g. SQL constraints)
// (keep its original level for now)
- $this->delegate->setPosition($subject, $subjectInfo, -$subjectInfo->getSpan(), $subjectInfo->lvl, $groupRestriction);
+ $this->delegate->setPosition($subject, $subjectInfo, -$subjectInfo->getSpan(), $subjectInfo->lvl);
$subjectInfo->update(-$subjectInfo->getSpan(), $subjectInfo->lvl);
}
@@ -189,7 +189,7 @@
self::getLog()->debug("setting final position of subject to lft = $newLeft, lvl = $level");
// move subject to final position
- $this->delegate->setPosition($subject, $subjectInfo, $newLeft, $level, $groupRestriction);
+ $this->delegate->setPosition($subject, $subjectInfo, $newLeft, $level);
$subjectInfo->update($newLeft, $level);
}
@@ -210,10 +210,10 @@
}
// store the subtree in the negative area (in case we do not want to delete it, but rather move it to a different tree)
- $this->delegate->setPosition($subject, $subjectInfo, -$subjectInfo->getSpan(), 0, $groupRestriction);
+ $this->delegate->setPosition($subject, $subjectInfo, -$subjectInfo->getSpan(), 0);
// restore numbering consistency
- $this->delegate->shift($subject, -$subjectInfo->getSpan(), $subjectInfo->rgt + 1, false, $groupRestriction);
+ $this->delegate->shift($subject, -$subjectInfo->getSpan(), $subjectInfo->rgt + 1, false, $subjectInfo->getGroupKey());
}
/**
Modified: trunk/framework/Bee/Persistence/Behaviors/NestedSet/TreeStrategy.php
===================================================================
--- trunk/framework/Bee/Persistence/Behaviors/NestedSet/TreeStrategy.php 2013-06-27 03:18:25 UTC (rev 41)
+++ trunk/framework/Bee/Persistence/Behaviors/NestedSet/TreeStrategy.php 2013-06-28 14:49:43 UTC (rev 42)
@@ -44,12 +44,13 @@
public function saveStructure(ITreeNode $structureRoot) {
$rootNodeInfo = $this->nodeInfoCache->contains($structureRoot) ? $this->nodeInfoCache->offsetGet($structureRoot) : $this->delegate->getNodeInfo($structureRoot);
+ $this->delegate->unsetChildGroupKeys($rootNodeInfo);
$oldNext = $rootNodeInfo->rgt + 1;
- $next = $this->calculateNodeInfo($structureRoot, $rootNodeInfo->lft, $rootNodeInfo->lvl);
+ $next = $this->calculateNodeInfo($structureRoot, $rootNodeInfo->lft, $rootNodeInfo->lvl, $rootNodeInfo->getGroupKey());
$delta = $next - $oldNext;
- $this->delegate->shift($structureRoot, $delta, $oldNext, false);
+ $this->delegate->shift($structureRoot, $delta, $oldNext, false, $rootNodeInfo->getGroupKey());
$myDelegate = $this->delegate;
$this->walkTree($structureRoot, function(ITreeNode $currentNode, NodeInfo $nodeInfo) use ($myDelegate) {
@@ -57,6 +58,11 @@
});
}
+ /**
+ * Walk the tree under $structureRoot iteratively in preorder and apply the given lambda $func to each node.
+ * @param ITreeNode $structureRoot
+ * @param $func
+ */
protected function walkTree(ITreeNode $structureRoot, $func) {
$stack = array($structureRoot);
while(count($stack) > 0) {
@@ -72,9 +78,10 @@
* @param ITreeNode $currentNode
* @param $lft
* @param $lvl
+ * @param array $groupKey
* @return mixed
*/
- protected function calculateNodeInfo(ITreeNode $currentNode, $lft, $lvl) {
+ protected function calculateNodeInfo(ITreeNode $currentNode, $lft, $lvl, array $groupKey) {
$nodeInfo = new NodeInfo();
$this->nodeInfoCache->attach($currentNode, $nodeInfo);
@@ -82,9 +89,10 @@
$nodeInfo->lft = $lft;
$lft++;
foreach($currentNode->getChildren() as $child) {
- $lft = $this->calculateNodeInfo($child, $lft, $lvl + 1);
+ $lft = $this->calculateNodeInfo($child, $lft, $lvl + 1, $groupKey);
}
$nodeInfo->rgt = $lft;
+ $nodeInfo->setGroupKey($groupKey);
return $nodeInfo->rgt + 1;
}
@@ -95,4 +103,46 @@
protected function getNodeInfoCache() {
return $this->nodeInfoCache;
}
+
+ /**
+ * @param ITreeNode[] $nodesList
+ * @return ITreeNode
+ */
+ public function buildTreeStructure(array $nodesList) {
+ $nodeStack = new \SplStack();
+
+ $lastNode = null;
+ $lastLevel = false;
+
+ foreach ($nodesList as $node) {
+ $level = $this->delegate->getNodeInfo($node)->lvl;
+
+ if ($lastLevel !== false) {
+ if ($level > $lastLevel) {
+ // dive exactly one level
+ // must be exactly 1 larger than last level (otherwise intermediate nodes are probably missing)
+ \Bee_Utils_Assert::isTrue($level == $lastLevel + 1, sprintf('Malformed nodes list, missing intermediate levels between %d and %d', $lastLevel, $level));
+ // use last node as current parent
+ $nodeStack->push($lastNode);
+ } else {
+ // $lastLevel >= $level; emerge one or multiple levels
+ for ($i = $lastLevel; $i > $level; $i--) {
+ $nodeStack->pop();
+ }
+ }
+
+ // add to current parent (which must exist!!)
+ \Bee_Utils_Assert::isTrue(!$nodeStack->isEmpty(), sprintf('No current parent on level %d (if this happens on level 0, it usually means that your query returned multiple roots for this tree set)', $level));
+
+ $nodeStack->top()->appendChild($node);
+ }
+
+ $lastLevel = $level;
+ $lastNode = $node;
+ }
+
+ return $nodeStack->bottom();
+ }
+
+
}
Modified: trunk/framework/Bee/Persistence/Doctrine2/Behaviors/DelegateBase.php
===================================================================
--- trunk/framework/Bee/Persistence/Doctrine2/Behaviors/DelegateBase.php 2013-06-27 03:18:25 UTC (rev 41)
+++ trunk/framework/Bee/Persistence/Doctrine2/Behaviors/DelegateBase.php 2013-06-28 14:49:43 UTC (rev 42)
@@ -31,11 +31,18 @@
private $entityName;
/**
+ * @var array
+ */
+ private $groupKeyFields;
+
+ /**
* @param string $entityName
+ * @param array $groupKeyFields
*/
- public function __construct($entityName) {
+ public function __construct($entityName, array $groupKeyFields) {
\Bee_Utils_Assert::hasText($entityName, 'Entity name required, must not be empty');
$this->entityName = $entityName;
+ $this->groupKeyFields = $groupKeyFields;
}
/**
@@ -44,4 +51,11 @@
public function getEntityName() {
return $this->entityName;
}
+
+ /**
+ * @return array
+ */
+ public function getGroupKeyFields() {
+ return $this->groupKeyFields;
+ }
}
Modified: trunk/framework/Bee/Persistence/Doctrine2/Behaviors/GenericNestedSetDelegate.php
===================================================================
--- trunk/framework/Bee/Persistence/Doctrine2/Behaviors/GenericNestedSetDelegate.php 2013-06-27 03:18:25 UTC (rev 41)
+++ trunk/framework/Bee/Persistence/Doctrine2/Behaviors/GenericNestedSetDelegate.php 2013-06-28 14:49:43 UTC (rev 42)
@@ -16,6 +16,7 @@
* limitations under the License.
*/
use Bee\Persistence\Behaviors\NestedSet\IDelegate;
+use Bee\Persistence\Behaviors\NestedSet\ITreeNode;
use Bee\Persistence\Behaviors\NestedSet\NodeInfo;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\QueryBuilder;
@@ -25,7 +26,7 @@
* Date: 21.06.13
* Time: 16:01
*/
-
+
class GenericNestedSetDelegate extends DelegateBase implements IDelegate {
/**
@@ -46,13 +47,13 @@
/**
* @param EntityManager $entityManager
* @param string $entityName
+ * @param array $rootKeyFields
*/
- public function __construct(EntityManager $entityManager, $entityName) {
- parent::__construct($entityName);
+ public function __construct(EntityManager $entityManager, $entityName, array $rootKeyFields = array('rootId')) {
+ parent::__construct($entityName, $rootKeyFields);
$this->setEntityManager($entityManager);
}
-
/**
* @param string $leftFieldName
*/
@@ -85,14 +86,30 @@
$result->lft = $bw->getPropertyValue($this->leftFieldName);
$result->rgt = $bw->getPropertyValue($this->rightFieldName);
$result->lvl = $bw->getPropertyValue($this->levelFieldName);
- if(is_null($result->lft)) {
+ if (is_null($result->lft)) {
$result->lft = 1;
$result->lvl = 0;
}
+ $result->setGroupKey($this->extractGroupKey($bw));
return $result;
}
/**
+ * @param mixed|\Bee_Beans_BeanWrapper $nestedSetEntityOrBeanWrapper
+ * @return array
+ */
+ protected function extractGroupKey($nestedSetEntityOrBeanWrapper) {
+ if (!($nestedSetEntityOrBeanWrapper instanceof \Bee_Beans_BeanWrapper)) {
+ $nestedSetEntityOrBeanWrapper = new \Bee_Beans_BeanWrapper($nestedSetEntityOrBeanWrapper);
+ }
+ $groupKey = array();
+ foreach ($this->getGroupKeyFields() as $groupFieldName) {
+ $groupKey[$groupFieldName] = $nestedSetEntityOrBeanWrapper->getPropertyValue($groupFieldName);
+ }
+ return $groupKey;
+ }
+
+ /**
* @param mixed $nestedSetEntity
* @param mixed $restriction
* @return NodeInfo
@@ -106,41 +123,106 @@
* @param NodeInfo $nodeInfo
* @param bool|int $newLft
* @param bool|int $newLvl
- * @param mixed $restriction
*/
- public function setPosition($nestedSetEntity, NodeInfo $nodeInfo, $newLft = false, $newLvl = false, $restriction = false) {
+ public function setPosition($nestedSetEntity, NodeInfo $nodeInfo, $newLft = false, $newLvl = false) {
$bw = new \Bee_Beans_BeanWrapper($nestedSetEntity);
$bw->setPropertyValue($this->leftFieldName, $nodeInfo->lft);
$bw->setPropertyValue($this->rightFieldName, $nodeInfo->rgt);
$bw->setPropertyValue($this->levelFieldName, $nodeInfo->lvl);
+
+ $grpKey = $nodeInfo->getGroupKey();
+ foreach ($this->getGroupKeyFields() as $groupKeyField) {
+ $bw->setPropertyValue($groupKeyField, $grpKey[$groupKeyField]);
+ }
// todo: implement the other cases (i.e. for the non-tree strategy API)
}
/**
+ * @param NodeInfo $parentNodeInfo
+ * @return void
+ */
+ public function unsetChildGroupKeys(NodeInfo $parentNodeInfo) {
+ $qb = $this->createUpdateBaseQueryBuilder($parentNodeInfo->getGroupKey());
+
+ // set group key to null...
+ foreach ($this->getGroupKeyFields() as $groupKeyField) {
+ $qb->set("e.$groupKeyField", 'NULL');
+ }
+
+ // .. on all children of the parent node given by the NodeInfo
+ $qb->andWhere("e.{$this->leftFieldName} > :parentLft")
+ ->setParameter('parentLft', $parentNodeInfo->lft)
+ ->andWhere("e.{$this->rightFieldName} < :parentRgt")
+ ->setParameter('parentRgt', $parentNodeInfo->rgt);
+ $qb->getQuery()->execute();
+ }
+
+ /**
* @param mixed $nestedSetEntity
* @param int $delta
* @param int $lowerBoundIncl
* @param int $upperBoundExcl
- * @param mixed $restriction
+ * @param array $groupKey
*/
- public function shift($nestedSetEntity, $delta, $lowerBoundIncl, $upperBoundExcl, $restriction = false) {
- $this->buildShiftQuery($this->leftFieldName, $delta, $lowerBoundIncl, $upperBoundExcl, $restriction)->execute();
- $this->buildShiftQuery($this->rightFieldName, $delta, $lowerBoundIncl, $upperBoundExcl, $restriction)->execute();
+ public function shift($nestedSetEntity, $delta, $lowerBoundIncl, $upperBoundExcl, array $groupKey) {
+ $this->buildShiftQuery($this->leftFieldName, $delta, $lowerBoundIncl, $upperBoundExcl, $groupKey)->execute();
+ $this->buildShiftQuery($this->rightFieldName, $delta, $lowerBoundIncl, $upperBoundExcl, $groupKey)->execute();
// todo: implement the other cases (i.e. for the non-tree strategy API)
}
/**
+ * @param QueryBuilder $qb
+ * @param NodeInfo $rootNodeInfo
+ * @param string $rootEntityAlias
+ * @param bool $maxLvl
+ */
+ public function augmentQueryWithSubtreeLimits(QueryBuilder $qb, NodeInfo $rootNodeInfo, $rootEntityAlias = 'e', $maxLvl = false) {
+ if ($rootEntityAlias) {
+ $rootEntityAlias = $rootEntityAlias . '.';
+ }
+
+ // limit to subtree of this root node
+ $qb->andWhere("$rootEntityAlias{$this->leftFieldName} >= :limitLft")
+ ->setParameter('limitLft', $rootNodeInfo->lft)
+ ->andWhere("$rootEntityAlias{$this->rightFieldName} <= :limitRgt")
+ ->setParameter('limitRgt', $rootNodeInfo->rgt);
+
+ // make sure we get only results from current group
+ $this->augmentQueryWithGroupLimits($qb, $rootNodeInfo->getGroupKey());
+
+ // apply max level restriction if needed
+ if ($maxLvl) {
+ $qb->andWhere("$rootEntityAlias{$this->leftFieldName} <= :maxLvl")->setParameter('maxLvl', $maxLvl);
+ }
+
+ // proper ordering
+ $qb->orderBy("$rootEntityAlias{$this->leftFieldName}", 'ASC');
+ }
+
+ /**
* @param string $fieldName
* @param int $delta
* @param int $lowerBoundIncl
* @param int $upperBoundExcl
- * @param mixed $restriction
+ * @param array $groupKey
* @return \Doctrine\ORM\Query
*/
- protected function buildShiftQuery($fieldName, $delta, $lowerBoundIncl, $upperBoundExcl, $restriction = false) {
- return $this->getEntityManager()->createQueryBuilder()->update($this->getEntityName(), 'e')
- ->set('e.'.$fieldName, 'e.'.$fieldName .' + :delta')->setParameter('delta', $delta)
- ->where('e.'.$fieldName . ' >= :lbIncl')->setParameter('lbIncl', $lowerBoundIncl)->getQuery();
-// ->orderBy('e.'.$fieldName, $delta > 0 ? 'DESC' : 'ASC')->getQuery();
+ protected function buildShiftQuery($fieldName, $delta, $lowerBoundIncl, $upperBoundExcl, array $groupKey) {
+ $qb = $this->createUpdateBaseQueryBuilder($groupKey);
+ $qb->set("e.$fieldName", "e.$fieldName + :delta")->setParameter('delta', $delta)
+ ->andWhere("e.$fieldName >= :lbIncl")->setParameter('lbIncl', $lowerBoundIncl);
+ return $qb->getQuery();
}
+
+ protected function createUpdateBaseQueryBuilder(array $groupKey) {
+ $qb = $this->getEntityManager()->createQueryBuilder()->update($this->getEntityName(), 'e');
+ return $this->augmentQueryWithGroupLimits($qb, $groupKey);
+ }
+
+ protected function augmentQueryWithGroupLimits(QueryBuilder $qb, array $groupKey) {
+ foreach ($this->getGroupKeyFields() as $groupFieldName) {
+ $qb->andWhere("e.$groupFieldName = :$groupFieldName")->setParameter($groupFieldName, $groupKey[$groupFieldName]);
+ }
+ return $qb;
+ }
}
Modified: trunk/framework/Bee/Persistence/Doctrine2/Log4PHPLogger.php
===================================================================
--- trunk/framework/Bee/Persistence/Doctrine2/Log4PHPLogger.php 2013-06-27 03:18:25 UTC (rev 41)
+++ trunk/framework/Bee/Persistence/Doctrine2/Log4PHPLogger.php 2013-06-28 14:49:43 UTC (rev 42)
@@ -46,7 +46,7 @@
* @return void
*/
public function startQuery($sql, array $params = null, array $types = null) {
- self::getLog()->trace('SQL : [' . $sql . '] PARAMS : [' . serialize($params) . '] TYPES: ['. serialize($types) . ']');
+ self::getLog()->trace('SQL : [' . $sql . '] PARAMS : [' . implode(', ', $params) . '] TYPES: ['. implode(', ', $types) . ']');
$this->startTime = microtime(true);
}
Modified: trunk/framework/Bee/Persistence/Pdo/Behaviors/DelegateBase.php
===================================================================
--- trunk/framework/Bee/Persistence/Pdo/Behaviors/DelegateBase.php 2013-06-27 03:18:25 UTC (rev 41)
+++ trunk/framework/Bee/Persistence/Pdo/Behaviors/DelegateBase.php 2013-06-28 14:49:43 UTC (rev 42)
@@ -79,9 +79,10 @@
* @param bool $restriction
* @return string
*/
- protected function getDomainRestrictionString($entity, array &$params, $restriction = false) {
+ protected function getDomainRestrictionString($entity, array &$params, array $groupKey = array()) {
$result = '1=1';
if ($this->getGroupFieldName()) {
+ //todo: fix this!
if ($restriction === false) {
// determine group value
$restriction = $this->getGroup($entity);
Modified: trunk/framework/Bee/Persistence/Pdo/Behaviors/GenericNestedSetDelegate.php
===================================================================
--- trunk/framework/Bee/Persistence/Pdo/Behaviors/GenericNestedSetDelegate.php 2013-06-27 03:18:25 UTC (rev 41)
+++ trunk/framework/Bee/Persistence/Pdo/Behaviors/GenericNestedSetDelegate.php 2013-06-28 14:49:43 UTC (rev 42)
@@ -102,21 +102,20 @@
/**
* @param mixed $nestedSetEntity
* @param NodeInfo $nodeInfo
- * @param int $newLft
- * @param int $newLvl
- * @param mixed $restriction
+ * @param bool|int $newLft
+ * @param bool|int $newLvl
*/
- public function setPosition($nestedSetEntity, NodeInfo $nodeInfo, $newLft = false, $newLvl = false, $restriction = false) {
+ public function setPosition($nestedSetEntity, NodeInfo $nodeInfo, $newLft = false, $newLvl = false) {
if ($nodeInfo->hasStructure()) {
$params = array(':pos_delta' => $newLft - $nodeInfo->lft, ':lvl_delta' => $newLvl - $nodeInfo->lvl, ':lft' => $nodeInfo->lft, ':rgt' => $nodeInfo->rgt);
$qryString = sprintf(self::SET_POSITION_QUERY_TEMPLATE, $this->leftFieldName, $this->rightFieldName, $this->levelFieldName,
- $this->getQueryDomain(), $this->getDomainRestrictionString($nestedSetEntity, $params, $restriction));
+ $this->getQueryDomain(), $this->getDomainRestrictionString($nestedSetEntity, $params, $nodeInfo->getGroupKey()));
} else {
$params = array(':lft' => $newLft, ':rgt' => $newLft + $nodeInfo->getSpan() - 1, ':lvl' => $newLvl);
$qryString = sprintf(self::SET_POSITION_QUERY_BY_ID_TEMPLATE, $this->leftFieldName, $this->rightFieldName,
$this->levelFieldName, $this->getQueryDomain(),
$this->getIdentityRestrictionString($nestedSetEntity, $params),
- $this->getDomainRestrictionString($nestedSetEntity, $params, $restriction));
+ $this->getDomainRestrictionString($nestedSetEntity, $params, $nodeInfo->getGroupKey()));
}
$this->getPdo()->prepare($qryString)->execute($params);
}
@@ -126,9 +125,9 @@
* @param int $delta
* @param int $lowerBoundIncl
* @param int $upperBoundExcl
- * @param mixed $restriction
+ * @param array $groupKey
*/
- public function shift($nestedSetEntity, $delta, $lowerBoundIncl, $upperBoundExcl, $restriction = false) {
+ public function shift($nestedSetEntity, $delta, $lowerBoundIncl, $upperBoundExcl, array $groupKey) {
$params = array(':delta' => $delta, ':lower_bound' => $lowerBoundIncl);
if ($upperBoundExcl !== false) {
$params[':upper_bound'] = $upperBoundExcl;
@@ -136,7 +135,7 @@
$qryTempl = $upperBoundExcl !== false ? self::SHIFT_QUERY_TEMPLATE : self::SHIFT_QUERY_OPEN_TEMPLATE;
$qryDomain = $this->getQueryDomain();
- $domRes = $this->getDomainRestrictionString($nestedSetEntity, $params, $restriction);
+ $domRes = $this->getDomainRestrictionString($nestedSetEntity, $params, $groupKey);
// order updates only if supported by the driver and not operating on a joined relation
$orderUpdate = $this->pdoSupportsFeature(FeatureDetector::FEATURE_ORDERED_UPDATE) && stripos($qryDomain, ' JOIN ') === false;
Modified: trunk/tests/Bee/Persistence/Behaviors/NestedSet/DelegateMock.php
===================================================================
--- trunk/tests/Bee/Persistence/Behaviors/NestedSet/DelegateMock.php 2013-06-27 03:18:25 UTC (rev 41)
+++ trunk/tests/Bee/Persistence/Behaviors/NestedSet/DelegateMock.php 2013-06-28 14:49:43 UTC (rev 42)
@@ -58,10 +58,9 @@
* @param NodeInfo $nodeInfo
* @param bool|int $newLft
* @param bool|int $newLvl
- * @param mixed $restriction
*/
- public function setPosition($nestedSetEntity, NodeInfo $nodeInfo, $newLft = false, $newLvl = false, $restriction = false) {
- array_push($this->protocol, sprintf('id=%s; lft=%d; rgt=%d; lvl=%d;', $nestedSetEntity->getId(), $nodeInfo->lft, $nodeInfo->rgt, $nodeInfo->lvl));
+ public function setPosition($nestedSetEntity, NodeInfo $nodeInfo, $newLft = false, $newLvl = false) {
+ array_push($this->protocol, sprintf('id=%s; lft=%d; rgt=%d; lvl=%d; grp=[%s]', $nestedSetEntity->getId(), $nodeInfo->lft, $nodeInfo->rgt, $nodeInfo->lvl, implode(',', $nodeInfo->getGroupKey())));
}
/**
@@ -69,9 +68,17 @@
* @param int $delta
* @param int $lowerBoundIncl
* @param int $upperBoundExcl
- * @param mixed $restriction
+ * @param array $groupKey
*/
- public function shift($nestedSetEntity, $delta, $lowerBoundIncl, $upperBoundExcl, $restriction = false) {
- array_push($this->protocol, sprintf('delta=%d; %d<=lft/rgt%s;', $delta, $lowerBoundIncl, $upperBoundExcl !== false ? '<'.$upperBoundExcl : ''));
+ public function shift($nestedSetEntity, $delta, $lowerBoundIncl, $upperBoundExcl, array $groupKey) {
+ array_push($this->protocol, sprintf('delta=%d; %d<=lft/rgt%s; grp=[%s]', $delta, $lowerBoundIncl, $upperBoundExcl !== false ? '<'.$upperBoundExcl : '', implode(',', $groupKey)));
}
+
+ /**
+ * @param NodeInfo $parentNodeInfo
+ * @return void
+ */
+ public function unsetChildGroupKeys(NodeInfo $parentNodeInfo) {
+ // TODO: Implement unsetChildGroupKeys() method.
+ }
}
Modified: trunk/tests/Bee/Persistence/Behaviors/NestedSet/TestTreeNode.php
===================================================================
--- trunk/tests/Bee/Persistence/Behaviors/NestedSet/TestTreeNode.php 2013-06-27 03:18:25 UTC (rev 41)
+++ trunk/tests/Bee/Persistence/Behaviors/NestedSet/TestTreeNode.php 2013-06-28 14:49:43 UTC (rev 42)
@@ -40,33 +40,18 @@
private $children;
/**
+ * @param array $id
* @param TestTreeNode[] $children
* @param array $nodeInfo
+ * @return \Bee\Persistence\Behaviors\NestedSet\TestTreeNode
*/
public function __construct($id, $children, array $nodeInfo) {
parent::__construct($nodeInfo);
$this->id = $id;
$this->children = $children;
- foreach($this->children as $child) {
- $child->setParent($this);
- }
}
/**
- * @return ITreeNode
- */
- public function getParent() {
- return $this->parent;
- }
-
- /**
- * @param \Bee\Persistence\Behaviors\NestedSet\ITreeNode $parent
- */
- public function setParent($parent) {
- $this->parent = $parent;
- }
-
- /**
* @return ITreeNode[]
*/
public function getChildren() {
@@ -79,4 +64,12 @@
public function getId() {
return $this->id;
}
+
+ /**
+ * @param ITreeNode $child
+ * @return void
+ */
+ public function appendChild(ITreeNode $child) {
+ array_push($this->children, $child);
+ }
}
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|