Commit 9b53bb89 authored by joesimms's avatar joesimms

joesimms: initial draft for tree support. NestedSet support included,...

joesimms: initial draft for tree support. NestedSet support included, placeholders for other popular implementations also included. Read the README.tree file for more information and changelog to core files. Modified core files have also been included in this commit. hope it works and you like it !
parent f56b11af
This diff is collapsed.
<?php
/*
* $Id$
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.com>.
*/
/**
* Doctrine_Node
*
* @package Doctrine
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @category Object Relational Mapping
* @link www.phpdoctrine.com
* @since 1.0
* @version $Revision$
* @author Joe Simms <joe.simms@websites4.com>
*/
class Doctrine_Node implements IteratorAggregate
{
/**
* @param object $record reference to associated Doctrine_Record instance
*/
protected $record;
/**
* @param array $options
*/
protected $options;
/**
* @param string $iteratorType (Pre | Post | Level)
*/
protected $iteratorType;
/**
* @param array $iteratorOptions
*/
protected $iteratorOptions;
/**
* contructor, creates node with reference to record and any options
*
* @param object $record instance of Doctrine_Record
* @param array $options options
*/
public function __construct(&$record, $options)
{
$this->record = $record;
$this->options = $options;
}
/**
* factory method to return node instance based upon chosen implementation
*
* @param object $record instance of Doctrine_Record
* @param string $impName implementation (NestedSet, AdjacencyList, MaterializedPath)
* @param array $options options
* @return object $options instance of Doctrine_Node
*/
public static function factory(&$record, $implName, $options = array()) {
$class = 'Doctrine_Node_'.$implName;
if(!class_exists($class))
throw new Doctrine_Node_Exception("The class $class must exist and extend Doctrine_Node");
return new $class($record, $options);
}
/**
* setter for record attribute
*
* @param object $record instance of Doctrine_Record
*/
public function setRecord(&$record)
{
$this->record = $record;
}
/**
* getter for record attribute
*
* @return object instance of Doctrine_Record
*/
public function getRecord() {
return $this->record;
}
/**
* convenience function for getIterator
*
* @param string $type type of iterator (Pre | Post | Level)
* @param array $options options
*/
public function traverse($type = 'Pre', $options = array()) {
return $this->getIterator($type, $options);
}
/**
* get iterator
*
* @param string $type type of iterator (Pre | Post | Level)
* @param array $options options
*/
public function getIterator($type = null, $options = null)
{
if ($type === null)
$type = (isset($this->iteratorType) ? $this->iteratorType : 'Pre');
if ($options === null)
$options = (isset($this->iteratorOptions) ? $this->iteratorOptions : array());
$iteratorClass = 'Doctrine_Node_'.$this->record->getTable()->getTreeImplName().'_'.ucfirst(strtolower($type)).'OrderIterator';
return new $iteratorClass($this->record, $options);
}
/**
* sets node's iterator type
*
* @param int
*/
public function setIteratorType($type) {
$this->iteratorType = $type;
}
/**
* sets node's iterator options
*
* @param int
*/
public function setIteratorOptions($options) {
$this->iteratorOptions = $options;
}
} // END class
\ No newline at end of file
<?php <?php
/* /*
* $Id$ * $Id$
* *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* *
* This software consists of voluntary contributions made by many individuals * This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see * and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.com>. * <http://www.phpdoctrine.com>.
*/ */
/** /**
* Doctrine_Tree_PathModel * Doctrine_Node_AdjacencyList
* *
* the purpose of Doctrine_Tree_PathModel is to provide PathModel tree access * @package Doctrine
* strategy for all records extending it * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* * @category Object Relational Mapping
* @package Doctrine ORM * @link www.phpdoctrine.com
* @url www.phpdoctrine.com * @since 1.0
* @license LGPL * @version $Revision$
*/ * @author Joe Simms <joe.simms@websites4.com>
class Doctrine_Tree_PathModel extends Doctrine_Record { */
class Doctrine_Node_AdjacencyList extends Doctrine_Node implements Doctrine_Node_Interface { }
public function getLeafNodes() { }
\ No newline at end of file
public function getPath() { }
public function getDepth() { }
public function removeNode() { }
public function addNode() { }
}
<?php <?php
/* /*
* $Id$ * $Id$
* *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* *
* This software consists of voluntary contributions made by many individuals * This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see * and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.com>. * <http://www.phpdoctrine.com>.
*/ */
/** /**
* Doctrine_Tree_NestedSet * Doctrine_Node_AdjacencyList_LevelOrderIterator
* *
* the purpose of Doctrine_Tree_NestedSet is to provide NestedSet tree access * @package Doctrine
* strategy for all records extending it * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* * @category Object Relational Mapping
* @package Doctrine ORM * @link www.phpdoctrine.com
* @url www.phpdoctrine.com * @since 1.0
* @license LGPL * @version $Revision$
*/ * @author Joe Simms <joe.simms@websites4.com>
class Doctrine_Tree_NestedSet extends Doctrine_Record { */
class Doctrine_Node_AdjacencyList_LevelOrderIterator implements Iterator {}
public function getLeafNodes() {
$query = "SELECT ".implode(", ",$this->table->getColumnNames()).
" FROM ".$this->table->getTableName().
" WHERE rgt = lft + 1";
}
public function getPath() { }
public function getDepth() {
$query = "SELECT (COUNT(parent.name) - 1) AS depth
FROM ".$this->table->getTableName()." AS node,".
$this->table->getTableName()." AS parent
WHERE node.lft BETWEEN parent.lft AND parent.rgt
GROUP BY node.name";
}
public function removeNode() { }
public function addNode() { }
}
<?php
/*
* $Id$
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.com>.
*/
/**
* Doctrine_Node_AdjacencyList_PostOrderIterator
*
* @package Doctrine
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @category Object Relational Mapping
* @link www.phpdoctrine.com
* @since 1.0
* @version $Revision$
* @author Joe Simms <joe.simms@websites4.com>
*/
class Doctrine_Node_AdjacencyList_PostOrderIterator implements Iterator {}
<?php
/*
* $Id$
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.com>.
*/
/**
* Doctrine_Node_AdjacencyList_PreOrderIterator
*
* @package Doctrine
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @category Object Relational Mapping
* @link www.phpdoctrine.com
* @since 1.0
* @version $Revision$
* @author Joe Simms <joe.simms@websites4.com>
*/
class Doctrine_Node_AdjacencyList_PreOrderIterator implements Iterator {}
<?php
/*
* $Id$
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.com>.
*/
/**
* Doctrine_Node_Exception
*
* @package Doctrine
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @category Object Relational Mapping
* @link www.phpdoctrine.com
* @since 1.0
* @version $Revision$
* @author Joe Simms <joe.simms@websites4.com>
*/
class Doctrine_Node_Exception extends Doctrine_Exception { }
<?php
/*
* $Id$
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.com>.
*/
/**
* Doctrine_Node_Interface
*
* @package Doctrine
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @category Object Relational Mapping
* @link www.phpdoctrine.com
* @since 1.0
* @version $Revision$
* @author Joe Simms <joe.simms@websites4.com>
*/
interface Doctrine_Node_Interface {
/**
* test if node has previous sibling
*
* @return bool
*/
public function hasPrevSibling();
/**
* test if node has next sibling
*
* @return bool
*/
public function hasNextSibling();
/**
* test if node has children
*
* @return bool
*/
public function hasChildren();
/**
* test if node has parent
*
* @return bool
*/
public function hasParent();
/**
* gets record of prev sibling or empty record
*
* @return object Doctrine_Record
*/
public function getPrevSibling();
/**
* gets record of next sibling or empty record
*
* @return object Doctrine_Record
*/
public function getNextSibling();
/**
* gets siblings for node
*
* @return array array of sibling Doctrine_Record objects
*/
public function getSiblings($includeNode = false);
/**
* gets record of first child or empty record
*
* @return object Doctrine_Record
*/
public function getFirstChild();
/**
* gets record of last child or empty record
*
* @return object Doctrine_Record
*/
public function getLastChild();
/**
* gets children for node (direct descendants only)
*
* @return array array of sibling Doctrine_Record objects
*/
public function getChildren();
/**
* gets descendants for node (direct descendants only)
*
* @return iterator iterator to traverse descendants from node
*/
public function getDescendants();
/**
* gets record of parent or empty record
*
* @return object Doctrine_Record
*/
public function getParent();
/**
* gets ancestors for node
*
* @return object Doctrine_Collection
*/
public function getAncestors();
/**
* gets path to node from root, uses record::toString() method to get node names
*
* @param string $seperator path seperator
* @param bool $includeNode whether or not to include node at end of path
* @return string string representation of path
*/
public function getPath($seperator = ' > ', $includeNode = false);
/**
* gets level (depth) of node in the tree
*
* @return int
*/
public function getLevel();
/**
* gets number of children (direct descendants)
*
* @return int
*/
public function getNumberChildren();
/**
* gets number of descendants (children and their children)
*
* @return int
*/
public function getNumberDescendants();
/**
* inserts node as parent of dest record
*
* @return bool
*/
public function insertAsParentOf(Doctrine_Record $dest);
/**
* inserts node as previous sibling of dest record
*
* @return bool
*/
public function insertAsPrevSiblingOf(Doctrine_Record $dest);
/**
* inserts node as next sibling of dest record
*
* @return bool
*/
public function insertAsNextSiblingOf(Doctrine_Record $dest);
/**
* inserts node as first child of dest record
*
* @return bool
*/
public function insertAsFirstChildOf(Doctrine_Record $dest);
/**
* inserts node as first child of dest record
*
* @return bool
*/
public function insertAsLastChildOf(Doctrine_Record $dest);
/**
* moves node as prev sibling of dest record
*
*/
public function moveAsPrevSiblingOf(Doctrine_Record $dest);
/**
* moves node as next sibling of dest record
*
*/
public function moveAsNextSiblingOf(Doctrine_Record $dest);
/**
* moves node as first child of dest record
*
*/
public function moveAsFirstChildOf(Doctrine_Record $dest);
/**
* moves node as last child of dest record
*
*/
public function moveAsLastChildOf(Doctrine_Record $dest);
/**
* adds node as last child of record
*
*/
public function addChild(Doctrine_Record $record);
/**
* determines if node is leaf
*
* @return bool
*/
public function isLeaf();
/**
* determines if node is root
*
* @return bool
*/
public function isRoot();
/**
* determines if node is equal to subject node
*
* @return bool
*/
public function isEqualTo(Doctrine_Record $subj);
/**
* determines if node is child of subject node
*
* @return bool
*/
public function isDescendantOf(Doctrine_Record $subj);
/**
* determines if node is child of or sibling to subject node
*
* @return bool
*/
public function isDescendantOfOrEqualTo(Doctrine_Record $subj);
/**
* determines if node is valid
*
* @return bool
*/
public function isValidNode();
/**
* deletes node and it's descendants
*
*/
public function delete();
}
\ No newline at end of file
<?php
/*
* $Id$
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.com>.
*/
/**
* Doctrine_Node_MaterializedPath
*
* @package Doctrine
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @category Object Relational Mapping
* @link www.phpdoctrine.com
* @since 1.0
* @version $Revision$
* @author Joe Simms <joe.simms@websites4.com>
*/
class Doctrine_Node_MaterializedPath extends Doctrine_Node implements Doctrine_Node_Interface { }
\ No newline at end of file
<?php
/*
* $Id$
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.com>.
*/
/**
* Doctrine_Node_MaterializedPath_LevelOrderIterator
*
* @package Doctrine
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @category Object Relational Mapping
* @link www.phpdoctrine.com
* @since 1.0
* @version $Revision$
* @author Joe Simms <joe.simms@websites4.com>
*/
class Doctrine_Node_MaterializedPath_LevelOrderIterator implements Iterator
{
private $topNode = null;
private $curNode = null;
public function __construct($node, $opts) {
throw new Doctrine_Exception('Not yet implemented');
}
public function rewind() {
throw new Doctrine_Exception('Not yet implemented');
}
public function valid() {
throw new Doctrine_Exception('Not yet implemented');
}
public function current() {
throw new Doctrine_Exception('Not yet implemented');
}
public function key() {
throw new Doctrine_Exception('Not yet implemented');
}
public function next() {
throw new Doctrine_Exception('Not yet implemented');
}
}
<?php
/*
* $Id$
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.com>.
*/
/**
* Doctrine_Node_MaterializedPath_PostOrderIterator
*
* @package Doctrine
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @category Object Relational Mapping
* @link www.phpdoctrine.com
* @since 1.0
* @version $Revision$
* @author Joe Simms <joe.simms@websites4.com>
*/
class Doctrine_Node_MaterializedPath_PostOrderIterator implements Iterator
{
private $topNode = null;
private $curNode = null;
public function __construct($node, $opts) {
throw new Doctrine_Exception('Not yet implemented');
}
public function rewind() {
throw new Doctrine_Exception('Not yet implemented');
}
public function valid() {
throw new Doctrine_Exception('Not yet implemented');
}
public function current() {
throw new Doctrine_Exception('Not yet implemented');
}
public function key() {
throw new Doctrine_Exception('Not yet implemented');
}
public function next() {
throw new Doctrine_Exception('Not yet implemented');
}
}
<?php
/*
* $Id$
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.com>.
*/
/**
* Doctrine_Node_MaterializedPath_PreOrderIterator
*
* @package Doctrine
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @category Object Relational Mapping
* @link www.phpdoctrine.com
* @since 1.0
* @version $Revision$
* @author Joe Simms <joe.simms@websites4.com>
*/
class Doctrine_Node_MaterializedPath_PreOrderIterator implements Iterator
{
private $topNode = null;
private $curNode = null;
public function __construct($node, $opts) {
throw new Doctrine_Exception('Not yet implemented');
}
public function rewind() {
throw new Doctrine_Exception('Not yet implemented');
}
public function valid() {
throw new Doctrine_Exception('Not yet implemented');
}
public function current() {
throw new Doctrine_Exception('Not yet implemented');
}
public function key() {
throw new Doctrine_Exception('Not yet implemented');
}
public function next() {
throw new Doctrine_Exception('Not yet implemented');
}
}
This diff is collapsed.
<?php
/*
* $Id$
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.com>.
*/
/**
* Doctrine_Node_NestedSet_LevelOrderIterator
*
* @package Doctrine
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @category Object Relational Mapping
* @link www.phpdoctrine.com
* @since 1.0
* @version $Revision$
* @author Joe Simms <joe.simms@websites4.com>
*/
class Doctrine_Node_NestedSet_LevelOrderIterator implements Iterator {}
<?php
/*
* $Id$
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.com>.
*/
/**
* Doctrine_Node_NestedSet_PostOrderIterator
*
* @package Doctrine
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @category Object Relational Mapping
* @link www.phpdoctrine.com
* @since 1.0
* @version $Revision$
* @author Joe Simms <joe.simms@websites4.com>
*/
class Doctrine_Node_NestedSet_PostOrderIterator implements Iterator {}
<?php
/*
* $Id$
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.com>.
*/
/**
* Doctrine_Node_NestedSet_PreOrderIterator
*
* @package Doctrine
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @category Object Relational Mapping
* @link www.phpdoctrine.com
* @since 1.0
* @version $Revision$
* @author Joe Simms <joe.simms@websites4.com>
*/
class Doctrine_Node_NestedSet_PreOrderIterator implements Iterator
{
/**
* @var Doctrine_Collection $collection
*/
protected $collection;
/**
* @var array $keys
*/
protected $keys;
/**
* @var mixed $key
*/
protected $key;
/**
* @var integer $index
*/
protected $index;
/**
* @var integer $index
*/
protected $prevIndex;
/**
* @var integer $index
*/
protected $traverseLevel;
/**
* @var integer $count
*/
protected $count;
public function __construct($record, $opts) {
$componentName = $record->getTable()->getComponentName();
$q = $record->getTable()->createQuery();
if(isset($opts['include_record']) && $opts['include_record'])
{
$query = $q->where("$componentName.lft >= ? AND $componentName.rgt <= ?", array($record->get('lft'), $record->get('rgt')))->orderBy('lft asc');
}
else
{
$query = $q->where("$componentName.lft > ? AND $componentName.rgt < ?", array($record->get('lft'), $record->get('rgt')))->orderBy('lft asc');
}
$this->maxLevel = isset($opts['depth']) ? ($opts['depth'] + $record->getNode()->getLevel()) : 0;
$this->options = $opts;
$this->collection = isset($opts['collection']) ? $opts['collection'] : $query->execute();
$this->keys = $this->collection->getKeys();
$this->count = $this->collection->count();
$this->index = -1;
$this->level = $record->getNode()->getLevel();
$this->prevLeft = $record->getNode()->getLeftValue();
echo $this->maxDepth;
// clear the table identity cache
$record->getTable()->clear();
}
/**
* rewinds the iterator
*
* @return void
*/
public function rewind() {
$this->index = -1;
$this->key = null;
}
/**
* returns the current key
*
* @return integer
*/
public function key() {
return $this->key;
}
/**
* returns the current record
*
* @return Doctrine_Record
*/
public function current() {
$record = $this->collection->get($this->key);
$record->getNode()->setLevel($this->level);
return $record;
}
/**
* advances the internal pointer
*
* @return void
*/
public function next() {
while($current = $this->advanceIndex())
{
if($this->maxLevel && ($this->level > $this->maxLevel))
continue;
return $current;
}
return false;
}
/**
* @return boolean whether or not the iteration will continue
*/
public function valid() {
return ($this->index < $this->count);
}
public function count() {
return $this->count;
}
private function updateLevel() {
if(!(isset($this->options['include_record']) && $this->options['include_record'] && $this->index == 0))
{
$left = $this->collection->get($this->key)->getNode()->getLeftValue();
$this->level += $this->prevLeft - $left + 2;
$this->prevLeft = $left;
}
}
private function advanceIndex() {
$this->index++;
$i = $this->index;
if(isset($this->keys[$i]))
{
$this->key = $this->keys[$i];
$this->updateLevel();
return $this->current();
}
return false;
}
}
<?php
/*
* $Id$
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.com>.
*/
Doctrine::autoload('Doctrine_Query_Part');
/**
* Doctrine_Query
*
* @package Doctrine
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @category Object Relational Mapping
* @link www.phpdoctrine.com
* @since 1.0
* @version $Revision$
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
*/
class Doctrine_Query_Set extends Doctrine_Query_Part
{
public function parse($dql)
{
$parts = Doctrine_Query::sqlExplode($dql, ',');
$result = array();
foreach ($parts as $part) {
$set = Doctrine_Query::sqlExplode($part, '=');
$e = explode('.', trim($set[0]));
$field = array_pop($e);
$reference = implode('.', $e);
$alias = $this->query->getTableAlias($reference);
$fieldname = $alias ? $alias . '.' . $field : $field;
$result[] = $fieldname . ' = ' . $set[1];
}
return implode(', ', $result);
}
}
<?php
/*
* $Id$
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.com>.
*/
Doctrine::autoload('Doctrine_Query_Condition');
/**
* Doctrine_Query_Where
*
* @package Doctrine
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @category Object Relational Mapping
* @link www.phpdoctrine.com
* @since 1.0
* @version $Revision$
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
*/
class Doctrine_Query_Where extends Doctrine_Query_Condition
{
/**
* load
* returns the parsed query part
*
* @param string $where
* @return string
*/
public function load($where)
{
$where = trim($where);
$e = Doctrine_Query::sqlExplode($where);
if (count($e) > 1) {
$tmp = $e[0] . ' ' . $e[1];
if (substr($tmp, 0, 6) == 'EXISTS') {
return $this->parseExists($where, true);
} elseif (substr($where, 0, 10) == 'NOT EXISTS') {
return $this->parseExists($where, false);
}
}
if (count($e) < 3) {
$e = Doctrine_Query::sqlExplode($where, array('=', '<', '>', '!='));
}
$r = array_shift($e);
$a = explode('.', $r);
if (count($a) > 1) {
$field = array_pop($a);
$count = count($e);
$slice = array_slice($e, -1, 1);
$value = implode('', $slice);
$operator = trim(substr($where, strlen($r), -strlen($value)));
$reference = implode('.', $a);
$count = count($a);
$pos = strpos($field, '(');
if ($pos !== false) {
$func = substr($field, 0, $pos);
$value = trim(substr($field, ($pos + 1), -1));
$values = Doctrine_Query::sqlExplode($value, ',');
$field = array_pop($a);
$reference = implode('.', $a);
$table = $this->query->load($reference, false);
array_pop($a);
$reference2 = implode('.', $a);
$alias = $this->query->getTableAlias($reference2);
$stack = $this->query->getRelationStack();
$relation = end($stack);
$stack = $this->query->getTableStack();
switch ($func) {
case 'contains':
case 'regexp':
case 'like':
$operator = $this->getOperator($func);
if (empty($relation)) {
throw new Doctrine_Query_Exception('DQL functions contains/regexp/like can only be used for fields of related components');
}
$where = array();
foreach ($values as $value) {
$where[] = $alias.'.'.$relation->getLocal().
' IN (SELECT '.$relation->getForeign().
' FROM '.$relation->getTable()->getTableName().' WHERE '.$field.$operator.$value.')';
}
$where = implode(' AND ', $where);
break;
default:
throw new Doctrine_Query_Exception('Unknown DQL function: '.$func);
}
} else {
$table = $this->query->load($reference, false);
$alias = $this->query->getTableAlias($reference);
$table = $this->query->getTable($alias);
// check if value is enumerated value
$enumIndex = $table->enumIndex($field, trim($value, "'"));
if (substr($value, 0, 1) == '(') {
// trim brackets
$trimmed = Doctrine_Query::bracketTrim($value);
if (substr($trimmed, 0, 4) == 'FROM' || substr($trimmed, 0, 6) == 'SELECT') {
// subquery found
$q = new Doctrine_Query();
$value = '(' . $q->parseQuery($trimmed)->getQuery() . ')';
} elseif (substr($trimmed, 0, 4) == 'SQL:') {
$value = '(' . substr($trimmed, 4) . ')';
} else {
// simple in expression found
$e = Doctrine_Query::sqlExplode($trimmed, ',');
$value = array();
foreach ($e as $part) {
$index = $table->enumIndex($field, trim($part, "'"));
if ($index !== false) {
$value[] = $index;
} else {
$value[] = $this->parseLiteralValue($part);
}
}
$value = '(' . implode(', ', $value) . ')';
}
} else {
if ($enumIndex !== false) {
$value = $enumIndex;
} else {
$value = $this->parseLiteralValue($value);
}
}
switch ($operator) {
case '<':
case '>':
case '=':
case '!=':
if ($enumIndex !== false) {
$value = $enumIndex;
}
default:
$fieldname = $alias ? $alias . '.' . $field : $field;
$where = $fieldname . ' '
. $operator . ' ' . $value;
}
}
}
return $where;
}
/**
* parses an EXISTS expression
*
* @param string $where query where part to be parsed
* @param boolean $negation whether or not to use the NOT keyword
* @return string
*/
public function parseExists($where, $negation)
{
$operator = ($negation) ? 'EXISTS' : 'NOT EXISTS';
$pos = strpos($where, '(');
if ($pos == false)
throw new Doctrine_Query_Exception("Unknown expression, expected '('");
$sub = Doctrine_Query::bracketTrim(substr($where, $pos));
return $operator . ' ('.$this->query->createSubquery()->parseQuery($sub, false)->getQuery() . ')';
}
/**
* getOperator
*
* @param string $func
* @return string
*/
public function getOperator($func)
{
switch ($func) {
case 'contains':
$operator = ' = ';
break;
case 'regexp':
$operator = $this->query->getConnection()->getRegexpOperator();
break;
case 'like':
$operator = ' LIKE ';
break;
}
return $operator;
}
/**
* __toString
* return string representation of this object
*
* @return string
*/
public function __toString()
{
return ( ! empty($this->parts))?implode(' AND ', $this->parts):'';
}
}
REMEMBER
--------
If performing batch tree manipulation tasks, then remember to refresh your records (see record::refresh()), as any transformations of the tree are likely to affect all instances of records that you have in your scope. (zYne, is there any way of automating this?)
If you are inserting or moving a node within the tree, you must use the appropriate function to place the node in it's destination. Note: you cannot save a new record without inserting it into the tree.
You can save an already existing node using record::save() without affecting the tree. Never set the tree specific record attributes manually.
If you wish to delete a record, you MUST delete the node and not the record, using $record->deleteNode() or $record->getNode()->delete(). Deleting a node, will delete all its descendants.
The difference between descendants and children is that descendants include children of children whereas children are direct descendants of their parent (real children not gran children and great gran children etc etc).
The most effective way to traverse a tree from the root node, is to use the tree::fetchTree() method:
$tree = $manager->getTable('Model')->getTree()->fetchTree();
It will by default include the root node in the tree and will return an iterator to traverse the tree.
To traverse a tree from a given node, it will normally cost 3 queries, one to fetch the starting node, one to fetch the branch from this node, and one to determine the level of the start node, the traversal algorithm with then determine the level of each subsequent node for you.
EXAMPLES
--------
See EXAMPLE.tree.php for very draft examples on how to use the tree interface within doctrine (note that the interface is independent of the implementation, so when other implementations are added, you should be able to switch implementation and your code still work). This should be run in a browser and relevant database settings altered as appropriate.
MORE INFO
---------
For more info on storing hierarchical data in databases, the various implementations and tree traversal see these articles:
http://dev.mysql.com/tech-resources/articles/hierarchical-data.html
http://www.sitepoint.com/article/hierarchical-data-database
http://en.wikipedia.org/wiki/Tree_traversal
TO DO
-----
Discuss adding __call() to record to allow the node methods to be called directly from the record, although i know we are trying to avoid introspection.
Discuss adding a level column to the database to store levels (will reduce traversing nodes by one query, and allow us to implement the LevelOrder Traversal of the Tree with one query, but updating tree may be more costly).
Maybe add tree configuration to allow the above to be configurable as well as other options such as:
-on deletion of a node, move descendants, unassign descendants or delete descendants
-allowing the ability to save nodes that are not assigned in the tree (set lft=0, rgt=0, retrieve with tree::fetchUnassigned)
-auto refreshing objects left and right values used in tree transformations
Return getSiblings and getAncestors as Iterators
NOTES FOR ZYNE
--------------
IMHO, i think that the Ajacency list should be moved into a tree structure, the table definitions and setUp can be set in the class Doctrine_Tree_AdjacencyList, then they simply have to call actsAsTree('AdjacencyList') in their setTableDefinition, although to be honest, with nestedset implemented i cannot think why i would want to use adjacency list anyhow !
Doctrine_Query_Set, Doctrine_Query_Where
----------------------------------------
Not too sure if problem with my query syntax or with Doctrine, but i followed examples in docs
In set and where, if not Component supplied, then alias is empty, so resultant query would be something like:
UPDATE menu m SET .lft = lft + 2
WHERE lft >= ?
Notice the invalid resultant syntax .lft, as the alias was not set, so added check to determine if alias isset.
CHANGELOG
---------
Doctrine_Record
---------------
added methods:
getNode()
deleteNode()
amended:
actsAsTree()
Doctrine_Table
--------------
amended constructor to call tree::setUp()
added setTree(), to call tree::setTableDefinition() and setup Tree in Table
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
<?php <?php
/* /*
* $Id$ * $Id$
* *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* *
* This software consists of voluntary contributions made by many individuals * This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see * and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.com>. * <http://www.phpdoctrine.com>.
*/ */
/** /**
* Doctrine_Tree * Doctrine_Tree
* *
* the purpose of Doctrine_Tree is to provide tree access * @package Doctrine
* functionality for all records extending it * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* * @category Object Relational Mapping
* @package Doctrine ORM * @link www.phpdoctrine.com
* @url www.phpdoctrine.com * @since 1.0
* @license LGPL * @version $Revision$
*/ * @author Joe Simms <joe.simms@websites4.com>
abstract class Doctrine_Tree extends Doctrine_Record { */
class Doctrine_Tree
abstract public function getLeafNodes(); {
/**
abstract public function getPath(); * @param object $table reference to associated Doctrine_Table instance
*/
abstract public function getDepth(); protected $table;
abstract public function removeNode(); /**
* @param array $options
abstract public function addNode(); */
} protected $options;
/**
* contructor, creates tree with reference to table and any options
*
* @param object $table instance of Doctrine_Table
* @param array $options options
*/
public function __construct($table, $options)
{
$this->table = $table;
$this->options = $options;
}
/**
* Used to define table attributes required for the given implementation
*
*/
public function setTableDefinition()
{
throw new Doctrine_Tree_Exception('Table attributes have not been defined for this Tree implementation.');
}
/**
* this method is used for setting up relations and attributes and should be used by specific implementations
*
*/
public function setUp()
{
}
/**
* factory method to return tree instance based upon chosen implementation
*
* @param object $table instance of Doctrine_Table
* @param string $impName implementation (NestedSet, AdjacencyList, MaterializedPath)
* @param array $options options
* @return object $options instance of Doctrine_Node
*/
public static function factory( &$table, $implName, $options = array())
{
$class = 'Doctrine_Tree_'.$implName;
if(!class_exists($class))
throw new Doctrine_Exception('The chosen class must extend Doctrine_Tree');
return new $class($table, $options);
}
} // END class
\ No newline at end of file
<?php
/*
* $Id$
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.com>.
*/
/**
* Doctrine_Tree_AdjacencyList
*
* @package Doctrine
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @category Object Relational Mapping
* @link www.phpdoctrine.com
* @since 1.0
* @version $Revision$
* @author Joe Simms <joe.simms@websites4.com>
*/
class Doctrine_Tree_AdjacencyList extends Doctrine_Tree implements Doctrine_Tree_Interface { }
<?php
/*
* $Id$
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.com>.
*/
/**
* Doctrine_Tree_Exception
*
* @package Doctrine
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @category Object Relational Mapping
* @link www.phpdoctrine.com
* @since 1.0
* @version $Revision$
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
*/
class Doctrine_Tree_Exception extends Doctrine_Exception { }
<?php
/*
* $Id$
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.com>.
*/
/**
* Doctrine_Tree_Interface
*
* @package Doctrine
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @category Object Relational Mapping
* @link www.phpdoctrine.com
* @since 1.0
* @version $Revision$
* @author Joe Simms <joe.simms@websites4.com>
*/
interface Doctrine_Tree_Interface {
/**
* creates root node from given record or from a new record
*
* @param object $record instance of Doctrine_Record
*/
public function createRoot(Doctrine_Record $record = null);
/**
* returns root node
*
* @return object $record instance of Doctrine_Record
*/
public function findRoot();
/**
* optimised method to returns iterator for traversal of the entire tree from root
*
* @param array $options options
* @return object $iterator instance of Doctrine_Node_<Implementation>_PreOrderIterator
*/
public function fetchTree($options = array());
/**
* optimised method that returns iterator for traversal of the tree from the given record primary key
*
* @param mixed $pk primary key as used by table::find() to locate node to traverse tree from
* @param array $options options
* @return iterator instance of Doctrine_Node_<Implementation>_PreOrderIterator
*/
public function fetchBranch($pk, $options = array());
}
\ No newline at end of file
<?php
/*
* $Id$
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.com>.
*/
/**
* Doctrine_Tree_MaterializedPath
*
* @package Doctrine
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @category Object Relational Mapping
* @link www.phpdoctrine.com
* @since 1.0
* @version $Revision$
* @author Joe Simms <joe.simms@websites4.com>
*/
class Doctrine_Tree_MaterializedPath extends Doctrine_Tree implements Doctrine_Tree_Interface { }
\ No newline at end of file
<?php
/*
* $Id$
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.com>.
*/
/**
* Doctrine_Tree_NestedSet
*
* @package Doctrine
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @category Object Relational Mapping
* @link www.phpdoctrine.com
* @since 1.0
* @version $Revision$
* @author Joe Simms <joe.simms@websites4.com>
*/
class Doctrine_Tree_NestedSet extends Doctrine_Tree implements Doctrine_Tree_Interface
{
/**
* used to define table attributes required for the NestetSet implementation
* adds lft and rgt columns for corresponding left and right values
*
*/
public function setTableDefinition()
{
$this->table->setColumn("lft","integer",11);
$this->table->setColumn("rgt","integer",11);
}
/**
* creates root node from given record or from a new record
*
* @param object $record instance of Doctrine_Record
*/
public function createRoot(Doctrine_Record $record = null)
{
if(!$record)
{
$record = $this->table->create();
}
$record->set('lft', '1');
$record->set('rgt', '2');
$record->save();
return $record;
}
/**
* returns root node
*
* @return object $record instance of Doctrine_Record
*/
public function findRoot()
{
$q = $this->table->createQuery();
$root = $q->where('lft = ?', 1)
->execute()->getFirst();
// if no record is returned, create record
if(!$root)
{
$root = $this->table->create();
}
// set level to prevent additional query to determine level
$root->getNode()->setLevel(0);
return $root;
}
/**
* optimised method to returns iterator for traversal of the entire tree from root
*
* @param array $options options
* @return object $iterator instance of Doctrine_Node_NestedSet_PreOrderIterator
*/
public function fetchTree($options = array())
{
// fetch tree
$q = $this->table->createQuery();
$tree = $q->where('lft >= ?', 1)
->orderBy('lft asc')
->execute();
$root = $tree->getFirst();
// if no record is returned, create record
if(!$root)
{
$root = $this->table->create();
}
if($root->exists())
{
// set level to prevent additional query
$root->getNode()->setLevel(0);
// default to include root node
$options = array_merge(array('include_record'=>true), $options);
// remove root node from collection if not required
if($options['include_record'] == false)
$tree->remove(0);
// set collection for iterator
$options['collection'] = $tree;
return $root->getNode()->traverse('Pre', $options);
}
}
/**
* optimised method that returns iterator for traversal of the tree from the given record primary key
*
* @param mixed $pk primary key as used by table::find() to locate node to traverse tree from
* @param array $options options
* @return iterator instance of Doctrine_Node_<Implementation>_PreOrderIterator
*/
public function fetchBranch($pk, $options = array())
{
$record = $this->table->find($pk);
if($record->exists())
{
$options = array_merge(array('include_record'=>true), $options);
return $record->getNode()->traverse('Pre', $options);
}
}
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment