Author: dr
Date: Fri Oct 5 17:16:45 2007
New Revision: 6378
Log:
- Renamed the ezcTreeInvalidIdException to ezcTreeUnknownIdException and
added the ezcTreeInvalidIdException that tells you when the ID itself
is broken.
- Added an option that allows you to change the separation character for
the materialized path backend.
Modified:
trunk/Tree/design/class_diagram.png
trunk/Tree/review.txt
trunk/Tree/src/backends/memory.php
trunk/Tree/src/backends/xml.php
trunk/Tree/src/exceptions/invalid_id.php
trunk/Tree/src/tree.php
trunk/Tree/src/tree_autoload.php
trunk/Tree/tests/tree.php
trunk/TreeDatabaseTiein/src/backends/db_materialized_path.php
trunk/TreeDatabaseTiein/src/backends/db_nested_set.php
trunk/TreeDatabaseTiein/tests/db_materialized_path_tree.php
trunk/TreeDatabaseTiein/tests/suite.php
Modified: trunk/Tree/design/class_diagram.png
==============================================================================
Binary files - no diff available.
Modified: trunk/Tree/review.txt
==============================================================================
--- trunk/Tree/review.txt [iso-8859-1] (original)
+++ trunk/Tree/review.txt [iso-8859-1] Fri Oct 5 17:16:45 2007
@@ -13,7 +13,7 @@
It was, but I added an option to make both subtrees and just nodes
highlighted now.
-[ ] Files missing __get() and __set() ($this->properties is accessed directly):
+[X] Files missing __get() and __set() ($this->properties is accessed directly):
- Tree/src/backends/memory.php
- Tree/src/backends/xml.php (__get() is present, but not fully
implemented)
- Tree/src/tree_node.php (__get() and set() are implemented but not used)
@@ -48,7 +48,7 @@
Other points
------------
-[ ] Issue #11444: Allow the / char to be changed in the nested set
+[X] Issue #11444: Allow the / char to be changed in the materialized path
implementation, and add a check for this char in used IDs when creating
a
new node.
@@ -57,7 +57,7 @@
[ ] Check XHTML visitor's generation of paths - they are sort of useles as
only the
last item is used. Perhaps make this an option.
-[ ] Check if the highlighting can be done on the data, and not the <li> nodes -
+[X] Check if the highlighting can be done on the data, and not the <li> nodes -
make that an option as well perhaps.
[ ] Check example from Alex, and add them to docs if useful.
Modified: trunk/Tree/src/backends/memory.php
==============================================================================
--- trunk/Tree/src/backends/memory.php [iso-8859-1] (original)
+++ trunk/Tree/src/backends/memory.php [iso-8859-1] Fri Oct 5 17:16:45 2007
@@ -113,7 +113,7 @@
{
if ( !$this->nodeExists( $nodeId ) )
{
- throw new ezcTreeInvalidIdException( $nodeId );
+ throw new ezcTreeUnknownIdException( $nodeId );
}
return $this->nodeList[$nodeId];
}
Modified: trunk/Tree/src/backends/xml.php
==============================================================================
--- trunk/Tree/src/backends/xml.php [iso-8859-1] (original)
+++ trunk/Tree/src/backends/xml.php [iso-8859-1] Fri Oct 5 17:16:45 2007
@@ -269,7 +269,7 @@
$node = $this->dom->getElementById(
"{$this->properties['prefix']}$nodeId" );
if ( !$node )
{
- throw new ezcTreeInvalidIdException( $nodeId );
+ throw new ezcTreeUnknownIdException( $nodeId );
}
return $node;
}
Modified: trunk/Tree/src/exceptions/invalid_id.php
==============================================================================
--- trunk/Tree/src/exceptions/invalid_id.php [iso-8859-1] (original)
+++ trunk/Tree/src/exceptions/invalid_id.php [iso-8859-1] Fri Oct 5 17:16:45
2007
@@ -10,8 +10,7 @@
*/
/**
- * Exception that is thrown when a node is request through an invalid
- * (non-existing) ID.
+ * Exception that is thrown when a node is created with an invalid ID.
*
* @package Tree
* @version //autogentag//
@@ -23,9 +22,9 @@
*
* @param string $nodeId
*/
- public function __construct( $nodeId )
+ public function __construct( $nodeId, $invalidChar )
{
- parent::__construct( "The node with ID '{$nodeId}' could not be
found." );
+ parent::__construct( "The node ID '{$nodeId}' contains the invalid
character '{$invalidChar}'." );
}
}
?>
Modified: trunk/Tree/src/tree.php
==============================================================================
--- trunk/Tree/src/tree.php [iso-8859-1] (original)
+++ trunk/Tree/src/tree.php [iso-8859-1] Fri Oct 5 17:16:45 2007
@@ -166,6 +166,18 @@
}
/**
+ * This method checks whether a node ID is valid to be used in a backend.
+ *
+ * @throws ezcTreeInvalidNodeIDException if the node is not valid.
+ *
+ * @param string $nodeId
+ */
+ protected function checkNodeId( $nodeId )
+ {
+ /* The default implementation does not check anything */
+ }
+
+ /**
* Creates a new tree node with node ID $nodeId and $data.
*
* This method returns by default an object of the ezcTreeNode class,
@@ -179,6 +191,7 @@
*/
public function createNode( $nodeId, $data )
{
+ $this->checkNodeID( $nodeId );
$className = $this->properties['nodeClassName'];
return new $className( $this, $nodeId, $data );
}
@@ -213,7 +226,7 @@
{
if ( !$this->nodeExists( $nodeId ) )
{
- throw new ezcTreeInvalidIdException( $nodeId );
+ throw new ezcTreeUnknownIdException( $nodeId );
}
$className = $this->properties['nodeClassName'];
$node = new $className( $this, $nodeId );
Modified: trunk/Tree/src/tree_autoload.php
==============================================================================
--- trunk/Tree/src/tree_autoload.php [iso-8859-1] (original)
+++ trunk/Tree/src/tree_autoload.php [iso-8859-1] Fri Oct 5 17:16:45 2007
@@ -19,6 +19,7 @@
'ezcTreeInvalidXmlFormatException' =>
'Tree/exceptions/invalid_xml_format.php',
'ezcTreeTransactionAlreadyStartedException' =>
'Tree/exceptions/transaction_already_started.php',
'ezcTreeTransactionNotStartedException' =>
'Tree/exceptions/transaction_not_started.php',
+ 'ezcTreeUnknownIdException' =>
'Tree/exceptions/unknown_id.php',
'ezcTreeDataStore' =>
'Tree/interfaces/data_store.php',
'ezcTreeVisitable' =>
'Tree/interfaces/visitable.php',
'ezcTree' => 'Tree/tree.php',
Modified: trunk/Tree/tests/tree.php
==============================================================================
--- trunk/Tree/tests/tree.php [iso-8859-1] (original)
+++ trunk/Tree/tests/tree.php [iso-8859-1] Fri Oct 5 17:16:45 2007
@@ -164,7 +164,7 @@
$node = $tree->fetchNodeById( 42 );
self::fail( "Expected exception was not thrown." );
}
- catch ( ezcTreeInvalidIdException $e )
+ catch ( ezcTreeUnknownIdException $e )
{
self::assertSame( "The node with ID '42' could not be found.",
$e->getMessage() );
}
@@ -192,7 +192,7 @@
{
self::assertSame( true, $tree->fetchNodeById( 98 )->isChildOf(
$tree->fetchNodeById( 99 ) ) );
}
- catch ( ezcTreeInvalidIdException $e )
+ catch ( ezcTreeUnknownIdException $e )
{
self::assertSame( "The node with ID '98' could not be found.",
$e->getMessage() );
}
@@ -220,7 +220,7 @@
{
self::assertSame( false, $tree->isChildOf( 98, 99 ) );
}
- catch ( ezcTreeInvalidIdException $e )
+ catch ( ezcTreeUnknownIdException $e )
{
self::assertSame( "The node with ID '98' could not be found.",
$e->getMessage() );
}
Modified: trunk/TreeDatabaseTiein/src/backends/db_materialized_path.php
==============================================================================
--- trunk/TreeDatabaseTiein/src/backends/db_materialized_path.php [iso-8859-1]
(original)
+++ trunk/TreeDatabaseTiein/src/backends/db_materialized_path.php [iso-8859-1]
Fri Oct 5 17:16:45 2007
@@ -23,6 +23,9 @@
*
* @property-read ezcTreeDbDataStore $store
* The data store that is used for retrieving/storing data.
+ * @property-read string $separationChar
+ * The character that is used to separate node IDs internally.
+ * This character can then *not* be part of a node ID.
* @property string $nodeClassName
* Which class is used as tree node - this class *must* inherit
* the ezcTreeNode class.
@@ -34,12 +37,116 @@
class ezcTreeDbMaterializedPath extends ezcTreeDb
{
/**
+ * Constructs a new ezcTreeDbMaterializedPath object.
+ *
+ * The different arguments to the constructor configure which database
+ * connection ($dbh) is used to access the database and the $indexTableName
+ * argument which table is used to retrieve the relation data from. The
+ * $store argument configure which data store is used with this tree.
+ *
+ * The $separationChar argument defaults to / and is used to separate node
+ * IDs internally. This character can *not* be part of a node ID, and
should be
+ * the same character that was used when creating the tree.
+ *
+ * Just like the others, this database backend requires the index table to
+ * at least define the field 'id', which can either be a string or an
+ * integer field.
+ *
+ * @param ezcDbHandler $dbh
+ * @param string $indexTableName
+ * @param ezcTreeDbDataStore $store
+ * @param string $separationChar
+ */
+ public function __construct( ezcDbHandler $dbh, $indexTableName,
ezcTreeDbDataStore $store, $separationChar = '/' )
+ {
+ parent::__construct( $dbh, $indexTableName, $store );
+ $this->properties['separationChar'] = $separationChar;
+ }
+
+ /**
+ * Returns the value of the property $name.
+ *
+ * @throws ezcBasePropertyNotFoundException if the property does not exist.
+ * @param string $name
+ * @ignore
+ */
+ public function __get( $name )
+ {
+ switch ( $name )
+ {
+ case 'separationChar':
+ return $this->properties[$name];
+ }
+ return parent::__get( $name );
+ }
+
+ /**
+ * Sets the property $name to $value.
+ *
+ * @throws ezcBasePropertyNotFoundException if the property does not exist.
+ * @throws ezcBasePropertyPermissionException if a read-only property is
+ * tried to be modified.
+ * @param string $name
+ * @param mixed $value
+ * @ignore
+ */
+ public function __set( $name, $value )
+ {
+ switch ( $name )
+ {
+ case 'separationChar':
+ throw new ezcBasePropertyPermissionException( $name,
ezcBasePropertyPermissionException::READ );
+
+ default:
+ return parent::__set( $name, $value );
+ }
+ }
+
+ /**
+ * Returns true if the property $name is set, otherwise false.
+ *
+ * @param string $name
+ * @return bool
+ * @ignore
+ */
+ public function __isset( $name )
+ {
+ switch ( $name )
+ {
+ case 'separationChar':
+ return isset( $this->properties[$name] );
+
+ default:
+ return parent::__isset( $name );
+ }
+ }
+
+ /**
+ * This method checks whether a node ID is valid to be used in a backend.
+ *
+ * @throws ezcTreeInvalidNodeIDException if the node is not valid.
+ *
+ * @param string $nodeId
+ */
+ protected function checkNodeId( $nodeId )
+ {
+ if ( strchr( $nodeId, $this->properties['separationChar'] ) != false )
+ {
+ throw new ezcTreeInvalidIdException( $nodeId,
$this->properties['separationChar'] );
+ }
+ }
+
+ /**
* Creates a new ezcTreeDbMaterializedPath object.
*
* The different arguments to the method configure which database
* connection ($dbh) is used to access the database and the $indexTableName
* argument which table is used to retrieve the relation data from. The
* $store argument configure which data store is used with this tree.
+ *
+ * The $separationChar argument defaults to / and is used to separate node
+ * IDs internally. This character can *not* be part of a node ID, and the
same
+ * character should be used when re-opening the tree upon instantiation.
*
* It is up to the user to create the database table and make sure it is
* empty.
@@ -47,10 +154,11 @@
* @param ezcDbHandler $dbh
* @param string $indexTableName
* @param ezcTreeDbDataStore $store
- */
- public static function create( ezcDbHandler $dbh, $indexTableName,
ezcTreeDbDataStore $store )
- {
- return new ezcTreeDbMaterializedPath( $dbh, $indexTableName, $store );
+ * @param string $separationChar
+ */
+ public static function create( ezcDbHandler $dbh, $indexTableName,
ezcTreeDbDataStore $store, $separationChar = '/' )
+ {
+ return new ezcTreeDbMaterializedPath( $dbh, $indexTableName, $store,
$separationChar );
}
/**
@@ -136,7 +244,7 @@
// Fetch node information
list( $parentId, $path ) = $this->fetchNodeInformation( $nodeId );
- $parts = split( '/', $path );
+ $parts = split( $this->properties['separationChar'], $path );
array_shift( $parts );
foreach ( $parts as $pathNodeId )
@@ -174,7 +282,7 @@
// WHERE path LIKE '$path/%'
$q->select( 'id' )
->from( $db->quoteIdentifier( $this->indexTableName ) )
- ->where( $q->expr->like( 'path', $q->bindValue( "$path/%" ) ) );
+ ->where( $q->expr->like( 'path', $q->bindValue(
"$path{$this->properties['separationChar']}%" ) ) );
$s = $q->prepare();
$s->execute();
@@ -277,7 +385,7 @@
// WHERE path LIKE '$path/%'
$q->select( 'count(id)' )
->from( $db->quoteIdentifier( $this->indexTableName ) )
- ->where( $q->expr->like( 'path', $q->bindValue( "$path/%" ) ) );
+ ->where( $q->expr->like( 'path', $q->bindValue(
"$path{$this->properties['separationChar']}%" ) ) );
$s = $q->prepare();
$s->execute();
$r = $s->fetch( PDO::FETCH_NUM );
@@ -296,7 +404,7 @@
// Fetch information for node
list( $parentId, $path ) = $this->fetchNodeInformation( $nodeId );
- return substr_count( $path, '/' ) - 1;
+ return substr_count( $path, $this->properties['separationChar'] ) - 1;
}
/**
@@ -338,7 +446,7 @@
// Fetch node information
list( $dummyParentId, $path ) = $this->fetchNodeInformation( $childId
);
- $parts = split( '/', $path );
+ $parts = split( $this->properties['separationChar'], $path );
array_shift( $parts );
return in_array( $parentId, $parts ) && ( $childId !== $parentId );
@@ -378,7 +486,7 @@
$q->insertInto( $db->quoteIdentifier( $this->indexTableName ) )
->set( 'parent_id', "null" )
->set( 'id', $q->bindValue( $node->id ) )
- ->set( 'path', $q->bindValue( '/' . $node->id ) );
+ ->set( 'path', $q->bindValue( $this->properties['separationChar'] .
$node->id ) );
$s = $q->prepare();
$s->execute();
@@ -408,7 +516,7 @@
$q->insertInto( $db->quoteIdentifier( $this->indexTableName ) )
->set( 'parent_id', $q->bindValue( $parentId ) )
->set( 'id', $q->bindValue( $childNode->id ) )
- ->set( 'path', $q->bindValue( $path . '/' . $childNode->id ) );
+ ->set( 'path', $q->bindValue( $path .
$this->properties['separationChar'] . $childNode->id ) );
$s = $q->prepare();
$s->execute();
@@ -476,7 +584,7 @@
// Get path to parent of $nodeId
// - position of last /
- $pos = strrpos( $origPath, '/' );
+ $pos = strrpos( $origPath, $this->properties['separationChar'] );
// - parent path and its length
$parentPath = substr( $origPath, 0, $pos );
$parentPathLength = strlen( $parentPath ) + 1;
@@ -504,7 +612,7 @@
) )
->where( $q->expr->lOr(
$q->expr->eq( 'id', $q->bindValue( $nodeId ) ),
- $q->expr->like( 'path', $q->bindValue( "$origPath/%" ) )
+ $q->expr->like( 'path', $q->bindValue(
"$origPath{$this->properties['separationChar']}%" ) )
) );
$s = $q->prepare();
$s->execute();
Modified: trunk/TreeDatabaseTiein/src/backends/db_nested_set.php
==============================================================================
--- trunk/TreeDatabaseTiein/src/backends/db_nested_set.php [iso-8859-1]
(original)
+++ trunk/TreeDatabaseTiein/src/backends/db_nested_set.php [iso-8859-1] Fri Oct
5 17:16:45 2007
@@ -374,7 +374,7 @@
}
// Delete all data for the deleted nodes
- $nodeList = $this->fetchSubtree( $nodeId );
+ $nodeList = $this->fetchSubtreeDepthFirst( $nodeId );
$this->store->deleteDataForNodes( $nodeList );
// Fetch node information
Modified: trunk/TreeDatabaseTiein/tests/db_materialized_path_tree.php
==============================================================================
--- trunk/TreeDatabaseTiein/tests/db_materialized_path_tree.php [iso-8859-1]
(original)
+++ trunk/TreeDatabaseTiein/tests/db_materialized_path_tree.php [iso-8859-1]
Fri Oct 5 17:16:45 2007
@@ -73,6 +73,86 @@
return $tree;
}
+ public function testWithWrongSeparationChar()
+ {
+ $store = new ezcTreeDbExternalTableDataStore( $this->dbh, 'data',
'id', 'data' );
+ $tree = new ezcTreeDbMaterializedPath(
+ $this->dbh,
+ 'materialized_path',
+ $store,
+ '@'
+ );
+
+ $nodeList = $tree->fetchNodeById( 4 )->fetchSubtree();
+ self::assertSame( 1, $nodeList->size );
+ }
+
+ public function testCreateNodeWithInvalidId1()
+ {
+ $store = new ezcTreeDbExternalTableDataStore( $this->dbh, 'data',
'id', 'data' );
+ $tree = new ezcTreeDbMaterializedPath(
+ $this->dbh,
+ 'materialized_path',
+ $store,
+ '/'
+ );
+
+
+ try
+ {
+ $newNode = $tree->createNode( 'Is/This/Right', 'No' );
+ self::fail( 'Expected exception not thrown.' );
+ }
+ catch ( ezcTreeInvalidIdException $e )
+ {
+ self::assertSame( "The node ID 'Is/This/Right' contains the
invalid character '/'.", $e->getMessage() );
+ }
+ }
+
+ public function testCreateNodeWithInvalidId2()
+ {
+ $store = new ezcTreeDbExternalTableDataStore( $this->dbh, 'data',
'id', 'data' );
+ $tree = new ezcTreeDbMaterializedPath(
+ $this->dbh,
+ 'materialized_path',
+ $store,
+ '@'
+ );
+
+ try
+ {
+ $newNode = $tree->createNode( '[EMAIL PROTECTED]@Right', 'No' );
+ self::fail( 'Expected exception not thrown.' );
+ }
+ catch ( ezcTreeInvalidIdException $e )
+ {
+ self::assertSame( "The node ID '[EMAIL PROTECTED]@Right' contains
the invalid character '@'.", $e->getMessage() );
+ }
+ }
+
+ public function testSeparatingCharPropertyAccess()
+ {
+ $store = new ezcTreeDbExternalTableDataStore( $this->dbh, 'data',
'id', 'data' );
+ $tree = new ezcTreeDbMaterializedPath(
+ $this->dbh,
+ 'materialized_path',
+ $store,
+ '@'
+ );
+
+ self::assertSame( '@', $tree->separationChar );
+ self::assertSame( true, isset( $tree->separationChar ) );
+ try
+ {
+ $newNode = $tree->separationChar = '#';
+ self::fail( 'Expected exception not thrown.' );
+ }
+ catch ( ezcBasePropertyPermissionException $e )
+ {
+ self::assertSame( "The property 'separationChar' is read-only.",
$e->getMessage() );
+ }
+ }
+
public static function suite()
{
return new PHPUnit_Framework_TestSuite(
"ezcTreeDbMaterializedPathTest" );
Modified: trunk/TreeDatabaseTiein/tests/suite.php
==============================================================================
--- trunk/TreeDatabaseTiein/tests/suite.php [iso-8859-1] (original)
+++ trunk/TreeDatabaseTiein/tests/suite.php [iso-8859-1] Fri Oct 5 17:16:45
2007
@@ -13,6 +13,7 @@
*/
require_once 'Tree/tests/tree.php';
require_once 'db_materialized_path_tree.php';
+require_once 'db_materialized_path_tree_diff_separator.php';
require_once 'db_nested_set_tree.php';
require_once 'db_parent_child_tree.php';
require_once 'copy_tree.php';
@@ -30,6 +31,7 @@
$this->setName("TreeDatabaseTiein");
$this->addTest( ezcTreeDbMaterializedPathTest::suite() );
+ $this->addTest(
ezcTreeDbMaterializedPathTestWithDifferentSeparator::suite() );
$this->addTest( ezcTreeDbNestedSetTest::suite() );
$this->addTest( ezcTreeDbParentChildTest::suite() );
$this->addTest( ezcTreeDbCopyTest::suite() );
--
svn-components mailing list
[email protected]
http://lists.ez.no/mailman/listinfo/svn-components