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.
pgpSxHqHo7Zbd.pgp
Description: PGP signature
-- Components mailing list [email protected] http://lists.ez.no/mailman/listinfo/components
