Author: ts
Date: Fri Jan 11 15:21:55 2008
New Revision: 7127

Log:
- Code cleanups and restructuring.
- Finished task #12287: ezcPersistentSession refactoring.

Modified:
    trunk/PersistentObject/src/handlers/delete_handler.php
    trunk/PersistentObject/src/handlers/load_handler.php
    trunk/PersistentObject/src/handlers/save_handler.php

Modified: trunk/PersistentObject/src/handlers/delete_handler.php
==============================================================================
--- trunk/PersistentObject/src/handlers/delete_handler.php [iso-8859-1] 
(original)
+++ trunk/PersistentObject/src/handlers/delete_handler.php [iso-8859-1] Fri Jan 
11 15:21:55 2008
@@ -49,24 +49,24 @@
      */
     public function delete( $object )
     {
-        $class = get_class( $object );
-        $def = $this->definitionManager->fetchDefinition( $class ); // 
propagate exception
-        $state = $this->session->getObjectState( $object );
+        $class   = get_class( $object );
+        $def     = $this->definitionManager->fetchDefinition( $class );
+        $state   = $this->session->getObjectState( $object );
         $idValue = $state[$def->idProperty->propertyName];
 
-        // check that the object is persistent already
+        // Check that the object is persistent already.
+        // The < 0 check results from the times where only numeric IDs were 
allowed.
         if ( $idValue == null || $idValue < 0 )
         {
-            $class = get_class( $object );
             throw new ezcPersistentObjectNotPersistentException( $class );
         }
 
-        // Transaction savety for exceptions thrown while cascading
+        // Transaction safety for exceptions thrown while cascading.
         $this->database->beginTransaction();
 
         try
         {
-            // check for cascading relations to follow
+            // Check for cascading relations to follow.
             foreach ( $def->relations as $relatedClass => $relation )
             {
                 $this->cascadeDelete( $object, $relatedClass, $relation );
@@ -74,20 +74,26 @@
         }
         catch ( Exception $e )
         {
-            // Roll back the current transaction on any exception
+            // Roll back the current transaction on any exception.
             $this->database->rollback();
             throw $e;
         }
 
-        // create and execute query
+        // Create and execute query.
         $q = $this->database->createDeleteQuery();
-        $q->deleteFrom( $this->database->quoteIdentifier( $def->table ) )
-            ->where( $q->expr->eq( $this->database->quoteIdentifier( 
$def->idProperty->columnName ),
-                                   $q->bindValue( $idValue ) ) );
+        $q->deleteFrom( 
+            $this->database->quoteIdentifier( $def->table )
+          )
+          ->where(
+            $q->expr->eq(
+                $this->database->quoteIdentifier( $def->idProperty->columnName 
),
+                $q->bindValue( $idValue )
+            ) 
+        );
 
         try
         {
-            $this->session->performQuery( $q, true );
+            $this->session->performQuery( $q );
         }
         catch ( Exception $e )
         {
@@ -119,11 +125,12 @@
      */
     public function removeRelatedObject( $object, $relatedObject )
     {
-        $class = get_class( $object );
-        $def = $this->definitionManager->fetchDefinition( ( $class = 
get_class( $object ) ) );
-
+        $class        = get_class( $object );
         $relatedClass = get_class( $relatedObject );
-
+        $def          = $this->definitionManager->fetchDefinition( $class );
+        $relatedDef = $this->definitionManager->fetchDefinition( get_class( 
$relatedObject ) );
+
+        // Sanity checks.
         if ( !isset( $def->relations[$relatedClass] ) )
         {
             throw new ezcPersistentRelationNotFoundException( $class, 
$relatedClass );
@@ -138,32 +145,47 @@
             );
         }
 
-        $objectState = $this->session->getObjectState( $object );
+        $objectState        = $this->session->getObjectState( $object );
         $relatedObjectState = $this->session->getObjectState( $relatedObject );
 
-        $relatedDef = $this->definitionManager->fetchDefinition( get_class( 
$relatedObject ) );
         switch ( get_class( ( $relation = $def->relations[get_class( 
$relatedObject )] ) ) )
         {
             case "ezcPersistentOneToManyRelation":
             case "ezcPersistentOneToOneRelation":
                 foreach ( $relation->columnMap as $map )
                 {
-                    
$relatedObjectState[$relatedDef->columns[$map->destinationColumn]->propertyName]
 = null;
+                    $relatedObjectState[
+                        
$relatedDef->columns[$map->destinationColumn]->propertyName
+                    ] = null;
                 }
                 break;
             case "ezcPersistentManyToManyRelation":
                 $q = $this->database->createDeleteQuery();
-                $q->deleteFrom( $this->database->quoteIdentifier( 
$relation->relationTable ) );
+                $q->deleteFrom(
+                    $this->database->quoteIdentifier( $relation->relationTable 
)
+                );
                 foreach ( $relation->columnMap as $map )
                 {
                     $q->where(
                         $q->expr->eq(
-                            $this->database->quoteIdentifier( 
$map->relationSourceColumn ),
-                            $q->bindValue( 
$objectState[$def->columns[$map->sourceColumn]->propertyName] )
+                            $this->database->quoteIdentifier(
+                                $map->relationSourceColumn
+                            ),
+                            $q->bindValue(
+                                $objectState[
+                                    
$def->columns[$map->sourceColumn]->propertyName
+                                ]
+                            )
                         ),
                         $q->expr->eq(
-                            $this->database->quoteIdentifier( 
$map->relationDestinationColumn ),
-                            $q->bindValue( 
$relatedObjectState[$relatedDef->columns[$map->destinationColumn]->propertyName]
 )
+                            $this->database->quoteIdentifier(
+                                $map->relationDestinationColumn
+                            ),
+                            $q->bindValue(
+                                $relatedObjectState[
+                                    
$relatedDef->columns[$map->destinationColumn]->propertyName
+                                ] 
+                            )
                         )
                     );
                 }
@@ -218,9 +240,8 @@
      */
     public function createDeleteQuery( $class )
     {
-        $def = $this->definitionManager->fetchDefinition( $class ); // 
propagate exception
-
-        // init query
+        $def = $this->definitionManager->fetchDefinition( $class );
+
         $q = $this->database->createDeleteQuery();
         $q->setAliases( $this->session->generateAliasMap( $def, false ) );
         $q->deleteFrom( $this->database->quoteIdentifier( $def->table ) );
@@ -248,9 +269,13 @@
         // Remove relation records for ManyToMany relations
         if ( $relation instanceof ezcPersistentManyToManyRelation )
         {
-            foreach ( $this->session->loadHandler->getRelatedObjects( $object, 
$relatedClass ) as $relatedObject )
+            $relatedObjects = $this->session->loadHandler->getRelatedObjects(
+                $object,
+                $relatedClass
+            );
+            foreach ( $relatedObjects as $relatedObject )
             {
-                // Need to determine the correct direction for removal
+                // Determine the correct direction for removal.
                 if ( $relation->reverse === true  )
                 {
                     $this->removeRelatedObject( $relatedObject, $object );
@@ -261,8 +286,12 @@
                 }
             }
         }
+
+        // Actually remove related objects
         if ( isset( $relation->cascade ) && $relation->cascade === true )
         {
+            // Reverse relations never cascade
+            // @todo: Is this correct? Or do we need to cascade reverse here?
             if ( isset( $relation->reverse ) && $relation->reverse === true )
             {
                 throw new ezcPersistentRelationOperationNotSupported(
@@ -272,7 +301,11 @@
                     "Reverse relations do not support cascading."
                 );
             }
-            foreach ( $this->session->loadHandler->getRelatedObjects( $object, 
$relatedClass ) as $relatedObject )
+            $relatedObjects = $this->session->loadHandler->getRelatedObjects(
+                $object,
+                $relatedClass
+            );
+            foreach ( $relatedObjects as $relatedObject )
             {
                 $this->delete( $relatedObject );
             }

Modified: trunk/PersistentObject/src/handlers/load_handler.php
==============================================================================
--- trunk/PersistentObject/src/handlers/load_handler.php [iso-8859-1] (original)
+++ trunk/PersistentObject/src/handlers/load_handler.php [iso-8859-1] Fri Jan 
11 15:21:55 2008
@@ -35,9 +35,11 @@
      */
     public function load( $class, $id )
     {
-        $def = $this->definitionManager->fetchDefinition( $class ); // 
propagate exception
+        $def    = $this->definitionManager->fetchDefinition( $class );
         $object = new $def->class;
+
         $this->loadIntoObject( $object, $id );
+
         return $object;
     }
 
@@ -61,7 +63,7 @@
         }
         catch ( Exception $e )
         {
-            // eat, we return null on error
+            // Eat, we return null on error.
         }
         return $result;
     }
@@ -84,19 +86,32 @@
      */
     public function loadIntoObject( $object, $id )
     {
-        $def = $this->definitionManager->fetchDefinition( get_class( $object ) 
); // propagate exception
+        $def = $this->definitionManager->fetchDefinition(
+            get_class( $object ) 
+        );
+
+        // Prepare query.
         $q = $this->database->createSelectQuery();
-        $q->select( $this->session->getColumnsFromDefinition( $def ) )
-            ->from( $this->database->quoteIdentifier( $def->table ) )
-            ->where( $q->expr->eq( $this->database->quoteIdentifier( 
$def->idProperty->columnName ),
-                                   $q->bindValue( $id ) ) );
-
+        $q->select(
+            $this->session->getColumnsFromDefinition( $def )
+        )->from(
+            $this->database->quoteIdentifier( $def->table )
+        )->where(
+            $q->expr->eq(
+                $this->database->quoteIdentifier( $def->idProperty->columnName 
),
+                $q->bindValue( $id )
+            )
+        );
+
+        // Execute and fetch rows.
         $stmt = $this->session->performQuery( $q );
         $row  = $stmt->fetch( PDO::FETCH_ASSOC );
         $stmt->closeCursor();
-        if ( $row !== false ) // we got a result
-        {
-            // we could check if there was more than one result here
+
+        // Convert result into object.
+        if ( $row !== false )
+        {
+            // We could check if there was more than one result here
             // but we don't because of the overhead and since the Persistent
             // Object would be faulty by design in that case and the user 
would have
             // to execute custom code to get into an invalid state.
@@ -119,7 +134,9 @@
         else
         {
             $class = get_class( $object );
-            throw new ezcPersistentQueryException( "No object of class 
'$class' with id '$id'." );
+            throw new ezcPersistentQueryException(
+                "No object of class '$class' with id '$id'."
+            );
         }
     }
 
@@ -141,16 +158,17 @@
      */
     public function refresh( $object )
     {
-        $def = $this->definitionManager->fetchDefinition( get_class( $object ) 
); // propagate exception
-        $state = $this->session->getObjectState( $object );
+        $class   = get_class( $object );
+        $def     = $this->definitionManager->fetchDefinition( $class );
+        $state   = $this->session->getObjectState( $object );
         $idValue = $state[$def->idProperty->propertyName];
+        
         if ( $idValue !== null )
         {
             $this->loadIntoObject( $object, $idValue );
         }
         else
         {
-            $class = get_class( $object );
             throw new ezcPersistentObjectNotPersistentException( $class );
         }
     }
@@ -194,11 +212,12 @@
      */
     public function find( ezcQuerySelect $query, $class )
     {
-        $def = $this->definitionManager->fetchDefinition( $class ); // 
propagate exception
-
-        $rows = $this->session->performQuery( $query )->fetchAll( 
PDO::FETCH_ASSOC );
-
-        // convert all the rows states and then objects
+        $def = $this->definitionManager->fetchDefinition( $class );
+
+        $rows = $this->session->performQuery( $query )
+            ->fetchAll( PDO::FETCH_ASSOC );
+
+        // Convert all the rows to states and then to objects.
         $result = array();
         foreach ( $rows as $row )
         {
@@ -238,7 +257,7 @@
      */
     public function findIterator( ezcQuerySelect $query, $class )
     {
-        $def  = $this->definitionManager->fetchDefinition( $class ); // 
propagate exception
+        $def  = $this->definitionManager->fetchDefinition( $class );
         $stmt = $this->session->performQuery( $query );
         return new ezcPersistentFindIterator( $stmt, $def );
     }
@@ -321,7 +340,10 @@
         $resArr = $this->find( $query, $relatedClass );
         if ( sizeof( $resArr ) < 1 )
         {
-            throw new ezcPersistentRelatedObjectNotFoundException( $object, 
$relatedClass );
+            throw new ezcPersistentRelatedObjectNotFoundException(
+                $object,
+                $relatedClass
+            );
         }
         return $resArr[0];
     }
@@ -348,13 +370,17 @@
      */
     public function createFindQuery( $class )
     {
-        $def = $this->definitionManager->fetchDefinition( $class ); // 
propagate exception
-
-        // init query
+        $def = $this->definitionManager->fetchDefinition( $class );
+
+        // Init query
         $q = $this->database->createSelectQuery();
         $q->setAliases( $this->session->generateAliasMap( $def ) );
-        $q->select( $this->session->getColumnsFromDefinition( $def ) )
-            ->from( $this->database->quoteIdentifier( $def->table ) );
+
+        $q->select(
+            $this->session->getColumnsFromDefinition( $def )
+        )->from(
+            $this->database->quoteIdentifier( $def->table )
+        );
 
         return $q;
     }
@@ -377,15 +403,18 @@
      */
     public function createRelationFindQuery( $object, $relatedClass )
     {
-        $def = $this->definitionManager->fetchDefinition( ( $class = 
get_class( $object ) ) );
+        $class = get_class( $object );
+        $def   = $this->definitionManager->fetchDefinition( $class );
+
         if ( !isset( $def->relations[$relatedClass] ) )
         {
-            throw new ezcPersistentRelationNotFoundException( $class, 
$relatedClass );
-        }
-        $relation = $def->relations[$relatedClass];
-
-        $query = $this->createFindQuery( $relatedClass );
-
+            throw new ezcPersistentRelationNotFoundException(
+                $class,
+                $relatedClass
+            );
+        }
+        $relation    = $def->relations[$relatedClass];
+        $query       = $this->createFindQuery( $relatedClass );
         $objectState = $this->session->getObjectState( $object );
 
         switch ( ( $relationClass = get_class( $relation ) ) )
@@ -393,37 +422,100 @@
             case "ezcPersistentOneToManyRelation":
             case "ezcPersistentManyToOneRelation":
             case "ezcPersistentOneToOneRelation":
-                foreach ( $relation->columnMap as $map )
-                {
-                    $query->where(
-                        $query->expr->eq(
-                            $this->database->quoteIdentifier( 
"{$map->destinationColumn}" ),
-                            $query->bindValue( 
$objectState[$def->columns[$map->sourceColumn]->propertyName] )
-                        )
-                    );
-                }
+                $this->createSimpleRelationFindQuery( $query, $def, $relation, 
$objectState );
                 break;
             case "ezcPersistentManyToManyRelation":
-                $query->from( $this->database->quoteIdentifier( 
$relation->relationTable ) );
-                foreach ( $relation->columnMap as $map )
-                {
-                    $query->where(
-                        $query->expr->eq(
-                            $this->database->quoteIdentifier( 
$relation->relationTable ) . "." . $this->database->quoteIdentifier( 
$map->relationSourceColumn ),
-                            $query->bindValue( 
$objectState[$def->columns[$map->sourceColumn]->propertyName] )
-                        ),
-                        $query->expr->eq(
-                            $this->database->quoteIdentifier( 
$relation->relationTable ) . "." . $this->database->quoteIdentifier( 
$map->relationDestinationColumn ),
-                            $this->database->quoteIdentifier( 
$relation->destinationTable ) . "." . $this->database->quoteIdentifier( 
$map->destinationColumn )
-                        )
-                    );
-                }
+                $this->createComplexRelationFindQuery( $query, $def, 
$relation, $objectState );
                 break;
             default:
                 throw new ezcPersistentRelationInvalidException( 
$relationClass );
         }
         return $query;
     }
+
+    /**
+     * Sets find query value for simple related objects. 
+     *
+     * Manipulates the find $query for objects related to the object defined in
+     * $objectState, defined my the relation $relation. This method is
+     * responsile for
+     * <ul>
+     *     <li>[EMAIL PROTECTED] ezcPersistentOneToManyRelation}</li>
+     *     <li>[EMAIL PROTECTED] ezcPersistentOneToOneRelation}</li>
+     *     <li>[EMAIL PROTECTED] ezcPersistentManyToOneRelatio}n</li>
+     * </ul>
+     * for [EMAIL PROTECTED] ezcPersistentManyToManyRelation} see [EMAIL 
PROTECTED]
+     * createComplexRelationFindQuery()}.
+     * 
+     * @param ezcQuery $query 
+     * @param ezcPersistentRelation $relation 
+     * @param array $objectState 
+     */
+    private function createSimpleRelationFindQuery(
+        ezcQuery $query,
+        ezcPersistentObjectDefinition $def,
+        ezcPersistentRelation $relation,
+        array $objectState
+    )
+    {
+        foreach ( $relation->columnMap as $map )
+        {
+            $query->where(
+                $query->expr->eq(
+                    $this->database->quoteIdentifier(
+                        $map->destinationColumn
+                    ),
+                    $query->bindValue(
+                        
$objectState[$def->columns[$map->sourceColumn]->propertyName]
+                    )
+                )
+            );
+        }
+    }
+
+    /**
+     * Sets find query value for many-to-many related objects. 
+     *
+     * Manipulates the find $query for objects related to the object defined in
+     * $objectState, defined my the relation $relation.
+     * 
+     * @param ezcQuery $query 
+     * @param ezcPersistentManyToManyRelation $relation 
+     * @param array $objectState 
+     */
+    private function createComplexRelationFindQuery(
+        ezcQuery $query,
+        ezcPersistentObjectDefinition $def,
+        ezcPersistentManyToManyRelation $relation,
+        array $objectState
+    )
+    {
+        // Join with relation table.
+        $query->from(
+            $this->database->quoteIdentifier( $relation->relationTable )
+        );
+        foreach ( $relation->columnMap as $map )
+        {
+            $query->where(
+                $query->expr->eq(
+                    $this->database->quoteIdentifier( $relation->relationTable 
) 
+                        . "." 
+                        . $this->database->quoteIdentifier( 
$map->relationSourceColumn ),
+                    $query->bindValue(
+                        
$objectState[$def->columns[$map->sourceColumn]->propertyName]
+                    )
+                ),
+                $query->expr->eq(
+                    $this->database->quoteIdentifier( $relation->relationTable 
)
+                        . "." 
+                        . $this->database->quoteIdentifier( 
$map->relationDestinationColumn ),
+                    $this->database->quoteIdentifier( 
$relation->destinationTable )
+                        . "." 
+                        . $this->database->quoteIdentifier( 
$map->destinationColumn )
+                )
+            );
+        }
+    }
 }
 
 ?>

Modified: trunk/PersistentObject/src/handlers/save_handler.php
==============================================================================
--- trunk/PersistentObject/src/handlers/save_handler.php [iso-8859-1] (original)
+++ trunk/PersistentObject/src/handlers/save_handler.php [iso-8859-1] Fri Jan 
11 15:21:55 2008
@@ -21,9 +21,10 @@
 class ezcPersistentSaveHandler extends ezcPersistentSessionHandler
 {
     /**
-     * Saves the new persistent object $object to the database using an INSERT 
INTO query.
-     *
-     * The correct ID is set to $object.
+     * Saves a new persistent $object to the database using an INSERT query.
+     *
+     * The correct ID is set to $object after it has been saved, as described
+     * in its [EMAIL PROTECTED] ezcPersistentObjectDefinition}.
      *
      * @throws ezcPersistentObjectException if $object
      *         is not of a valid persistent object type.
@@ -33,7 +34,7 @@
      *         if it was not possible to generate a unique identifier for the
      *         new object.
      * @throws ezcPersistentObjectException
-     *         if the insert query failed.
+     *         if the INSERT query failed.
      *
      * @param object $object
      */
@@ -43,13 +44,19 @@
     }
 
     /**
-     * Saves the new persistent object $object to the database using an UPDATE 
query.
-     *
-     * @throws ezcPersistentDefinitionNotFoundException if $object is not of a 
valid persistent object type.
-     * @throws ezcPersistentObjectNotPersistentException if $object is not 
stored in the database already.
+     * Saves the persistent $object to the database using an UPDATE query.
+     *
+     * The object needs to have already a valid ID als described in its [EMAIL 
PROTECTED]
+     * ezcPersistentObjectDefinition}.
+     *
+     * @throws ezcPersistentDefinitionNotFoundException
+     *         if $object is not of a valid persistent object type.
+     * @throws ezcPersistentObjectNotPersistentException
+     *         if $object is not stored in the database already.
      * @throws ezcPersistentQueryException
+     *         if the UPDATE query fails.
+     *
      * @param object $object
-     * @return void
      */
     public function update( $object )
     {
@@ -76,18 +83,22 @@
      */
     public function saveOrUpdate( $object )
     {
-        $def = $this->definitionManager->fetchDefinition( get_class( $object ) 
);// propagate exception
+        $class = get_class( $object );
+        $def   = $this->definitionManager->fetchDefinition( $class );
         $state = $this->session->getObjectState( $object );
 
-        // fetch the id generator
+        // Fetch the id generator
         $idGenerator = null;
+        // @todo: Missing else part! Should throw exception!
         if ( ezcBaseFeatures::classExists( $def->idProperty->generator->class 
) )
         {
             $idGenerator = new $def->idProperty->generator->class;
             if ( !( $idGenerator instanceof ezcPersistentIdentifierGenerator ) 
)
             {
-                throw new ezcPersistentIdentifierGenerationException( 
get_class( $object ),
-                                                                      "Could 
not initialize identifier generator: ". "{$def->idProperty->generator->class} 
." );
+                throw new ezcPersistentIdentifierGenerationException( 
+                    $class,
+                    "Could not initialize identifier generator: 
{$def->idProperty->generator->class}."
+                );
             }
         }
 
@@ -122,67 +133,63 @@
      */
     public function addRelatedObject( $object, $relatedObject )
     {
-        $class = get_class( $object );
-        $def = $this->definitionManager->fetchDefinition( ( $class = 
get_class( $object ) ) );
-
+        $class        = get_class( $object );
         $relatedClass = get_class( $relatedObject );
-
-        $objectState = $this->session->getObjectState( $object );
+        $def          = $this->definitionManager->fetchDefinition( $class );
+
+        $objectState        = $this->session->getObjectState( $object );
         $relatedObjectState = $this->session->getObjectState( $relatedObject );
 
+        // Sanity checks.
         if ( !isset( $def->relations[$relatedClass] ) )
         {
-            throw new ezcPersistentRelationNotFoundException( $class, 
$relatedClass );
-        }
-        if ( isset( $def->relations[$relatedClass]->reverse ) && 
$def->relations[$relatedClass]->reverse === true )
+            throw new ezcPersistentRelationNotFoundException(
+                $class,
+                $relatedClass
+            );
+        }
+        if (
+            isset( $def->relations[$relatedClass]->reverse ) 
+            && $def->relations[$relatedClass]->reverse === true
+        )
         {
             throw new ezcPersistentRelationOperationNotSupportedException(
                 $class,
                 $relatedClass,
-                "addRelatedObject",
+                __FUNCTION__,
                 "Relation is a reverse relation."
             );
         }
 
-        $relatedDef = $this->definitionManager->fetchDefinition( get_class( 
$relatedObject ) );
-        switch ( get_class( ( $relation = $def->relations[get_class( 
$relatedObject )] ) ) )
+        $relatedDef = $this->definitionManager->fetchDefinition( $relatedClass 
);
+        $relation   = $def->relations[$relatedClass];
+
+        switch ( get_class( $relation ) )
         {
             case "ezcPersistentOneToManyRelation":
+            // Not needed, already caught by sanity checks:
+            // case "ezcPersistentManyToOneRelation":
             case "ezcPersistentOneToOneRelation":
                 foreach ( $relation->columnMap as $map )
                 {
-                    
$relatedObjectState[$relatedDef->columns[$map->destinationColumn]->propertyName]
 =
-                        
$objectState[$def->columns[$map->sourceColumn]->propertyName];
+                    $relatedObjectState[
+                        
$relatedDef->columns[$map->destinationColumn]->propertyName
+                    ] = $objectState[
+                        $def->columns[$map->sourceColumn]->propertyName
+                    ];
                 }
+                $relatedObject->setState( $relatedObjectState );
                 break;
             case "ezcPersistentManyToManyRelation":
-                $q = $this->database->createInsertQuery();
-                $q->insertInto( $this->database->quoteIdentifier( 
$relation->relationTable ) );
-                $insertColumns = array();
-                foreach ( $relation->columnMap as $map )
-                {
-                    if ( in_array( $map->relationSourceColumn, $insertColumns 
) === false )
-                    {
-                        $q->set(
-                            $this->database->quoteIdentifier( 
$map->relationSourceColumn ),
-                            $q->bindValue( 
$objectState[$def->columns[$map->sourceColumn]->propertyName] )
-                        );
-                        $insertColumns[] = $map->relationSourceColumn;
-                    }
-                    if ( in_array( $map->relationDestinationColumn, 
$insertColumns ) === false )
-                    {
-                        $q->set(
-                            $this->database->quoteIdentifier( 
$map->relationDestinationColumn ),
-                            $q->bindValue( 
$relatedObjectState[$relatedDef->columns[$map->destinationColumn]->propertyName]
 )
-                        );
-                        $insertColumns[] = $map->relationDestinationColumn;
-                    }
-                }
-                $this->session->performQuery( $q );
+                $this->insertRelationRecord(
+                    $relation,
+                    $def,
+                    $relatedDef,
+                    $objectState,
+                    $relatedObjectState
+                );
                 break;
         }
-
-        $relatedObject->setState( $relatedObjectState );
     }
 
     /**
@@ -200,9 +207,8 @@
      */
     public function createUpdateQuery( $class )
     {
-        $def = $this->definitionManager->fetchDefinition( $class ); // 
propagate exception
-
-        // init query
+        $def = $this->definitionManager->fetchDefinition( $class );
+
         $q = $this->database->createUpdateQuery();
         $q->setAliases( $this->session->generateAliasMap( $def, false ) );
         $q->update( $this->database->quoteIdentifier( $def->table ) );
@@ -246,54 +252,73 @@
      *         if it was not possible to generate a unique identifier for the
      *         new object.
      * @throws ezcPersistentObjectException
-     *         if the insert query failed.
+     *         if the INSERT query failed.
      *
      * @param object $object
      * @param bool $doPersistenceCheck
      * @param ezcPersistentIdentifierGenerator $idGenerator
      */
-    private function saveInternal( $object, $doPersistenceCheck = true,
-                                   ezcPersistentIdentifierGenerator 
$idGenerator = null )
-    {
-        $def = $this->definitionManager->fetchDefinition( get_class( $object ) 
);// propagate exception
-        $state = $this->filterAndCastState( $this->session->getObjectState( 
$object ), $def );
+    private function saveInternal(
+        $object,
+        $doPersistenceCheck = true,
+        ezcPersistentIdentifierGenerator $idGenerator = null 
+    )
+    {
+        $class = get_class( $object );
+        $def   = $this->definitionManager->fetchDefinition( $class );
+        $state = $this->filterAndCastState(
+            $this->session->getObjectState( $object ),
+            $def
+        );
         $idValue = $state[$def->idProperty->propertyName];
 
-        // fetch the id generator
-        if ( $idGenerator == null && ezcBaseFeatures::classExists( 
$def->idProperty->generator->class ) )
+        // Fetch the id generator.
+        if ( $idGenerator === null 
+             && ezcBaseFeatures::classExists( 
$def->idProperty->generator->class )
+        )
+        // @todo: Missing else part, should throw an exception!
         {
             $idGenerator = new $def->idProperty->generator->class;
             if ( !( $idGenerator instanceof ezcPersistentIdentifierGenerator ) 
)
             {
-                throw new ezcPersistentIdentifierGenerationException( 
get_class( $object ),
-                                                                      "Could 
not initialize identifier generator: ". "{$def->idProperty->generator->class} 
." );
-            }
-        }
-
-        if ( $doPersistenceCheck == true && $idGenerator->checkPersistence( 
$def, $this->database, $state ) )
-        {
-            $class = get_class( $object );
+                throw new ezcPersistentIdentifierGenerationException(
+                    $class,
+                    "Could not initialize identifier generator: 
{$def->idProperty->generator->class}."
+                );
+            }
+        }
+
+        if ( $doPersistenceCheck == true
+             && $idGenerator->checkPersistence( $def, $this->database, $state )
+        )
+        {
             throw new ezcPersistentObjectAlreadyPersistentException( $class );
         }
 
-
-        // set up and execute the query
+        // Set up and execute the query.
         $q = $this->database->createInsertQuery();
         $q->insertInto( $this->database->quoteIdentifier( $def->table ) );
         foreach ( $state as $name => $value )
         {
-            if ( $name != $def->idProperty->propertyName ) // skip the id field
-            {
-                // set each of the properties
-                $q->set( $this->database->quoteIdentifier( 
$def->properties[$name]->columnName ), $q->bindValue( $value ) );
-            }
-        }
-
+            if ( $name !== $def->idProperty->propertyName )
+            {
+                // Set each of the properties.
+                $q->set(
+                    $this->database->quoteIdentifier(
+                        $def->properties[$name]->columnName
+                    ), 
+                    $q->bindValue( $value )
+                );
+            }
+        }
+
+        // Atomic operation
         $this->database->beginTransaction();
-        // let presave id generator do its work
+        
+        // Let presave id generator do its work.
         $idGenerator->preSave( $def, $this->database, $q );
 
-        // execute the insert query
+        // Execute the insert query
         try
         {
             $this->session->performQuery( $q );
@@ -304,72 +329,94 @@
             throw $e;
         }
 
-        // fetch the newly created id, and set it to the object
+        // Fetch the newly created ID, and set it to the objects ID property.
         $id = $idGenerator->postSave( $def, $this->database );
         if ( $id === null )
         {
+            // Something must have went wrong, no ID generated.
             $this->database->rollback();
-            throw new ezcPersistentIdentifierGenerationException( $def->class 
);
-        }
-
-        // everything seems to be fine, lets commit the queries to the database
-        // and update the object with its newly created id.
+            throw new ezcPersistentIdentifierGenerationException( $class );
+        }
+
+        // Everything seems to be fine, lets commit the queries to the database
+        // and update the object with its newly created ID.
         $this->database->commit();
-
+        
         $state[$def->idProperty->propertyName] = $id;
         $object->setState( $state );
     }
 
     /**
-     * Saves the new persistent object $object to the database using an UPDATE 
query.
-     *
-     * If $doPersistenceCheck is set this function will check if the object is 
persistent before
-     * saving. If not, the check is omitted.
-     *
-     * @throws ezcPersistentDefinitionNotFoundException if $object is not of a 
valid persistent object type.
-     * @throws ezcPersistentObjectNotPersistentException if $object is not 
stored in the database already.
+     * Saves the new persistent $object to the database using an UPDATE query.
+     *
+     * If $doPersistenceCheck is set this function will check if the object is
+     * persistent before saving. If not, the check is omitted.
+     *
+     * @throws ezcPersistentDefinitionNotFoundException
+     *         if $object is not of a valid persistent object type.
+     * @throws ezcPersistentObjectNotPersistentException
+     *         if $object is not stored in the database already.
      * @throws ezcPersistentQueryException
+     *         if the UPDATE query failed.
+     *
      * @param object $object
      * @param bool $doPersistenceCheck
-     * @return void
      */
     private function updateInternal( $object, $doPersistenceCheck = true )
     {
-        $def = $this->definitionManager->fetchDefinition( get_class( $object ) 
); // propagate exception
-        $state = $this->filterAndCastState( $this->session->getObjectState( 
$object ), $def );
+        $class = get_class( $object );
+        $def   = $this->definitionManager->fetchDefinition( $class );
+        $state = $this->filterAndCastState(
+            $this->session->getObjectState( $object ),
+            $def
+        );
         $idValue = $state[$def->idProperty->propertyName];
 
-        // fetch the id generator
+        // Fetch the id generator
         $idGenerator = null;
         if ( ezcBaseFeatures::classExists( $def->idProperty->generator->class 
) )
         {
             $idGenerator = new $def->idProperty->generator->class;
             if ( !( $idGenerator instanceof ezcPersistentIdentifierGenerator ) 
)
             {
-                throw new ezcPersistentIdentifierGenerationException( 
get_class( $object ),
-                                                                      "Could 
not initialize identifier generator: ". "{$def->idProperty->generator->class} 
." );
-            }
-        }
-
-        if ( $doPersistenceCheck == true && !$idGenerator->checkPersistence( 
$def, $this->database, $state ) )
-        {
-            $class = get_class( $object );
-            throw new ezcPersistentObjectNotPersistentException( get_class( 
$object ) );
-        }
-
-        // set up and execute the query
+                throw new ezcPersistentIdentifierGenerationException(
+                    $class,
+                    "Could not initialize identifier generator: 
{$def->idProperty->generator->class}."
+                );
+            }
+        }
+
+        if ( $doPersistenceCheck == true
+             && !$idGenerator->checkPersistence( $def, $this->database, $state 
)
+        )
+        {
+            throw new ezcPersistentObjectNotPersistentException( $class );
+        }
+
+        // Set up and execute the query
         $q = $this->database->createUpdateQuery();
         $q->update( $this->database->quoteIdentifier( $def->table ) );
         foreach ( $state as $name => $value )
         {
-            if ( $name != $def->idProperty->propertyName ) // skip the id field
-            {
-                // set each of the properties
-                $q->set( $this->database->quoteIdentifier( 
$def->properties[$name]->columnName ), $q->bindValue( $value ) );
-            }
-        }
-        $q->where( $q->expr->eq( $this->database->quoteIdentifier( 
$def->idProperty->columnName ),
-                                 $q->bindValue( $idValue ) ) );
+            // Skip the id field.
+            if ( $name != $def->idProperty->propertyName )
+            {
+                // Set each of the properties.
+                $q->set(
+                    $this->database->quoteIdentifier(
+                        $def->properties[$name]->columnName ),
+                        $q->bindValue( $value )
+                    );
+            }
+        }
+        $q->where(
+            $q->expr->eq(
+                $this->database->quoteIdentifier(
+                    $def->idProperty->columnName
+                ),
+                $q->bindValue( $idValue )
+            )
+        );
 
         $this->session->performQuery( $q );
     }
@@ -388,15 +435,17 @@
         foreach ( $state as $name => $value )
         {
             $type = null;
-            if ( $name == $def->idProperty->propertyName )
+            if ( $name === $def->idProperty->propertyName )
             {
                 $type = $def->idProperty->propertyType;
+                // ID property has no conversion.
                 $conv = null;
             }
             else
             {
                 if ( !isset( $def->properties[$name] ) )
                 {
+                    // Unknown property
                     continue;
                 }
                 $type = $def->properties[$name]->propertyType;
@@ -405,10 +454,12 @@
 
             if ( !is_null( $value ) )
             {
+                // First convert back from complex type.
                 if ( !is_null( $conv ) )
                 {
                     $value = $conv->toDatabase( $value );
                 }
+                // Then cast simple type.
                 switch ( $type )
                 {
                     case ezcPersistentObjectProperty::PHP_TYPE_INT:
@@ -427,6 +478,60 @@
         }
         return $typedState;
     }
+
+    /**
+     * Inserts the relation record for a many-to-many relation.
+     * 
+     * @param ezcPersistentManyToManyRelation $relation 
+     * @param array $objectState 
+     * @param array $relatedObjectState 
+     */
+    private function insertRelationRecord(
+        ezcPersistentManyToManyRelation $relation,
+        ezcPersistentObjectDefinition $def,
+        ezcPersistentObjectDefinition $relatedDef,
+        array $objectState,
+        array $relatedObjectState
+    )
+    {
+        $q = $this->database->createInsertQuery();
+        $q->insertInto(
+            $this->database->quoteIdentifier( $relation->relationTable )
+        );
+        $insertColumns = array();
+        foreach ( $relation->columnMap as $map )
+        {
+            if ( !in_array( $map->relationSourceColumn, $insertColumns ) )
+            {
+                $q->set(
+                    $this->database->quoteIdentifier(
+                        $map->relationSourceColumn
+                    ),
+                    $q->bindValue(
+                        $objectState[
+                            $def->columns[$map->sourceColumn]->propertyName
+                        ]
+                    )
+                );
+                $insertColumns[] = $map->relationSourceColumn;
+            }
+            if ( !in_array( $map->relationDestinationColumn, $insertColumns ) )
+            {
+                $q->set(
+                    $this->database->quoteIdentifier(
+                        $map->relationDestinationColumn
+                    ),
+                    $q->bindValue(
+                        $relatedObjectState[
+                            
$relatedDef->columns[$map->destinationColumn]->propertyName
+                        ]
+                    )
+                );
+                $insertColumns[] = $map->relationDestinationColumn;
+            }
+        }
+        $this->session->performQuery( $q );
+    }
 }
 
 ?>


-- 
svn-components mailing list
svn-components@lists.ez.no
http://lists.ez.no/mailman/listinfo/svn-components

Reply via email to