eZ component: PersistentObject, Design, 1.4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :Author: Frederik Holljen :Revision: $Rev: 3576 $ :Date: $Date: 2006-09-25 13:44:15 +0400 (Mon, 25 Sep 2006) $ :Status: Draft .. contents:: Scope ===== The scope of this document is to describe the proposed enhancements for the PersistentObject component version 1.4. The general goal for this version is to implement various features described by these issues in our issue tracker: - #8963 [PersistentObject] Support for composite IDs - #10151 Improved Database and PersistentObject datatype support (especially #binary data) - #10373 Several relations to the same table for PersistentObject Each of the issues and their proposed solutions are explained in a seperate chapter in this document. Support for composite IDs (and composite properties in general) [#8963] ====================================================================== Note: This section is not finished. Please read the discussion on the bug to see if it will be implemented at all. Background ---------- Currently PersistentObject only supports single primary keys for the underlying database structure through the definition struct ezcPersistentObjectIdProperty. This proposal adds a mechanism to PersistentObject to support primary keys that consist of several table columns. TODO: Discuss difference between composite and multi column. We want multicolumn keys and composite properties. Split into one more task. Design ------ :: ezcPersistentObjectColumn { public $columnName; public $columnType; } ezcPersistentObjectIdProperty { // deprecated public $columnName; public $visibility; // ezcPersistentObjectColumn public $column; } ezcPersistentObjectMultiColumnId { // array of ezcPersistentObjectIdProperty public $ids;// Note: automatic text generator on the ids. // This is because any form of sequence // does not make sense. (Unless someone // can tell me otherwise and tell me how // to specify/implement that... :) } ezcPersistentCompositeProperty { // array of ezcPersistentObjectColumn public $columns; public $filter; // covered by different spec. public $propertyName; public $propertyType; } Required API changes: ezcPersistentIdentifierGenerator::postSave() if we want to use it to return the ids. (Like we do now) ezcPersistentSession::load( $class, $id ) since $id can now be composite ezcPersistentSession::loadIfExist( $class, $id ) since $id can now be composite ezcPersistentSession::loadIntoObject( $pObject, $id ) since $id can now be composite Open questions -------------- Improved datatype support (especially binary data) [#10151] =========================================================== Background ---------- PDO uses several different ways of binding parameters to queries. Currently these are: - PDO::PARAM_BOOL - PDO::PARAM_NULL - PDO::PARAM_INT - PDO::PARAM_LOB - PDO::PARAM_STR (default) - PDO::PARAM_INPUT_OUTPUT Currently unsported by PDO. Used for in/out parameters of a stored procedure. Currently only the default paramter PARAM_STR is supported by persistent object. This does not mean that you can not store integers and booleans as the database drivers will figure this out themselves. However, for some field types especially you are required to use parameters. An example of this is binary data which can contain '\0'. If you use the default parameter PDO::PARAM_STR the remaining data will simply be ignored since the end of the string has already been encountered. The support for PDO PARAM_ types was recently added to the Database component as a fix for issue `#010943`_. .. _`#010943`: http://issues.ez.no/IssueView.php?Id=10943 Design ------ The proposed solution is to add a columnType property for all definitions where a column is defined. The columnType can be one of the PDO PARAM_ type parameters and directly defines the parameter type provided to PDO when building the queries. This currently affects: - ezcPersistentObjectIdProperty - ezcPersistentObjectProperty Open questions -------------- It would be nice to make large binary data available as a resource both for writing and reading. PDO::PARAM_LOB can handle this if used together with PDO::FETCH_BOUND. Should we, and how do we make this available to the user? Write support will most probably work out of the box. If the value is a resource the whole file will be read automatically by PDO as long as PARAM_LOB is used. Should we use the PDO::PARAM_BOOL/INT by default? That is do we actually want to require to use this for anything else than PARAM_LOB since ints/bools etc. actually work fine already. What does using these parameters gain us. Several relations to the same table for PersistentObject [#10373] ================================================================= Background ---------- Since version 1.2 PersistentObject supports relations. The definition of a relation will typically look something like: :: $def->relations["Address"] = new ezcPersistentManyToManyRelation( "persons", "addresses", "persons_addresses" ); $def->relations["Address"]->columnMap = array( new ezcPersistentDoubleTableMap( "id", "person_id", "address_id", "id" ) ); The method to fetch a relation with this definition will typically look something like: :: // signature getRelatedObjects( object $relationObject, string $className ) $addresses = $session->getRelatedObjects( $person, "Address" ); Basically we can see that both the definition and the fetching of related objects is bound to the related class type. This means that a class can only have one relation type to another class. Usually this is sufficient. However, sometimes it is necessary to have more than one relation to the same class e.g. a Person class with the relations "mother" and "father" to the very same Person class. PersistentSession design ------------------------ The proposed solution is to add an optional name for relations. This way it is possible to use the name to specify the exact relation you want to fetch if there are more than one. All methods used to fetch and store relations will have the optional parameter appended to them. The affected methods and their new signatures are: :: ezcPersistentSession::getRelatedObject( object $object, string $className, string $relationName = null ) ezcPersistentSession::getRelatedObjects( object $object, string $className, string $relationName = null ) ezcPersistentSession::addRelatedObject( object $object, object $relationObject, string $relationName = null ); ezcPersistentSession::removeRelatedObject( object $object, object $relationObject, string $relationName = null ); The new parameter makes it possible to reach one new exceptional state: - ezcPersistentUnderministicRelationException is thrown when several relations to one class is defined but no relation name is used. Definition Design ----------------- Similar to the changes to PersistentSession we need to change the persistent object definition to store the relation name for classes that have more than one relation to another class. To do this we want to introduce a wrapper struct that can hold several named relations: :: class ezcPersistentRelationCollection { public $namedRelations = array(); } An implementation of the example with persons would then look something like: :: $personRelations = new ezcPersistentRelationCollection; $def->relations[Person] = $personRelations; $personRelations['mother'] = new ezcPersistentOneToOneRelation( "persons", "persons" ); $personRelations['mother']->columnMap = array( new ezcPersistentSingleTableMap( "id", "mother_id" ) ); $personRelations['father'] = new ezcPersistentOneToOneRelation( "persons", "persons" ); $personRelations['father']->columnMap = array( new ezcPersistentSingleTableMap( "id", "father_id" ) ); The changes do not break BC and require changes in PersistentSession to work. An extra if will have to be introduced to check for the existence of named relations. This will not harm performance in a significant way. .. Local Variables: mode: rst fill-column: 79 End: vim: et syn=rst tw=79