# nested 嵌套预加载关联

预加载关联可以减少查询,并且支持嵌套,通过 . 分隔嵌套关联。

Uses

<?php

use Leevel\Support\Collection;
use Tests\Database\DatabaseTestCase as TestCase;
use Tests\Database\Ddd\Entity\Relation\Post;
use Tests\Database\Ddd\Entity\Relation\Role;
use Tests\Database\Ddd\Entity\Relation\User;
use Tests\Database\Ddd\Entity\Relation\UserRole;

# 基本使用方法

fixture 定义

Tests\Database\Ddd\Entity\Relation\Post

namespace Tests\Database\Ddd\Entity\Relation;

use Leevel\Database\Ddd\Entity;
use Leevel\Database\Ddd\GetterSetter;
use Leevel\Database\Ddd\Relation\Relation;

class Post extends Entity
{
    use GetterSetter;

    public const TABLE = 'post';

    public const ID = 'id';

    public const AUTO = 'id';

    public const STRUCT = [
        'id' => [
            self::READONLY           => true,
        ],
        'title'     => [],
        'user_id'   => [],
        'summary'   => [],
        'create_at' => [],
        'delete_at' => [
            self::CREATE_FILL => 0,
        ],
        'user'      => [
            self::BELONGS_TO     => User::class,
            self::SOURCE_KEY     => 'user_id',
            self::TARGET_KEY     => 'id',
        ],
        'comment' => [
            self::HAS_MANY          => Comment::class,
            self::SOURCE_KEY        => 'id',
            self::TARGET_KEY        => 'post_id',
            self::RELATION_SCOPE    => 'comment',
        ],
        'post_content' => [
            self::HAS_ONE     => PostContent::class,
            self::SOURCE_KEY  => 'id',
            self::TARGET_KEY  => 'post_id',
        ],
        'user_not_defined_source_key'      => [
            self::BELONGS_TO     => User::class,
            self::TARGET_KEY     => 'id',
        ],
        'user_not_defined_target_key'      => [
            self::BELONGS_TO     => User::class,
            self::SOURCE_KEY     => 'id',
        ],
        'comment_not_defined_source_key' => [
            self::HAS_MANY          => Comment::class,
            self::TARGET_KEY        => 'post_id',
            self::RELATION_SCOPE    => 'comment',
        ],
        'comment_not_defined_target_key' => [
            self::HAS_MANY          => Comment::class,
            self::SOURCE_KEY        => 'id',
            self::RELATION_SCOPE    => 'comment',
        ],
        'post_content_not_defined_source_key' => [
            self::HAS_ONE     => PostContent::class,
            self::TARGET_KEY  => 'post_id',
        ],
        'post_content_not_defined_target_key' => [
            self::HAS_ONE     => PostContent::class,
            self::SOURCE_KEY  => 'id',
        ],
    ];

    public const DELETE_AT = 'delete_at';

    protected function relationScopeComment(Relation $relation): void
    {
        $relation->where('id', '>', 4);
    }
}

Tests\Database\Ddd\Entity\Relation\UserRole

namespace Tests\Database\Ddd\Entity\Relation;

use Leevel\Database\Ddd\Entity;
use Leevel\Database\Ddd\GetterSetter;

class UserRole extends Entity
{
    use GetterSetter;

    public const TABLE = 'user_role';

    public const ID = 'id';

    public const AUTO = 'id';

    public const STRUCT = [
        'id'        => [],
        'user_id'   => [],
        'role_id'   => [],
        'create_at' => [],
    ];
}

Tests\Database\Ddd\Entity\Relation\Role

namespace Tests\Database\Ddd\Entity\Relation;

use Leevel\Database\Ddd\Entity;
use Leevel\Database\Ddd\GetterSetter;

class Role extends Entity
{
    use GetterSetter;

    public const TABLE = 'role';

    public const ID = 'id';

    public const AUTO = 'id';

