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