Skip to content

Commit

Permalink
FullPath, SaveNodeAsRoot methods. Updated Folder class Doc
Browse files Browse the repository at this point in the history
  • Loading branch information
AidasK committed May 14, 2013
1 parent 505f076 commit 2149fae
Show file tree
Hide file tree
Showing 3 changed files with 126 additions and 5 deletions.
97 changes: 97 additions & 0 deletions ClosureTableBehavior.php
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,47 @@ public function path()
return $this->pathOf($owner->getPrimaryKey());
}

/**
* Named scope. Get path with its children.
* Warning: root node isn't returned.
*
* @return CActiveRecord the owner.
*/
public function fullPathOf($primaryKey)
{
/* @var $owner CActiveRecord */
$owner = $this->getOwner();
$db = $owner->getDbConnection();
$criteria = $owner->getDbCriteria();
$alias = $db->quoteColumnName($owner->getTableAlias());
$closureTable = $db->quoteTableName($this->closureTableName);
$parentAttribute = $db->quoteColumnName($this->parentAttribute);
$childAttribute = $db->quoteColumnName($this->childAttribute);
$primaryKeyName = $owner->tableSchema->primaryKey;
$criteria->mergeWith(array(
'join' => 'JOIN ' . $closureTable . ' ct1'
. ' JOIN ' . $closureTable . ' ct2'
. ' ON ct1.' . $parentAttribute . '=ct2.' . $parentAttribute
. ' AND ' . $alias . '.' . $primaryKeyName . '=ct2.' . $childAttribute
. ' AND ct2.' . $db->quoteColumnName($this->depthAttribute) . '=1',
'condition' => 'ct1.' . $childAttribute . '=' . $primaryKey
));
return $owner;
}

/**
* Named scope. Get path with its children.
* Warning: root node isn't returned.
*
* @return CActiveRecord the owner.
*/
public function fullPath()
{
/* @var $owner CActiveRecord */
$owner = $this->getOwner();
return $this->fullPathOf($owner->getPrimaryKey());
}

/**
* Named scope. Selects leaf column which indicates if record is a leaf
* @return CActiveRecord the owner.
Expand Down Expand Up @@ -210,6 +251,62 @@ public function isLeaf()
return (boolean)$this->getOwner()->{$this->isLeafParameter};
}

/**
* Save node and insert closure table records with transaction
* @param boolean $runValidation whether to perform validation before saving the record.
* If the validation fails, the record will not be saved to database.
* @param array $attributes list of attributes that need to be saved. Defaults to null,
* meaning all attributes that are loaded from DB will be saved.
* @throws CDbException|Exception
* @return boolean whether the saving succeeds
*/
public function saveNodeAsRoot($runValidation = true, $attributes = null)
{
/* @var $owner CActiveRecord */
$owner = $this->getOwner();
$db = $owner->getDbConnection();
if ($db->getCurrentTransaction() === null) {
$transaction = $db->beginTransaction();
}
try {
if (!$owner->save($runValidation, $attributes)) {
return false;
}
$this->markAsRoot($owner->primaryKey);
if (isset($transaction)) {
$transaction->commit();
}
} catch (CDbException $e) {
if (isset($transaction)) {
$transaction->rollback();
}
throw $e;
}
return true;
}

/**
* Insert closure table records
* @param $primaryKey
* @return int
*/
public function markAsRoot($primaryKey)
{
/* @var $owner CActiveRecord */
$owner = $this->getOwner();
$db = $owner->getDbConnection();
$childAttribute = $db->quoteColumnName($this->childAttribute);
$parentAttribute = $db->quoteColumnName($this->parentAttribute);
$depthAttribute = $db->quoteColumnName($this->depthAttribute);
$closureTable = $db->quoteTableName($this->closureTableName);
$cmd = $db->createCommand(
'INSERT INTO ' . $closureTable
. '(' . $parentAttribute . ',' . $childAttribute . ',' . $depthAttribute . ') '
. 'VALUES (:nodeId,:nodeId,\'0\')'
);
return $cmd->execute(array(':nodeId'=>$primaryKey));
}

/**
* Appends node to target as child (Only for new records).
* @param CActiveRecord|int $target where to append
Expand Down
16 changes: 11 additions & 5 deletions tests/models/Folder.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<?php
/**
* Class Folder
* ClosureTableBehavior scopes
* @method Folder descendantsOf($primaryKey, $depth = null) Named scope. Finds descendants
* @method Folder descendants($depth=null) Named scope. Finds descendants
* @method Folder childrenOf($primaryKey) Named scope. Finds children
Expand All @@ -11,13 +12,18 @@
* @method Folder parent() Named scope. Gets parent
* @method Folder pathOf($primaryKey) Named scope. Gets path
* @method Folder path() Named scope. Gets path
* @method Folder fullPathOf($primaryKey) Named scope. Get path with its children. (Warning: root node isn't returned.)
* @method Folder fullPath() Named scope. Get path with its children. (Warning: root node isn't returned.)
* @method Folder leaf() Named scope. Fills leaf attribute
*
* ClosureTableBehavior methods
* @method bool isLeaf() If node is a leaf
* @method Folder appendTo($target, $node = null) Appends node to target as child (Only for new records).
* @method Folder append(CActiveRecord $target) Appends node to target as child (Only for new records).
* @method Folder moveTo($target, $node = null) Move node
* @method Folder deleteNode($primaryKey = null) Delete node
* @method bool saveNodeAsRoot($runValidation = true, $attributes = null) Save node and insert closure table records
* with transaction.
* @method int markAsRoot($primaryKey) Insert closure table records
* @method int appendTo($target, $node = null) Appends node to target as child (Only for new records).
* @method int append(CActiveRecord $target) Appends node to target as child (Only for new records).
* @method int moveTo($target, $node = null) Move node
* @method int deleteNode($primaryKey = null) Delete node
*/
class Folder extends CActiveRecord
{
Expand Down
18 changes: 18 additions & 0 deletions tests/unit/ClosureTableBehaviorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,16 @@ public function testPath()
$this->assertEquals(7, $folders[3]->primaryKey);
}

public function testFullPath()
{
$folders = Folder::model()->fullPathOf(4)->findAll();
$this->assertEquals(4, count($folders));
$this->assertEquals(2, $folders[0]->primaryKey);
$this->assertEquals(4, $folders[1]->primaryKey);
$this->assertEquals(5, $folders[2]->primaryKey);
$this->assertEquals(6, $folders[3]->primaryKey);
}

public function testIsLeaf()
{
$leafs = array(3,5,7);
Expand Down Expand Up @@ -177,6 +187,14 @@ public function testDeleteNode()
$this->assertEquals(0, count(Folder::model()->findAll()));
}

public function testSaveAsRoot()
{
$newFolder = new Folder();
$newFolder->name = 'Folder 1';
$this->assertTrue($newFolder->saveNodeAsRoot());
$this->assertEquals(0, count($newFolder->descendants()->findAll()));
$this->assertEquals(0, count($newFolder->ancestors()->findAll()));
}

public function testMixed()
{
Expand Down

0 comments on commit 2149fae

Please sign in to comment.