    public const STRUCT = [
        'id'        => [],
        'name'      => [],
        'create_at' => [],
    ];
}
public function testBase(): void
{
    $posts = Post::select()->limit(5)->findAll();

    $this->assertInstanceof(Collection::class, $posts);
    $this->assertCount(0, $posts);

    $connect = $this->createDatabaseConnect();

    for ($i = 0; $i <= 5; $i++) {
        $this->assertSame(
            $i + 1,
            $connect
                ->table('post')
                ->insert([
                    'title'     => 'hello world',
                    'user_id'   => 1,
                    'summary'   => 'Say hello to the world.',
                    'delete_at' => 0,
                ])
        );
    }

    $this->assertSame(
        1,
        $connect
            ->table('user')
            ->insert([
                'name' => 'niu',
            ])
    );

    $this->assertSame(
        1,
        $connect
            ->table('role')
            ->insert([
                'name' => '管理员',
            ])
    );

    $this->assertSame(
        2,
        $connect
            ->table('role')
            ->insert([
                'name' => '版主',
            ])
    );

    $this->assertSame(
        3,
        $connect
            ->table('role')
            ->insert([
                'name' => '会员',
            ])
    );

    $this->assertSame(
        1,
        $connect
            ->table('user_role')
            ->insert([
                'user_id' => 1,
                'role_id' => 1,
            ])
    );

    $this->assertSame(
        2,
        $connect
            ->table('user_role')
            ->insert([
                'user_id' => 1,
                'role_id' => 3,
            ])
    );

    $posts = Post::eager(['user.role'])
        ->limit(5)
        ->findAll();

    $this->assertInstanceof(Collection::class, $posts);
    $this->assertCount(5, $posts);

    $post = Post::select()->where('id', 1)->findOne();

    $this->assertSame(1, $post->id);
    $this->assertSame(1, $post['id']);
    $this->assertSame(1, $post->getId());
    $this->assertSame(1, $post->user_id);
    $this->assertSame(1, $post->userId);
    $this->assertSame(1, $post['user_id']);
    $this->assertSame(1, $post->getUserId());
    $this->assertSame('hello world', $post->title);
    $this->assertSame('hello world', $post['title']);
    $this->assertSame('hello world', $post->getTitle());
    $this->assertSame('Say hello to the world.', $post->summary);
    $this->assertSame('Say hello to the world.', $post['summary']);
    $this->assertSame('Say hello to the world.', $post->getSummary());

    $user = $post->user;

    $this->assertInstanceof(User::class, $user);
    $this->assertSame(1, $user->id);
    $this->assertSame(1, $user['id']);
    $this->assertSame(1, $user->getId());
    $this->assertSame('niu', $user->name);
    $this->assertSame('niu', $user['name']);
    $this->assertSame('niu', $user->getName());

    $role = $user->role;

    $this->assertInstanceof(Collection::class, $role);

    $user1 = $role[0];

    $this->assertInstanceof(Role::class, $user1);
    $this->assertSame(1, $user1->id);
    $this->assertSame(1, $user1['id']);
    $this->assertSame(1, $user1->getId());
    $this->assertSame('管理员', $user1->name);
    $this->assertSame('管理员', $user1['name']);
    $this->assertSame('管理员', $user1->getName());

    $user2 = $role[1];
    $this->assertInstanceof(Role::class, $user2);
    $this->assertSame(3, $user2->id);
    $this->assertSame(3, $user2['id']);
    $this->assertSame(3, $user2->getId());
    $this->assertSame('会员', $user2->name);
    $this->assertSame('会员', $user2['name']);
    $this->assertSame('会员', $user2->getName());

    $this->assertCount(2, $role);
    $this->assertSame(1, $role[0]['id']);
    $this->assertSame('管理员', $role[0]['name']);
    $this->assertSame(3, $role[1]['id']);
    $this->assertSame('会员', $role[1]['name']);

    $middle = $role[0]->middle();
    $this->assertInstanceof(UserRole::class, $middle);
    $this->assertSame(1, $middle->userId);
    $this->assertSame(1, $middle->roleId);

    $middle = $role[1]->middle();
    $this->assertInstanceof(UserRole::class, $middle);
    $this->assertSame(1, $middle->userId);
    $this->assertSame(3, $middle->roleId);
}