Hello everyone, I am a big fan of how hibernate works, and it completly seperates the business logic from handling relations by using lazyload proxies for collections, objects and even large fields (BLOB). I'll propose an extension of PO and hope for many opinions and comments, although this mail is rather lengthy and technical :( Please don't skip over the pros and cons at the end, which are giving several angles on the issue.
Currently PO handles relations explicitly. Related objects have to be loaded by an explicit call to getRelatedObjects() to be retrieved. But this mechanism could be done behind the scenes easily via a lazy loading mechanism. Suppose for each relation of a persistent object you define a propertyName in which the lazy load object is injected. To be in the example of the ezcPo Tutorial, we define the relation of the 'Person' class to the 'Address' as: $def->relations["Address"] = new ezcPersistentOneToManyRelation( "persons", "addresses" ); $def->relations['Address']->lazyLoadProperty = 'address'; $def->relations["Address"]->columnMap = array( new ezcPersistentSingleTableMap( "id", "person_id" ) ); Now what would the LoadHandler do upon instantiating an object of Type 'Person'? It would recognize that there is a lazy load relation and would inject into $person->setState() a field with the following contents: $po = new SomePersistentObject(); $fields = array(); ... $callback = array($persistenceSession, 'getRelatedObjects'); $args = array($po, 'Address'); $fields['address'] = new ezcPersistentLazyLoadCollection($callback, $args); The LazyLoad Collection implements ArrayAccess, Countable and Iterator and upon the first access of any data of this collection triggers the lazy load via the hidden callback and then unsets the callback. This could also be done for n:1 or 1:1 relations witih a ezcPersistentLazyLoadObject class, which proxies all __get, __set, __call and other magic methods to the "real" object which is lazy loaded on the first call of any of the methods. Prerequisites are: * Identity Map is a requirement, since otherwise you could trigger loading of lots of identical objects, whithout even recognizing. The benefits of this handling would be: 1.) handling of relations is completly internal and a user can focus inside the model and a persistent object on the business logic without having to worry about missing relations, which is a very nice :-) 2.) Also this allows to create views of persistent objects, which have to use very many information of their related objects to be implementable by the frontend guys without them having to go back into the model and add the explicit loading of the relation. Personally i used this already to generate highly connected views with hyperlinks back and forth to any related object a PO might have. Business applications require lots of connections between the entities anyways so that the clients get to relevant information quickly and this way its easy to setup. Problems with LazyLoading are: 1.) SQL is executed behind the scenes, which might cause serious performance overhead if the lazy loading is "abused". 2.) Additionally Race conditions can occour, the n+1 sql query problem might hit hard. But this is currently the case also, when using getRelatedObjects explizitly. This can only be solved by implementing the possibility of using AssociationTable Loaders to load objects of several different types with a join query and construct them correctly, which is outside the scope of this proposal, but surely a nice to have for PO also. 3.) The example uses getRelatedObjects. The problem with this is, that you have to pass the entity object itsself to the callback. Maybe the use of a find query object is more nice in this context. 4.) Adding relations via getState()/setState() is a serious BC of PO, since its only handling properties now, also other things come up, when getState() may return a relation-property, how is it handled? are cascading save or delete options added or not? I have already implemented this in a prototype i use for work, based upon the Zend Framework, its a huge project and i can't even say i ever gonna finish it, I would rather contribute all that nice functinoality to ezcPo, since its already in such a good shape for all the required handling. If anyone is interested, the prototype is here: http://github.com/beberlei/data-mapper-proposal-prototype/ The current Lazy Load collections is located here: http://github.com/beberlei/data-mapper-proposal- prototype/blob/ba5e66c2037f6aadd04d5152c66190fbfbde2b58/library/WW/Entity/Mapper/LazyLoad/Collection.php The lazy load object proxy is located here: http://github.com/beberlei/data-mapper-proposal- prototype/blob/ba5e66c2037f6aadd04d5152c66190fbfbde2b58/library/WW/Entity/Mapper/LazyLoad/Entity.php A testcase that shows lazy load in action is: http://github.com/beberlei/data-mapper-proposal- prototype/blob/ba5e66c2037f6aadd04d5152c66190fbfbde2b58/tests/WW/Entity/ScenarioData/Clinic/ScenarioTest.php greetings, Benjamin -- Benjamin Eberlei http://www.beberlei.de -- Components mailing list Components@lists.ez.no http://lists.ez.no/mailman/listinfo/components