There are cases when in many to many relationships you need additional data 
that is only relevant, when in the context of the m:n relation but in neither 
object context alone. Currently this is not possible in ezcComponents.

I have looked at the ezcPersistentSession and relation related source code and 
came to the conclusion that is not an easy task to integrate without looking 
somewhat hackish.

My first thought was to extend ezcPersistentSession::addRelatedOject to accept
a new parameter with the additional data to be saved in the relation table via 
an relation data object. This is a very bad solution, since you now have the 
problem of how to retrieve the addtional data, and how their representations 
is defined and can be accessed.

Then again, the data within m:n relation tables is only needed, when the 
relation is in full context, so i came up with a nicer solution that 
recognizes this relationsip: I would add a new 
ezcPersistentManyToManyDataRelation class that extends 
ezcPersistentManyToManyRelation. It has an additional property 
'manyToManyClass', which is a representation of the aggregated
data of destination and relation table.

"manyToManyClass" has to full fill a a state aggregation interface 
ezcPersistentObjectAggregate, that has to functions getStates() and 
setStates() which return arrays of setState() and getState() of the related 
objects where keys are unique definition table names '$def->table'. Internally 
then all resolutions between the different tables can be resolved by iterating
over the getStates() records and calling the appropriate means for each object 
state of the aggregate.

A note: Technically the relation table with data has no definition and hence 
the definition manager will fail to locate it.

Therefore many to many tables with data also have to have a definition file for 
this approach to work, also to define the fields that the relation table 
contains. A Definition has to exist for all the loader methods too. What 
information exactly this file should contain for my proposal to work i cant say 
for now, i'll have to build a prototype.

Any ideas and/or comments? This is by far no issue i have thought to the end, 
so in questions of detail my proposal might utterly fail. :-)

beberlei

Attachment: Some Use cases of using my proposed relation:

For a simple example in the ezcPersistentObject Tutorial context. Now 
'persons_addresses' contains additional data on how long this person is 
already registered at this address:

1. definition

$def->relations["Address"] = new ezcPersistentManyToManyDataRelation(
    "persons",
    "addresses",
    "persons_addresses"
);
$def->relations["Address"]->columnMap = array(
    new ezcPersistentDoubleTableMap( "id", "person_id", "address_id", "id" )
); 
$def->relations["Address"]->manyToManyClass = "PersonAddress";

2. PersonAddress

class PersonAddress implements ezcPersistentObjectAggregate
{
    /**
     * @var Address
     */
    private $address;

    /**
     * @var array
     */
    private $persons_addresses;

    public function getStates()
    {
        return array(
            'persons_addresses' => $this->persons_addresses,
            'addresses' => $this->address->getState();
        );
    }

    public function setStates(array $states)
    {
        foreach($states AS $table => $state) {
            switch($state) {
                case 'addresses':
                    $this->address = new Address();
                    $this->address->setState($state);
                    break;
                case 'persons_addresses':
                    $this->persons_addresses = $state;
                    break;
            }
        }
    }

    public function setRegisterDate($date)
    {
        $this->persons_addresses['register_date'] = $date;
    }
}

3 Use Case:

$person = $session->load('Person', 1);
$addresses = $person->getRelatedObjects();

foreach($addresses AS $address) {
    // now $address instanceof PersonAddress:
    $address->setRegisterDate(mktime(0, 0, 0, 5, 1, 2007));

    // session recognizes aggregation interface, iterates over the states
    $session->update($address);
}
-- 
Benjamin Eberlei
http://www.beberlei.de
-- 
Components mailing list
Components@lists.ez.no
http://lists.ez.no/mailman/listinfo/components

Reply via email to