实体导出数组
Testing Is Documentation
我们可以将实体导出为数组来方便处理数据。
Uses
<?php
use Leevel\Database\Ddd\Entity;
use Leevel\Kernel\Utils\Api;
use Tests\Database\DatabaseTestCase as TestCase;
use Tests\Database\Ddd\Entity\DemoToArrayBlackEntity;
use Tests\Database\Ddd\Entity\DemoToArrayEntity;
use Tests\Database\Ddd\Entity\DemoToArrayShowPropNullEntity;
use Tests\Database\Ddd\Entity\DemoToArrayShowPropNullRelationEntity;
use Tests\Database\Ddd\Entity\DemoToArrayShowPropNullRelationTargetEntity;
use Tests\Database\Ddd\Entity\DemoToArrayWhiteEntity;
use Tests\Database\Ddd\Entity\Relation\Post;
use Tests\Database\Ddd\Entity\Relation\User;
toArray 基本使用方法
fixture 定义
# Tests\Database\Ddd\EntityToArrayTest::makeEntity
protected function makeEntity(): DemoToArrayEntity
{
$entity = new DemoToArrayEntity();
$this->assertInstanceof(Entity::class, $entity);
$entity->name = '实体名字';
$entity->description = 'goods name';
$entity->address = '四川成都';
$entity->foo_bar = 'foo';
$entity->hello = 'hello world';
return $entity;
}
Tests\Database\Ddd\Entity\DemoToArrayEntity
namespace Tests\Database\Ddd\Entity;
use Leevel\Database\Ddd\Entity;
use Leevel\Database\Ddd\Struct;
class DemoToArrayEntity extends Entity
{
public const string TABLE = 'test';
public const string ID = 'id';
public const string AUTO = 'id';
#[Struct([
])]
protected ?int $id = null;
#[Struct([
])]
protected ?string $name = null;
#[Struct([
])]
protected ?string $description = null;
#[Struct([
])]
protected ?string $address = null;
#[Struct([
])]
protected ?string $fooBar = null;
#[Struct([
])]
protected ?string $hello = null;
}
public function testBaseUse(): void
{
$entity = $this->makeEntity();
$data = <<<'eot'
{
"name": "实体名字",
"description": "goods name",
"address": "四川成都",
"foo_bar": "foo",
"hello": "hello world"
}
eot;
self::assertSame(
$data,
$this->varJson(
$entity->toArray()
)
);
}
toArray 实体对象转数组支持白名单
toArray
第一个参数为白名单,设置了白名单,只有白名单的字段才能够转换为数组数据。
public function testWithWhite(): void
{
$entity = $this->makeEntity();
$data = <<<'eot'
{
"name": "实体名字",
"description": "goods name",
"address": "四川成都",
"foo_bar": "foo",
"hello": "hello world"
}
eot;
self::assertSame(
$data,
$this->varJson(
$entity->toArray()
)
);
$data = <<<'eot'
{
"name": "实体名字"
}
eot;
self::assertSame(
$data,
$this->varJson(
$entity
->only(['name'])
->toArray(),
1
)
);
$data = <<<'eot'
{
"name": "实体名字",
"description": "goods name"
}
eot;
self::assertSame(
$data,
$this->varJson(
$entity
->only(['name', 'description'])
->toArray(),
2
)
);
$data = <<<'eot'
{
"name": "实体名字",
"description": "goods name",
"hello": "hello world"
}
eot;
self::assertSame(
$data,
$this->varJson(
$entity
->only(['name', 'description', 'hello'])
->toArray(),
3
)
);
}
toArray 实体对象转数组支持黑名单
toArray
第二个参数为白名单,设置了黑名单但是没有设置白名单,只有不属于黑名单的字段才能够转换为数组数据。
public function testWithBlack(): void
{
$entity = $this->makeEntity();
$data = <<<'eot'
{
"name": "实体名字",
"description": "goods name",
"address": "四川成都",
"foo_bar": "foo",
"hello": "hello world"
}
eot;
self::assertSame(
$data,
$this->varJson(
$entity->toArray()
)
);
$data = <<<'eot'
{
"description": "goods name",
"address": "四川成都",
"foo_bar": "foo",
"hello": "hello world"
}
eot;
self::assertSame(
$data,
$this->varJson(
$entity
->except(['name'])
->toArray(),
1
)
);
$data = <<<'eot'
{
"address": "四川成都",
"foo_bar": "foo",
"hello": "hello world"
}
eot;
self::assertSame(
$data,
$this->varJson(
$entity
->except(['name', 'description'])
->toArray(),
2
)
);
$data = <<<'eot'
{
"description": "goods name",
"hello": "hello world"
}
eot;
self::assertSame(
$data,
$this->varJson(
$entity
->except(['foo_bar', 'name', 'address'])
->toArray(),
3
)
);
}
toArray 实体对象转数组支持字段设置为白名单
可以通过 STRUCT
中的定义 \Leevel\Database\Ddd\Entity::SHOW_PROP_WHITE
来设置字段白名单。
值得注意的是, toArray
的第一个参数白名单优先级更高。
如果设置了白名单,只有白名单的字段才能够转换为数组数据。
fixture 定义
# Tests\Database\Ddd\EntityToArrayTest::makeWhiteEntity
protected function makeWhiteEntity(): DemoToArrayWhiteEntity
{
$entity = new DemoToArrayWhiteEntity();
$this->assertInstanceof(Entity::class, $entity);
$entity->name = '实体名字';
$entity->description = 'goods name';
$entity->address = '四川成都';
$entity->foo_bar = 'foo';
$entity->hello = 'hello world';
return $entity;
}
Tests\Database\Ddd\Entity\DemoToArrayWhiteEntity
namespace Tests\Database\Ddd\Entity;
use Leevel\Database\Ddd\Entity;
use Leevel\Database\Ddd\Struct;
class DemoToArrayWhiteEntity extends Entity
{
public const string TABLE = 'test';
public const string ID = 'id';
public const string AUTO = 'id';
#[Struct([
])]
protected ?int $id = null;
#[Struct([
])]
protected ?string $name = null;
#[Struct([
self::SHOW_PROP_WHITE => true,
])]
protected ?string $description = null;
#[Struct([
])]
protected ?string $address = null;
#[Struct([
self::SHOW_PROP_WHITE => true,
])]
protected ?string $fooBar = null;
#[Struct([
])]
protected ?string $hello = null;
}
public function testWithWhiteEntity(): void
{
$entity = $this->makeWhiteEntity();
$data = <<<'eot'
{
"description": "goods name",
"foo_bar": "foo"
}
eot;
self::assertSame(
$data,
$this->varJson(
$entity->toArray()
)
);
}
toArray 实体对象转数组支持字段设置为黑名单
可以通过 STRUCT
中的定义 \Leevel\Database\Ddd\Entity::SHOW_PROP_BLACK
来设置字段黑名单。
值得注意的是, toArray
的第二个参数黑名单优先级更高。
如果设置了黑名单,设置了黑名单但是没有设置白名单,只有不属于黑名单的字段才能够转换为数组数据。
fixture 定义
# Tests\Database\Ddd\EntityToArrayTest::makeBlackEntity
protected function makeBlackEntity(): DemoToArrayBlackEntity
{
$entity = new DemoToArrayBlackEntity();
$this->assertInstanceof(Entity::class, $entity);
$entity->name = '实体名字';
$entity->description = 'goods name';
$entity->address = '四川成都';
$entity->foo_bar = 'foo';
$entity->hello = 'hello world';
return $entity;
}
Tests\Database\Ddd\Entity\DemoToArrayBlackEntity
namespace Tests\Database\Ddd\Entity;
use Leevel\Database\Ddd\Entity;
use Leevel\Database\Ddd\Struct;
class DemoToArrayBlackEntity extends Entity
{
public const string TABLE = 'test';
public const string ID = 'id';
public const string AUTO = 'id';
#[Struct([
])]
protected ?int $id = null;
#[Struct([
])]
protected ?string $name = null;
#[Struct([
self::SHOW_PROP_BLACK => true,
])]
protected ?string $description = null;
#[Struct([
])]
protected ?string $address = null;
#[Struct([
self::SHOW_PROP_BLACK => true,
])]
protected ?string $fooBar = null;
#[Struct([
])]
protected ?string $hello = null;
}
public function testWithBlackEntity(): void
{
$entity = $this->makeBlackEntity();
$data = <<<'eot'
{
"name": "实体名字",
"address": "四川成都",
"hello": "hello world"
}
eot;
self::assertSame(
$data,
$this->varJson(
$entity->toArray()
)
);
}
toArray 实体对象转数组支持转换关联实体数据
fixture 定义
# Tests\Database\Ddd\EntityToArrayTest::makeRelationEntity
protected function makeRelationEntity(): Post
{
$user = new User(['id' => 7]);
$user->name = 'xiaoniuge';
$entity = new Post(['id' => 5]);
$this->assertInstanceof(Post::class, $entity);
$entity->title = 'I am title';
$entity->summary = 'I am summary';
$entity->userId = 7;
$entity->withRelationProp('user', $user);
return $entity;
}
Tests\Database\Ddd\Entity\Relation\User
namespace Tests\Database\Ddd\Entity\Relation;
use Leevel\Database\Ddd\Entity;
use Leevel\Database\Ddd\EntityCollection as Collection;
use Leevel\Database\Ddd\Relation\ManyMany;
use Leevel\Database\Ddd\Struct;
class User extends Entity
{
public const string TABLE = 'user';
public const string ID = 'id';
public const string AUTO = 'id';
#[Struct([
])]
protected ?int $id = null;
#[Struct([
])]
protected ?string $name = null;
#[Struct([
])]
protected ?string $createAt = null;
#[Struct([
self::MANY_MANY => Role::class,
self::MIDDLE_ENTITY => UserRole::class,
self::SOURCE_KEY => 'id',
self::TARGET_KEY => 'id',
self::MIDDLE_SOURCE_KEY => 'user_id',
self::MIDDLE_TARGET_KEY => 'role_id',
])]
protected ?Collection $role = null;
#[Struct([
self::MANY_MANY => RoleSoftDeleted::class,
self::MIDDLE_ENTITY => UserRoleSoftDeleted::class,
self::SOURCE_KEY => 'id',
self::TARGET_KEY => 'id',
self::MIDDLE_SOURCE_KEY => 'user_id',
self::MIDDLE_TARGET_KEY => 'role_id',
])]
protected ?Collection $roleSoftDeleted = null;
#[Struct([
self::MANY_MANY => RoleSoftDeleted::class,
self::MIDDLE_ENTITY => UserRoleSoftDeleted::class,
self::SOURCE_KEY => 'id',
self::TARGET_KEY => 'id',
self::MIDDLE_SOURCE_KEY => 'user_id',
self::MIDDLE_TARGET_KEY => 'role_id',
self::RELATION_SCOPE => 'withSoftDeleted',
])]
protected ?Collection $roleMiddleWithSoftDeleted = null;
#[Struct([
self::MANY_MANY => RoleSoftDeleted::class,
self::MIDDLE_ENTITY => UserRoleSoftDeleted::class,
self::SOURCE_KEY => 'id',
self::TARGET_KEY => 'id',
self::MIDDLE_SOURCE_KEY => 'user_id',
self::MIDDLE_TARGET_KEY => 'role_id',
self::RELATION_SCOPE => 'onlySoftDeleted',
])]
protected ?Collection $roleMiddleOnlySoftDeleted = null;
#[Struct([
self::MANY_MANY => RoleSoftDeleted::class,
self::MIDDLE_ENTITY => UserRoleSoftDeleted::class,
self::SOURCE_KEY => 'id',
self::TARGET_KEY => 'id',
self::MIDDLE_SOURCE_KEY => 'user_id',
self::MIDDLE_TARGET_KEY => 'role_id',
self::RELATION_SCOPE => 'notFound',
])]
protected ?Collection $roleRelationScopeNotFound = null;
#[Struct([
self::MANY_MANY => RoleSoftDeleted::class,
self::MIDDLE_ENTITY => UserRoleSoftDeleted::class,
self::SOURCE_KEY => 'id',
self::TARGET_KEY => 'id',
self::MIDDLE_SOURCE_KEY => 'user_id',
self::MIDDLE_TARGET_KEY => 'role_id',
self::RELATION_SCOPE => 'foundButPrivate',
])]
protected ?Collection $roleRelationScopeFoundButPrivate = null;
#[Struct([
self::MANY_MANY => Role::class,
self::SOURCE_KEY => 'id',
self::TARGET_KEY => 'id',
self::MIDDLE_SOURCE_KEY => 'user_id',
self::MIDDLE_TARGET_KEY => 'role_id',
])]
protected ?Collection $roleNotDefinedMiddleEntity = null;
#[Struct([
self::MANY_MANY => Role::class,
self::MIDDLE_ENTITY => UserRole::class,
self::TARGET_KEY => 'id',
self::MIDDLE_SOURCE_KEY => 'user_id',
self::MIDDLE_TARGET_KEY => 'role_id',
])]
protected ?Collection $roleNotDefinedSourceKey = null;
#[Struct([
self::MANY_MANY => Role::class,
self::MIDDLE_ENTITY => UserRole::class,
self::SOURCE_KEY => 'id',
self::MIDDLE_SOURCE_KEY => 'user_id',
self::MIDDLE_TARGET_KEY => 'role_id',
])]
protected ?Collection $roleNotDefinedTargetKey = null;
#[Struct([
self::MANY_MANY => Role::class,
self::MIDDLE_ENTITY => UserRole::class,
self::SOURCE_KEY => 'id',
self::TARGET_KEY => 'id',
self::MIDDLE_TARGET_KEY => 'role_id',
])]
protected ?Collection $roleNotDefinedMiddleSourceKey = null;
#[Struct([
self::MANY_MANY => Role::class,
self::MIDDLE_ENTITY => UserRole::class,
self::SOURCE_KEY => 'id',
self::TARGET_KEY => 'id',
self::MIDDLE_SOURCE_KEY => 'user_id',
])]
protected ?Collection $roleNotDefinedMiddleTargetKey = null;
#[Struct([
self::MANY_MANY => Role::class,
self::MIDDLE_ENTITY => UserRole::class,
self::SOURCE_KEY => 'id',
self::TARGET_KEY => 'id',
self::MIDDLE_SOURCE_KEY => 'user_id',
self::MIDDLE_TARGET_KEY => 'role_id',
self::RELATION_SCOPE => 'middleField',
])]
protected ?Collection $roleMiddleField = null;
#[Struct([
self::MANY_MANY => RoleSoftDeleted::class,
self::MIDDLE_ENTITY => UserRoleSoftDeleted::class,
self::SOURCE_KEY => 'id',
self::TARGET_KEY => 'id',
self::MIDDLE_SOURCE_KEY => 'user_id',
self::MIDDLE_TARGET_KEY => 'role_id',
self::RELATION_SCOPE => 'middleOnlySoftDeletedAndMiddleFieldAndOtherTableCondition',
])]
protected ?Collection $roleMiddleOnlySoftDeletedAndMiddleFieldAndOtherTableCondition = null;
protected function relationScopeWithSoftDeleted(ManyMany $relation): void
{
$relation->middleWithSoftDeleted();
}
protected function relationScopeOnlySoftDeleted(ManyMany $relation): void
{
$relation->middleOnlySoftDeleted();
}
protected function relationScopeMiddleField(ManyMany $relation): void
{
$relation->middleField(['create_at', 'middle_id' => 'id']);
}
protected function relationScopeMiddleOnlySoftDeletedAndMiddleFieldAndOtherTableCondition(ManyMany $relation): void
{
$relation
->middleOnlySoftDeleted()
->middleField(['create_at', 'middle_id' => 'id'])
->setColumns('id,name')
->where('id', '>', 3)
;
}
/** @phpstan-ignore-next-line */
private function relationScopeFoundButPrivate(ManyMany $relation): void {}
}
Tests\Database\Ddd\Entity\Relation\Post
namespace Tests\Database\Ddd\Entity\Relation;
use Leevel\Database\Ddd\Entity;
use Leevel\Database\Ddd\EntityCollection as Collection;
use Leevel\Database\Ddd\Relation\Relation;
use Leevel\Database\Ddd\Struct;
class Post extends Entity
{
public const string TABLE = 'post';
public const string ID = 'id';
public const string AUTO = 'id';
public const string DELETE_AT = 'delete_at';
#[Struct([
self::READONLY => true,
self::COLUMN_NAME => 'ID',
])]
protected ?int $id = null;
#[Struct([
self::COLUMN_NAME => '标题',
])]
protected ?string $title = null;
#[Struct([
self::COLUMN_NAME => '用户ID',
])]
protected ?int $userId = null;
#[Struct([
self::COLUMN_NAME => '文章摘要',
])]
protected ?string $summary = null;
#[Struct([
self::COLUMN_NAME => '创建时间',
])]
protected ?string $createAt = null;
#[Struct([
self::CREATE_FILL => 0,
self::COLUMN_NAME => '删除时间',
])]
protected ?int $deleteAt = null;
#[Struct([
self::BELONGS_TO => User::class,
self::SOURCE_KEY => 'user_id',
self::TARGET_KEY => 'id',
])]
protected ?User $user = null;
#[Struct([
self::HAS_MANY => Comment::class,
self::SOURCE_KEY => 'id',
self::TARGET_KEY => 'post_id',
self::RELATION_SCOPE => 'comment',
])]
protected ?Collection $comment = null;
#[Struct([
self::HAS_ONE => PostContent::class,
self::SOURCE_KEY => 'id',
self::TARGET_KEY => 'post_id',
])]
protected ?PostContent $postContent = null;
#[Struct([
self::BELONGS_TO => User::class,
self::TARGET_KEY => 'id',
])]
protected ?int $userNotDefinedSourceKey = null;
#[Struct([
self::BELONGS_TO => User::class,
self::SOURCE_KEY => 'id',
])]
protected ?int $userNotDefinedTargetKey = null;
#[Struct([
self::HAS_MANY => Comment::class,
self::TARGET_KEY => 'post_id',
self::RELATION_SCOPE => 'comment',
])]
protected ?int $commentNotDefinedSourceKey = null;
#[Struct([
self::HAS_MANY => Comment::class,
self::SOURCE_KEY => 'id',
self::RELATION_SCOPE => 'comment',
])]
protected ?int $commentNotDefinedTargetKey = null;
#[Struct([
self::HAS_ONE => PostContent::class,
self::TARGET_KEY => 'post_id',
])]
protected ?int $postContentNotDefinedSourceKey = null;
#[Struct([
self::HAS_ONE => PostContent::class,
self::SOURCE_KEY => 'id',
])]
protected ?int $postContentNotDefinedTargetKey = null;
protected function relationScopeComment(Relation $relation): void
{
$relation->where('id', '>', 4);
}
protected function relationScopeStringUserRelationScope(Relation $relation): void
{
$relation->where('id', '>', 4);
}
}
public function testWithRelation(): void
{
$entity = $this->makeRelationEntity();
$data = <<<'eot'
{
"id": 5,
"title": "I am title",
"user_id": 7,
"summary": "I am summary",
"user": {
"id": 7,
"name": "xiaoniuge"
}
}
eot;
self::assertSame(
$data,
$this->varJson(
$entity->toArray()
)
);
}
toArray 实体对象转数组支持转换关联实体数据(黑白名单)
toArray
第三个参数为关联实体的黑白名单。
public function testWithRelationWhiteAndBlack(): void
{
$entity = $this->makeRelationEntity();
$data = <<<'eot'
{
"id": 5,
"title": "I am title",
"user_id": 7,
"summary": "I am summary",
"user": {
"name": "xiaoniuge"
}
}
eot;
self::assertSame(
$data,
$this->varJson(
$entity
->each(static function ($value, $k) {
if ('user' === $k) {
$value = $value->only(['name']);
}
return $value;
})
->toArray()
)
);
}
toArray 实体对象转数组支持 NULL 值字段默认指定数据
fixture 定义
# Tests\Database\Ddd\EntityToArrayTest::makeShowPropNullEntity
protected function makeShowPropNullEntity(): DemoToArrayShowPropNullEntity
{
$entity = new DemoToArrayShowPropNullEntity();
$this->assertInstanceof(Entity::class, $entity);
$entity->name = '实体名字';
$entity->description = 'goods name';
return $entity;
}
Tests\Database\Ddd\Entity\DemoToArrayShowPropNullEntity
namespace Tests\Database\Ddd\Entity;
use Leevel\Database\Ddd\Entity;
use Leevel\Database\Ddd\Struct;
class DemoToArrayShowPropNullEntity extends Entity
{
public const string TABLE = 'test';
public const string ID = 'id';
public const string AUTO = 'id';
#[Struct([
])]
protected ?int $id = null;
#[Struct([
])]
protected ?string $name = null;
#[Struct([
])]
protected ?string $description = null;
#[Struct([
self::SHOW_PROP_NULL => '',
])]
protected ?string $address = null;
#[Struct([
self::SHOW_PROP_NULL => null,
])]
protected ?string $fooBar = null;
#[Struct([
self::SHOW_PROP_NULL => 'default_value',
])]
protected ?string $hello = null;
}
public function testWithShowPropNull(): void
{
$entity = $this->makeShowPropNullEntity();
$data = <<<'eot'
{
"name": "实体名字",
"description": "goods name",
"address": "",
"foo_bar": null,
"hello": "default_value"
}
eot;
self::assertSame(
$data,
$this->varJson(
$entity->toArray()
)
);
}
toArray 实体对象转数组支持 NULL 值字段默认指定数据(关联模型)
fixture 定义
# Tests\Database\Ddd\EntityToArrayTest::makeRelationShowPropNullEntity
protected function makeRelationShowPropNullEntity(): DemoToArrayShowPropNullRelationEntity
{
$target = new DemoToArrayShowPropNullRelationTargetEntity(['id' => 5]);
$target->name = 'xiaoniuge';
$entity = new DemoToArrayShowPropNullRelationEntity(['id' => 5]);
$this->assertInstanceof(DemoToArrayShowPropNullRelationEntity::class, $entity);
$entity->name = 'I am name';
$entity->description = 'I am description';
$entity->withRelationProp('target', $target);
return $entity;
}
Tests\Database\Ddd\Entity\DemoToArrayShowPropNullRelationTargetEntity
namespace Tests\Database\Ddd\Entity;
use Leevel\Database\Ddd\Entity;
use Leevel\Database\Ddd\Struct;
class DemoToArrayShowPropNullRelationTargetEntity extends Entity
{
public const string TABLE = 'test';
public const string ID = 'id';
public const string AUTO = 'id';
#[Struct([
])]
protected ?int $id = null;
#[Struct([
])]
protected ?string $name = null;
}
Tests\Database\Ddd\Entity\DemoToArrayShowPropNullRelationEntity
namespace Tests\Database\Ddd\Entity;
use Leevel\Database\Ddd\Entity;
use Leevel\Database\Ddd\Struct;
class DemoToArrayShowPropNullRelationEntity extends Entity
{
public const string TABLE = 'test';
public const string ID = 'id';
public const string AUTO = 'id';
#[Struct([
])]
protected ?int $id = null;
#[Struct([
])]
protected ?string $name = null;
#[Struct([
])]
protected ?string $description = null;
#[Struct([
self::SHOW_PROP_NULL => '',
])]
protected ?string $address = null;
#[Struct([
self::SHOW_PROP_NULL => null,
])]
protected ?string $fooBar = null;
#[Struct([
self::SHOW_PROP_NULL => 'default_value',
])]
protected ?string $hello = null;
#[Struct([
self::HAS_ONE => DemoToArrayShowPropNullRelationTargetEntity::class,
self::SOURCE_KEY => 'id',
self::TARGET_KEY => 'id',
])]
protected ?DemoToArrayShowPropNullRelationTargetEntity $target = null;
}
public function testWithShowPropNullForRelation(): void
{
$entity = $this->makeRelationShowPropNullEntity();
$data = <<<'eot'
{
"id": 5,
"name": "I am name",
"description": "I am description",
"address": "",
"foo_bar": null,
"hello": "default_value",
"target": {
"id": 5,
"name": "xiaoniuge"
}
}
eot;
self::assertSame(
$data,
$this->varJson(
$entity->toArray()
)
);
}