Hello everybody,

Proposing an additionnal feature.

-- 
James Pic
GPG Key : 13185F50x8 / AEE2 CC15 8FF8 339C 23AC  5A91 491B 1638 1318 5F58
Downloadable on http://jamespic.com/pubkey.asc
Feature proposal for PO 1.4
===========================

Introduction
------------

This is a proposal for a new feature, in addition to Tobias Schlitt
proposal.

It's logic for a $person persistent-object's to have it's address 
accessible from property $person->address, or $person->addresses.
It is most likely how we implement relations in our persistent objects.

The relation Address is currently not mappable in Person's persistency
definition, which makes it impossible to make $person with
$person->address at once for the persistent session.

The need
--------

It's quiet repetitive to make a full set of methods to load and prepare
persistent-objects with the desired related-objects. For saving as 
well.

It's quiet a serious challenge to make a generic Session extension
with methods to directly load an object and it's related objects at
once. For saving as well.

To make this possible, these related objects must be mapped in the 
parent persistent-object definition.

Extending relations definition
------------------------------

Relations should have a propertyName.

Example ::

    $def->relations['myclass']->propertyName = 'myclass';

Or ::

    $def->relations['myclass']->propertyName = 'myclasses';

This way, the session can read the definition and access the 
nested objects itself.
"This way it is possible to use the propertyName to specify the exact 
relation you want to fetch if there are more than one." - as well.

Implementation
^^^^^^^^^^^^^^

I noticed that it's really simple to add propertyName to relations :
- add the new key to ezcPersistentRelation::$properties
- add the new case to the first set of cases in ezcPersistentRelation::__set()

Objective : new features
------------------------

This would allow introducing some new features::

    ezcPersistentSession::recursiveSave( object $object, 
PersistentObjectIterator $iterator );
    ezcPersistentSession::fetchComplete( string $className, $id, 
PersistentObjectIterator $iterator );

Implementation
^^^^^^^^^^^^^^

The two new methods should iterate throw related objects, identified by
their relation's propertyName.

Both require an iterator object, it should be used to
iterate through object's related object-properties, identified by the
relation's propertyName.
User's could configure it before it's used by the method.
Note that such an iterator can be useful for other purposes involving
other CRUD actions.

The default behavior of the iterator is a complete recursive iteration
through object's related-object-properties.

ezcPersistentSession::fetchComplete() should do *one* query.
ezcPersistentSession::recursiveSave() can be called once the application's
output is sent, therefore it's fine to do one-query-per-object.

PersistentObjectIterator
------------------------

The iteractor class should allow to recursively parse models - using 
relation's propertyName.
It should be configurable by code :
- use a specified depth,
- using relation propertyNames in whitelist or blacklist.

Implementation
^^^^^^^^^^^^^^

It should have the following public methods ::

    PersistentObjectIterator::setDepth( int $depth );
    PersistentObjectIterator::unsetDepth();
    PersistentObjectIterator::setWhiteList( array $whitelist );
    PersistentObjectIterator::setBlackList( array $blacklist );

If the iterator object has no depth explicitely set, the recursive
iterator should iterate through all recursive relations.

unsetDepth() allows to roll-back the iterator to the behavior explained
just above.

I propose two implementations of the blacklist and whitelist :

Array
    It's possible to set an array of relation-property-names and use it as
    a whitelist or blacklist.
    However, it would force each relation to have a globally-unique 
    propertyName.
Associative array
    To allow relation's propertyName to be unique per-object, it's better
    to use an array( className => relationPropertyName ).
OO
    Implementing a list interface PersistentRelationList will allow easier 
    testing. Blacklist and Whitelist are objects implementing tho interface,
    allowing to clearly identify each relation in the list.

Example
^^^^^^^

In a previous project, i wrote a ModelIterator_ to use with a 
PersistentSessionOverload_.

Note that in this example, models aren't using ::
    $def->relations['name']->propertyName = $propertyName
but instead ::
    $def->relationsMap['name'] = $propertyName

Also note that the iterator is only able of making a complete recursive 
iteration, not fully-featured.
I was speeded by deadlines when i coded this, so it's pretty nasty and 
i'm not exposing it with proud, but one can use it for inspiration or to 
sharpen understanding of the proposal.

.. _ModelIterator: 
http://devangels.org/trac/browser/tags/cornershop/models/cbMvcFlatIterator.php
.. _PersistentSessionOverload: 
http://devangels.org/trac/browser/tags/cornershop/overloaded/persistent_session.php

Special considerations
----------------------

Relation's propertyName is required to implement AnotherPOClassGenerator_
i wrote.
It uses AnotherPOClassGeneratorTemplate_ to generate the class, and 
AnotherPOClassGeneratorTestTemplate_ to generate the class test for PHPUnit_.
It's pretty reliable because i hacked PODSTSuite_ in order to run the 
generated test.

Most of the work is done, though it's not totally implemented, the generated
test is totally hacky - i should even add a definition handler.

You can have a look at AnotherPOClassGeneratorTestDefinition_ or even
AnotherPOClassGeneratorTestDbSchema_, which are used in the tests to produce
AnotherPOClassGeneratorClassExample_ and 
AnotherPOClassGeneratorClassTestExample_.

.. _AnotherPOClassGenerator: 
http://devangels.org/trac/browser/trunk/PersistentObjectDatabaseSchemaTiein
.. _AnotherPOClassGeneratorClassExample: 
http://devangels.org/trac/browser/trunk/widgetClass.php
.. _AnotherPOClassGeneratorClassTestExample: 
http://devangels.org/trac/browser/trunk/widgetClassTest.php
.. _AnotherPOClassGeneratorTemplate: 
http://devangels.org/trac/browser/trunk/PersistentObjectDatabaseSchemaTiein/src/class_template.php
.. _AnotherPOClassGeneratorTestDefinition: 
http://devangels.org/trac/browser/trunk/PersistentObjectDatabaseSchemaTiein/tests/data/new_generator_full_definition.php
.. _AnotherPOClassGeneratorTestTemplate: 
http://devangels.org/trac/browser/trunk/PersistentObjectDatabaseSchemaTiein/src/class_test_template.php
.. _AnotherPOClassGeneratorTestDbSchema: 
http://devangels.org/trac/browser/trunk/PersistentObjectDatabaseSchemaTiein/tests/data/new_generator_test_full_dbschema.php
.. _PODSTSuite: 
http://devangels.org/trac/browser/trunk/PersistentObjectDatabaseSchemaTiein/tests/suite.php
.. _PHPUnit: http://phpunit.de

Thanks
------

Tobias Schlitt's help was critical to produce this document.

Attachment: pgpSxHqHo7Zbd.pgp
Description: PGP signature

-- 
Components mailing list
[email protected]
http://lists.ez.no/mailman/listinfo/components

Reply via email to