phramework / jsonapi

jsonapi implementation for phramework
https://phramework.github.io/jsonapi/
Apache License 2.0
4 stars 2 forks source link

Circular dependency issue #45

Closed nohponex closed 7 years ago

nohponex commented 7 years ago

When having a Article that has a tag relationships and a Tag model that has a article relationship like in https://github.com/phramework/jsonapi-example

[Tue Sep 27 22:58:17 2016] PHP 249. Phramework\JSONAPI\APP\Models\Article::defineModel() /var/www/phramework/jsonapi-client/vendor/phramework/jsonapi/src/Model.php:37
[Tue Sep 27 22:58:17 2016] PHP 250. Phramework\JSONAPI\Model::getResourceModel() /var/www/phramework/jsonapi-client/tests/APP/Models/Article.php:64
[Tue Sep 27 22:58:17 2016] PHP 251. Phramework\JSONAPI\APP\Models\Tag::defineModel() /var/www/phramework/jsonapi-client/vendor/phramework/jsonapi/src/Model.php:37
[Tue Sep 27 22:58:17 2016] PHP 252. Phramework\JSONAPI\Model::getResourceModel() /var/www/phramework/jsonapi-client/tests/APP/Models/Tag.php:70

The definition of Article class:

<?php
class Article extends Model
{
    use ModelTrait;

    protected static function defineModel() : ResourceModel
    {
        return (new ResourceModel('article'))
            ->addVariable('table', 'article')
            ->setRelationships(
                (object) [
                    'author' => new Relationship(
                        User::getResourceModel(),
                        Relationship::TYPE_TO_ONE,
                        'creator-user_id'
                    ),
                    'tag' => new Relationship(
                        Tag::getResourceModel(),
                        Relationship::TYPE_TO_MANY,
                        null,//'tag_id'
                        (object) [
                            /**
                             * @param string $articleId
                             * @return string[]
                             */
                            'GET' => function (string $articleId) {
                                $ids = [];
                                return $ids;
                            }
                        ]
                    )
                ]
            );
    }
}

Tag class is similar

This is a very serious issue, since a lot of times have self referencing models (for example parent relationship)

nohponex commented 7 years ago

@alkallio @ConsideredHarmless could we use something like a promise of ResourceModel instead to solve this ?

The constructor of Relationship class is:

<?php
public function __construct(
        ResourceModel $model,
        int $type = Relationship::TYPE_TO_ONE,
        string $recordDataAttribute = null,
        \stdClass $callbacks = null,
        int $flags = Relationship::FLAG_DEFAULT
    ) {
nohponex commented 7 years ago

A callable instead of stdObject at setRelationships(\stdClass $relationships) should probably do the trick but it wont allow helper methods like addRelationship or removeRelationship to be implemented (could be used when extending an existing ResourceModel) .

Even if have something like lazy-evaluation (getRelationships calls the callable only when needed, hopefully after the construction of all ResourceModel)

So probably relationships MUST be defined separately when extending if they are different from "base" ResourceModel

nohponex commented 7 years ago

At 5a6d700

<?php
            ->setRelationships(
                (object) [
                    'author' => new Relationship(
                        function () {
                            return User::getResourceModel();
                        },
                        Relationship::TYPE_TO_ONE,
                        'creator-user_id'
                    ),
                    'tag' => new Relationship(
                        function () {
                            return Tag::getResourceModel();
                        },
                        Relationship::TYPE_TO_MANY,
                        null,//'tag_id'
                        (object) [
                            /**
                             * @param string $articleId
                             * @return string[]
                             */
                            'GET' => function (string $articleId) {
                                $ids = [];
                                return $ids;
                            }
                        ]
                    )
                ]
            );

Seems to do the trick