Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added the NestedRelation #290

Open
wants to merge 5 commits into
base: master
Choose a base branch
from

Conversation

alexberezinsky
Copy link

NestedRelation can be used for eager-loading of multi-level related entities.

Usage example for Post Entity:

namespace Entity;

use Spot\EntityInterface as Entity;
use Spot\MapperInterface as Mapper;

class Post extends \Spot\Entity
{
    protected static $table = 'posts';

    public static function fields()
    {
        return [
            'id'           => ['type' => 'integer', 'autoincrement' => true, 'primary' => true],
            'user_id'      => ['type' => 'integer', 'required' => true],
            'title'        => ['type' => 'string', 'required' => true],
            'body'         => ['type' => 'text', 'required' => true],
            'status'       => ['type' => 'integer', 'default' => 0, 'index' => true],
            'date_created' => ['type' => 'datetime', 'value' => new \DateTime()]
        ];
    }

    public static function relations(Mapper $mapper, Entity $entity)
    {
        $userRelation = $mapper->belongsTo($entity, 'Entity\User', 'user_id');
        $profileRelation =  User::relations($mapper, $entity)['profile'];
        return [
            'user' => $userRelation,
            'user.profile' => $mapper->nestedRelation($profileRelation, $userRelation);
        ];
    }
}

And then we can eager load user profiles with posts:

$posts = $posts->all()->with(['user', 'user.profile']);

NestedRelation can be used with any relations and can be multilevel. For example:

$posts = $posts->all()->with([
     'user', 
     'user.profile'
     'user.profile.image',
     'comments',
     'comments.user',
     'comments.user.profile',
     'comments.user.profile.image'
]);

@alexberezinsky
Copy link
Author

Hey guys. Please tell me what do you think about this idea. I use it for one of my projects to avoid lazy-loading of related entities. This can save a lot of db queries. I would like to contribute it to Spot2.
If you like the idea I can continue working on it and improve it further.

@FlipEverything
Copy link
Contributor

I like it! Somebody from the team will review it as soon as possible.

@alexberezinsky
Copy link
Author

Ok, great. Thanks.

lib/Relation/NestedRelation.php Outdated Show resolved Hide resolved
lib/Relation/NestedRelation.php Outdated Show resolved Hide resolved
lib/Relation/NestedRelation.php Show resolved Hide resolved
lib/Relation/NestedRelation.php Show resolved Hide resolved
@alexberezinsky
Copy link
Author

Hey guys,

I added some tests to the new relation.

Also I changed the way of adding nested relations to entities. So actually now there is no need to define them inside entities. Nested relations will be created automatically when added with 'with' method. So the only things to ensure is that all the parent levels are loaded and the target relation exists. For example:

$posts->all()->with(['user_comments', 'user_comments.user']);

For this case Post entity should have a 'user_comments' relation and UserComment entity should have 'user' relation. That will be enough for the above code to work.

I can improve it further if there is a need.

Thanks.

tests/NestedRelation.php Outdated Show resolved Hide resolved
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants