neat-php / object

Neat Object components
MIT License
4 stars 1 forks source link

Relation reference builder configuration #32

Closed annavanbiemen closed 3 years ago

annavanbiemen commented 4 years ago

Currently there is some support for building custom relations and references, but it lacks

Some attempts at building a custom relation failed misserably:

    // This one only seems able to read the relation, not store it
    public function parameter(): Relations\Many
    {
        /** @var Relations\Many $relation */
        $relation = $this->relations()->get('hasManyParameter', function () {
            $key = new RemoteKey(
                new NeatProperty(new \ReflectionProperty(self::class, 'id')),
                new NeatProperty(new \ReflectionProperty(PropertyOptionParameter::class, 'optionId')),
                'option_id',
                PropertyOptionParameter::repository()
            );

            return new Relations\Many($key, $this);
        });
    }

    // This one doesn't work either
    public function parameter(): Relations\Many
    {
        return $this->buildHasMany(PropertyOptionParameter::class, 'hasManyParameter')
            ->referenceFactory(function (\Neat\Object\Relations\Reference\RemoteKeyBuilder $builder) {
                $builder->property(PropertyOptionParameter::class, 'optionId');
            })
            ->resolve();
    }
annavanbiemen commented 4 years ago

The tests do contain an example however: https://github.com/neat-php/object/blob/master/tests/Helper/Article.php

annavanbiemen commented 3 years ago

Branch feature/reference-builder-configuration contains a possible solution.

It can be used like this:


    public function creator(): Relations\One
    {
        return $this->belongsToOne(User::class, __FUNCTION__, function (LocalKeyBuilder $builder) {
            $builder->setLocalKey('createdBy');
        });
    }

It promotes using this way of configuring the reference builder by deprecating the build*() methods in the Relations trait and ReferenceFactory trait. It also deprecates the RelationBuilder->referenceFactory() method.

It also adds clear and consistent methods to configure each reference type:

Setting the local key or remote key as property now also automatically sets the corresponding key column. It also works the other way around: setting a key column, sets the corresponding property.

Also in this branch: By supplying a $role parameter (__FUNCTION__ may be used here) you can have multiple references of the same type to the same remote class. Without this $role parameter, this would be problematic because of caching issues.

The branch still lacks documentation and tests.

Out of scope because of backward compatibility are:

annavanbiemen commented 3 years ago

This is how the earlier example from my first comment in this ticket would be written:

    public function parameter(): Relations\Many
    {
        return $this->hasMany(PropertyOptionParameter::class, __FUNCTION__, function (RemoteKeyBuilder $builder) {
            $builder->setRemoteKey('optionId');
        });
    }

Using the column name should yield the same result:

    public function parameter(): Relations\Many
    {
        return $this->hasMany(PropertyOptionParameter::class, __FUNCTION__, function (RemoteKeyBuilder $builder) {
            $builder->setRemoteKeyColumn('option_id');
        });
    }

You might prefer using property names over column names since an ORM allows you to distance yourself from the storage layer.