manyMany 多对多关联

Testing Is Documentation

tests/Database/Ddd/Relation/ManyManyTest.phpmanyMany 多对多关联 - 图1

多对多的关联是一种常用的关联,比如用户与角色属于多对多的关系。

多对多关联支持类型关联项

关联项说明例子
\Leevel\Database\Ddd\Entity::MANY_MANY多对多关联实体\Tests\Database\Ddd\Entity\Relation\Role::class
\Leevel\Database\Ddd\Entity::MIDDLE_ENTITY关联查询中间实体\Tests\Database\Ddd\Entity\Relation\UserRole::class
\Leevel\Database\Ddd\Entity::SOURCE_KEY关联查询源键字段user_id
\Leevel\Database\Ddd\Entity::TARGET_KEY关联目标键字段id
\Leevel\Database\Ddd\Entity::MIDDLE_SOURCE_KEY关联查询中间实体源键字段id
\Leevel\Database\Ddd\Entity::MIDDLE_TARGET_KEY关联查询中间实体目标键字段id
\Leevel\Database\Ddd\Entity::RELATION_SCOPE关联查询作用域middleField

Uses

  1. <?php
  2. use Leevel\Collection\Collection;
  3. use Leevel\Database\Ddd\Relation\ManyMany;
  4. use Leevel\Database\Ddd\Relation\Relation;
  5. use Leevel\Database\Ddd\Select;
  6. use Tests\Database\DatabaseTestCase as TestCase;
  7. use Tests\Database\Ddd\Entity\Relation\Role;
  8. use Tests\Database\Ddd\Entity\Relation\RoleSoftDeleted;
  9. use Tests\Database\Ddd\Entity\Relation\User;
  10. use Tests\Database\Ddd\Entity\Relation\UserRole;
  11. use Tests\Database\Ddd\Entity\Relation\UserRoleSoftDeleted;

基本使用方法

fixture 定义

Tests\Database\Ddd\Entity\Relation\User

  1. namespace Tests\Database\Ddd\Entity\Relation;
  2. use Leevel\Database\Ddd\Entity;
  3. use Leevel\Database\Ddd\GetterSetter;
  4. use Leevel\Database\Ddd\Relation\ManyMany;
  5. class User extends Entity
  6. {
  7. use GetterSetter;
  8. const TABLE = 'user';
  9. const ID = 'id';
  10. const AUTO = 'id';
  11. const STRUCT = [
  12. 'id' => [],
  13. 'name' => [],
  14. 'create_at' => [],
  15. 'role' => [
  16. self::MANY_MANY => Role::class,
  17. self::MIDDLE_ENTITY => UserRole::class,
  18. self::SOURCE_KEY => 'id',
  19. self::TARGET_KEY => 'id',
  20. self::MIDDLE_SOURCE_KEY => 'user_id',
  21. self::MIDDLE_TARGET_KEY => 'role_id',
  22. ],
  23. 'role_soft_deleted' => [
  24. self::MANY_MANY => RoleSoftDeleted::class,
  25. self::MIDDLE_ENTITY => UserRoleSoftDeleted::class,
  26. self::SOURCE_KEY => 'id',
  27. self::TARGET_KEY => 'id',
  28. self::MIDDLE_SOURCE_KEY => 'user_id',
  29. self::MIDDLE_TARGET_KEY => 'role_id',
  30. ],
  31. 'role_middle_with_soft_deleted' => [
  32. self::MANY_MANY => RoleSoftDeleted::class,
  33. self::MIDDLE_ENTITY => UserRoleSoftDeleted::class,
  34. self::SOURCE_KEY => 'id',
  35. self::TARGET_KEY => 'id',
  36. self::MIDDLE_SOURCE_KEY => 'user_id',
  37. self::MIDDLE_TARGET_KEY => 'role_id',
  38. self::RELATION_SCOPE => 'withSoftDeleted',
  39. ],
  40. 'role_middle_only_soft_deleted' => [
  41. self::MANY_MANY => RoleSoftDeleted::class,
  42. self::MIDDLE_ENTITY => UserRoleSoftDeleted::class,
  43. self::SOURCE_KEY => 'id',
  44. self::TARGET_KEY => 'id',
  45. self::MIDDLE_SOURCE_KEY => 'user_id',
  46. self::MIDDLE_TARGET_KEY => 'role_id',
  47. self::RELATION_SCOPE => 'onlySoftDeleted',
  48. ],
  49. 'role_relation_scope_not_found' => [
  50. self::MANY_MANY => RoleSoftDeleted::class,
  51. self::MIDDLE_ENTITY => UserRoleSoftDeleted::class,
  52. self::SOURCE_KEY => 'id',
  53. self::TARGET_KEY => 'id',
  54. self::MIDDLE_SOURCE_KEY => 'user_id',
  55. self::MIDDLE_TARGET_KEY => 'role_id',
  56. self::RELATION_SCOPE => 'notFound',
  57. ],
  58. 'role_relation_scope_found_but_private' => [
  59. self::MANY_MANY => RoleSoftDeleted::class,
  60. self::MIDDLE_ENTITY => UserRoleSoftDeleted::class,
  61. self::SOURCE_KEY => 'id',
  62. self::TARGET_KEY => 'id',
  63. self::MIDDLE_SOURCE_KEY => 'user_id',
  64. self::MIDDLE_TARGET_KEY => 'role_id',
  65. self::RELATION_SCOPE => 'foundButPrivate',
  66. ],
  67. 'role_not_defined_middle_entity' => [
  68. self::MANY_MANY => Role::class,
  69. self::SOURCE_KEY => 'id',
  70. self::TARGET_KEY => 'id',
  71. self::MIDDLE_SOURCE_KEY => 'user_id',
  72. self::MIDDLE_TARGET_KEY => 'role_id',
  73. ],
  74. 'role_not_defined_source_key' => [
  75. self::MANY_MANY => Role::class,
  76. self::MIDDLE_ENTITY => UserRole::class,
  77. self::TARGET_KEY => 'id',
  78. self::MIDDLE_SOURCE_KEY => 'user_id',
  79. self::MIDDLE_TARGET_KEY => 'role_id',
  80. ],
  81. 'role_not_defined_target_key' => [
  82. self::MANY_MANY => Role::class,
  83. self::MIDDLE_ENTITY => UserRole::class,
  84. self::SOURCE_KEY => 'id',
  85. self::MIDDLE_SOURCE_KEY => 'user_id',
  86. self::MIDDLE_TARGET_KEY => 'role_id',
  87. ],
  88. 'role_not_defined_middle_source_key' => [
  89. self::MANY_MANY => Role::class,
  90. self::MIDDLE_ENTITY => UserRole::class,
  91. self::SOURCE_KEY => 'id',
  92. self::TARGET_KEY => 'id',
  93. self::MIDDLE_TARGET_KEY => 'role_id',
  94. ],
  95. 'role_not_defined_middle_target_key' => [
  96. self::MANY_MANY => Role::class,
  97. self::MIDDLE_ENTITY => UserRole::class,
  98. self::SOURCE_KEY => 'id',
  99. self::TARGET_KEY => 'id',
  100. self::MIDDLE_SOURCE_KEY => 'user_id',
  101. ],
  102. 'role_middle_field' => [
  103. self::MANY_MANY => Role::class,
  104. self::MIDDLE_ENTITY => UserRole::class,
  105. self::SOURCE_KEY => 'id',
  106. self::TARGET_KEY => 'id',
  107. self::MIDDLE_SOURCE_KEY => 'user_id',
  108. self::MIDDLE_TARGET_KEY => 'role_id',
  109. self::RELATION_SCOPE => 'middleField',
  110. ],
  111. 'role_middle_only_soft_deleted_and_middle_field_and_other_table_condition' => [
  112. self::MANY_MANY => RoleSoftDeleted::class,
  113. self::MIDDLE_ENTITY => UserRoleSoftDeleted::class,
  114. self::SOURCE_KEY => 'id',
  115. self::TARGET_KEY => 'id',
  116. self::MIDDLE_SOURCE_KEY => 'user_id',
  117. self::MIDDLE_TARGET_KEY => 'role_id',
  118. self::RELATION_SCOPE => 'middleOnlySoftDeletedAndMiddleFieldAndOtherTableCondition',
  119. ],
  120. ];
  121. protected function relationScopeWithSoftDeleted(ManyMany $relation): void
  122. {
  123. $relation->middleWithSoftDeleted();
  124. }
  125. protected function relationScopeOnlySoftDeleted(ManyMany $relation): void
  126. {
  127. $relation->middleOnlySoftDeleted();
  128. }
  129. protected function relationScopeMiddleField(ManyMany $relation): void
  130. {
  131. $relation->middleField(['create_at', 'middle_id' => 'id']);
  132. }
  133. protected function relationScopeMiddleOnlySoftDeletedAndMiddleFieldAndOtherTableCondition(ManyMany $relation): void
  134. {
  135. $relation
  136. ->middleOnlySoftDeleted()
  137. ->middleField(['create_at', 'middle_id' => 'id'])
  138. ->setColumns('id,name')
  139. ->where('id', '>', 3);
  140. }
  141. private function relationScopeFoundButPrivate(ManyMany $relation): void
  142. {
  143. }
  144. }

Tests\Database\Ddd\Entity\Relation\UserRole

  1. namespace Tests\Database\Ddd\Entity\Relation;
  2. use Leevel\Database\Ddd\Entity;
  3. use Leevel\Database\Ddd\GetterSetter;
  4. class UserRole extends Entity
  5. {
  6. use GetterSetter;
  7. const TABLE = 'user_role';
  8. const ID = 'id';
  9. const AUTO = 'id';
  10. const STRUCT = [
  11. 'id' => [],
  12. 'user_id' => [],
  13. 'role_id' => [],
  14. 'create_at' => [],
  15. ];
  16. }

Tests\Database\Ddd\Entity\Relation\Role

  1. namespace Tests\Database\Ddd\Entity\Relation;
  2. use Leevel\Database\Ddd\Entity;
  3. use Leevel\Database\Ddd\GetterSetter;
  4. class Role extends Entity
  5. {
  6. use GetterSetter;
  7. const TABLE = 'role';
  8. const ID = 'id';
  9. const AUTO = 'id';
  10. const STRUCT = [
  11. 'id' => [],
  12. 'name' => [],
  13. 'create_at' => [],
  14. ];
  15. }
  1. public function testBaseUse(): void
  2. {
  3. $user = User::select()->where('id', 1)->findOne();
  4. $this->assertInstanceof(User::class, $user);
  5. $this->assertNull($user->id);
  6. $connect = $this->createDatabaseConnect();
  7. $this->assertSame(
  8. 1,
  9. $connect
  10. ->table('user')
  11. ->insert([
  12. 'name' => 'niu',
  13. ])
  14. );
  15. $this->assertSame(
  16. 1,
  17. $connect
  18. ->table('role')
  19. ->insert([
  20. 'name' => '管理员',
  21. ])
  22. );
  23. $this->assertSame(
  24. 2,
  25. $connect
  26. ->table('role')
  27. ->insert([
  28. 'name' => '版主',
  29. ])
  30. );
  31. $this->assertSame(
  32. 3,
  33. $connect
  34. ->table('role')
  35. ->insert([
  36. 'name' => '会员',
  37. ])
  38. );
  39. $this->assertSame(
  40. 1,
  41. $connect
  42. ->table('user_role')
  43. ->insert([
  44. 'user_id' => 1,
  45. 'role_id' => 1,
  46. ])
  47. );
  48. $this->assertSame(
  49. 2,
  50. $connect
  51. ->table('user_role')
  52. ->insert([
  53. 'user_id' => 1,
  54. 'role_id' => 3,
  55. ])
  56. );
  57. $user = User::select()->where('id', 1)->findOne();
  58. $this->assertSame(1, $user->id);
  59. $this->assertSame(1, $user['id']);
  60. $this->assertSame(1, $user->getId());
  61. $this->assertSame('niu', $user->name);
  62. $this->assertSame('niu', $user['name']);
  63. $this->assertSame('niu', $user->getName());
  64. $role = $user->role;
  65. $this->assertInstanceof(Collection::class, $role);
  66. $role1 = $role[0];
  67. $this->assertInstanceof(Role::class, $role1);
  68. $this->assertSame(1, $role1->id);
  69. $this->assertSame(1, $role1['id']);
  70. $this->assertSame(1, $role1->getId());
  71. $this->assertSame('管理员', $role1->name);
  72. $this->assertSame('管理员', $role1['name']);
  73. $this->assertSame('管理员', $role1->getName());
  74. $role2 = $role[1];
  75. $this->assertSame(3, $role2->id);
  76. $this->assertSame(3, $role2['id']);
  77. $this->assertSame(3, $role2->getId());
  78. $this->assertSame('会员', $role2->name);
  79. $this->assertSame('会员', $role2['name']);
  80. $this->assertSame('会员', $role2->getName());
  81. $this->assertCount(2, $role);
  82. $this->assertSame(1, $role[0]['id']);
  83. $this->assertSame('管理员', $role[0]['name']);
  84. $this->assertSame(3, $role[1]['id']);
  85. $this->assertSame('会员', $role[1]['name']);
  86. $middle = $role[0]->middle();
  87. $this->assertInstanceof(UserRole::class, $middle);
  88. $this->assertSame(1, $middle->userId);
  89. $this->assertSame(1, $middle->roleId);
  90. $middle = $role[1]->middle();
  91. $this->assertInstanceof(UserRole::class, $middle);
  92. $this->assertSame(1, $middle->userId);
  93. $this->assertSame(3, $middle->roleId);
  94. }

eager 预加载关联

  1. public function testEager(): void
  2. {
  3. $user = User::select()->where('id', 1)->findOne();
  4. $this->assertInstanceof(User::class, $user);
  5. $this->assertNull($user->id);
  6. $connect = $this->createDatabaseConnect();
  7. $this->assertSame(
  8. 1,
  9. $connect
  10. ->table('user')
  11. ->insert([
  12. 'name' => 'niu',
  13. ])
  14. );
  15. $this->assertSame(
  16. 1,
  17. $connect
  18. ->table('role')
  19. ->insert([
  20. 'name' => '管理员',
  21. ])
  22. );
  23. $this->assertSame(
  24. 2,
  25. $connect
  26. ->table('role')
  27. ->insert([
  28. 'name' => '版主',
  29. ])
  30. );
  31. $this->assertSame(
  32. 3,
  33. $connect
  34. ->table('role')
  35. ->insert([
  36. 'name' => '会员',
  37. ])
  38. );
  39. $this->assertSame(
  40. 1,
  41. $connect
  42. ->table('user_role')
  43. ->insert([
  44. 'user_id' => 1,
  45. 'role_id' => 1,
  46. ])
  47. );
  48. $this->assertSame(
  49. 2,
  50. $connect
  51. ->table('user_role')
  52. ->insert([
  53. 'user_id' => 1,
  54. 'role_id' => 3,
  55. ])
  56. );
  57. $user = User::eager(['role'])
  58. ->where('id', 1)
  59. ->findOne();
  60. $this->assertSame(1, $user->id);
  61. $this->assertSame(1, $user['id']);
  62. $this->assertSame(1, $user->getId());
  63. $this->assertSame('niu', $user->name);
  64. $this->assertSame('niu', $user['name']);
  65. $this->assertSame('niu', $user->getName());
  66. $role = $user->role;
  67. $this->assertInstanceof(Collection::class, $role);
  68. $role1 = $role[0];
  69. $this->assertInstanceof(Role::class, $role1);
  70. $this->assertSame(1, $role1->id);
  71. $this->assertSame(1, $role1['id']);
  72. $this->assertSame(1, $role1->getId());
  73. $this->assertSame('管理员', $role1->name);
  74. $this->assertSame('管理员', $role1['name']);
  75. $this->assertSame('管理员', $role1->getName());
  76. $role2 = $role[1];
  77. $this->assertInstanceof(Role::class, $role2);
  78. $this->assertSame(3, $role2->id);
  79. $this->assertSame(3, $role2['id']);
  80. $this->assertSame(3, $role2->getId());
  81. $this->assertSame('会员', $role2->name);
  82. $this->assertSame('会员', $role2['name']);
  83. $this->assertSame('会员', $role2->getName());
  84. $this->assertCount(2, $role);
  85. $this->assertSame(1, $role[0]['id']);
  86. $this->assertSame('管理员', $role[0]['name']);
  87. $this->assertSame(3, $role[1]['id']);
  88. $this->assertSame('会员', $role[1]['name']);
  89. $middle = $role[0]->middle();
  90. $this->assertSame(1, $middle->userId);
  91. $this->assertSame(1, $middle->roleId);
  92. $middle = $role[1]->middle();
  93. $this->assertSame(1, $middle->userId);
  94. $this->assertSame(3, $middle->roleId);
  95. }

eager 预加载关联支持查询条件过滤

  1. public function testEagerWithCondition(): void
  2. {
  3. $user = User::select()->where('id', 1)->findOne();
  4. $this->assertInstanceof(User::class, $user);
  5. $this->assertNull($user->id);
  6. $connect = $this->createDatabaseConnect();
  7. $this->assertSame(
  8. 1,
  9. $connect
  10. ->table('user')
  11. ->insert([
  12. 'name' => 'niu',
  13. ])
  14. );
  15. $this->assertSame(
  16. 1,
  17. $connect
  18. ->table('role')
  19. ->insert([
  20. 'name' => '管理员',
  21. ])
  22. );
  23. $this->assertSame(
  24. 2,
  25. $connect
  26. ->table('role')
  27. ->insert([
  28. 'name' => '版主',
  29. ])
  30. );
  31. $this->assertSame(
  32. 3,
  33. $connect
  34. ->table('role')
  35. ->insert([
  36. 'name' => '会员',
  37. ])
  38. );
  39. $this->assertSame(
  40. 1,
  41. $connect
  42. ->table('user_role')
  43. ->insert([
  44. 'user_id' => 1,
  45. 'role_id' => 1,
  46. ])
  47. );
  48. $this->assertSame(
  49. 2,
  50. $connect
  51. ->table('user_role')
  52. ->insert([
  53. 'user_id' => 1,
  54. 'role_id' => 3,
  55. ])
  56. );
  57. $user = User::eager(['role' => function (Relation $select) {
  58. $select->where('id', '>', 99999);
  59. }])
  60. ->where('id', 1)
  61. ->findOne();
  62. $this->assertSame(1, $user->id);
  63. $this->assertSame(1, $user['id']);
  64. $this->assertSame(1, $user->getId());
  65. $this->assertSame('niu', $user->name);
  66. $this->assertSame('niu', $user['name']);
  67. $this->assertSame('niu', $user->getName());
  68. $role = $user->role;
  69. $this->assertInstanceof(Collection::class, $role);
  70. $this->assertCount(0, $role);
  71. }

relation 读取关联

  1. public function testRelationAsMethod(): void
  2. {
  3. $connect = $this->createDatabaseConnect();
  4. $this->assertSame(
  5. 1,
  6. $connect
  7. ->table('user')
  8. ->insert([
  9. 'name' => 'niu',
  10. ])
  11. );
  12. $this->assertSame(
  13. 1,
  14. $connect
  15. ->table('role')
  16. ->insert([
  17. 'name' => '管理员',
  18. ])
  19. );
  20. $this->assertSame(
  21. 2,
  22. $connect
  23. ->table('role')
  24. ->insert([
  25. 'name' => '版主',
  26. ])
  27. );
  28. $this->assertSame(
  29. 3,
  30. $connect
  31. ->table('role')
  32. ->insert([
  33. 'name' => '会员',
  34. ])
  35. );
  36. $this->assertSame(
  37. 1,
  38. $connect
  39. ->table('user_role')
  40. ->insert([
  41. 'user_id' => 1,
  42. 'role_id' => 1,
  43. ])
  44. );
  45. $this->assertSame(
  46. 2,
  47. $connect
  48. ->table('user_role')
  49. ->insert([
  50. 'user_id' => 1,
  51. 'role_id' => 3,
  52. ])
  53. );
  54. $roleRelation = User::make()->relation('role');
  55. $this->assertInstanceof(ManyMany::class, $roleRelation);
  56. $this->assertSame('id', $roleRelation->getSourceKey());
  57. $this->assertSame('id', $roleRelation->getTargetKey());
  58. $this->assertSame('user_id', $roleRelation->getMiddleSourceKey());
  59. $this->assertSame('role_id', $roleRelation->getMiddleTargetKey());
  60. $this->assertInstanceof(User::class, $roleRelation->getSourceEntity());
  61. $this->assertInstanceof(Role::class, $roleRelation->getTargetEntity());
  62. $this->assertInstanceof(UserRole::class, $roleRelation->getMiddleEntity());
  63. $this->assertInstanceof(Select::class, $roleRelation->getSelect());
  64. }

relation 关联模型数据不存在返回空集合

  1. public function testRelationDataWasNotFound(): void
  2. {
  3. $user = User::select()->where('id', 1)->findOne();
  4. $this->assertInstanceof(User::class, $user);
  5. $this->assertNull($user->id);
  6. $connect = $this->createDatabaseConnect();
  7. $this->assertSame(
  8. 1,
  9. $connect
  10. ->table('user')
  11. ->insert([
  12. 'name' => 'niu',
  13. ])
  14. );
  15. $this->assertSame(
  16. 1,
  17. $connect
  18. ->table('role')
  19. ->insert([
  20. 'name' => '管理员',
  21. ])
  22. );
  23. $this->assertSame(
  24. 2,
  25. $connect
  26. ->table('role')
  27. ->insert([
  28. 'name' => '版主',
  29. ])
  30. );
  31. $this->assertSame(
  32. 3,
  33. $connect
  34. ->table('role')
  35. ->insert([
  36. 'name' => '会员',
  37. ])
  38. );
  39. $user = User::select()->where('id', 1)->findOne();
  40. $this->assertSame(1, $user->id);
  41. $this->assertSame(1, $user['id']);
  42. $this->assertSame(1, $user->getId());
  43. $this->assertSame('niu', $user->name);
  44. $this->assertSame('niu', $user['name']);
  45. $this->assertSame('niu', $user->getName());
  46. $role = $user->role;
  47. $this->assertInstanceof(Collection::class, $role);
  48. $this->assertCount(0, $role);
  49. }

关联软删除

fixture 定义

Tests\Database\Ddd\Entity\Relation\User

  1. namespace Tests\Database\Ddd\Entity\Relation;
  2. use Leevel\Database\Ddd\Entity;
  3. use Leevel\Database\Ddd\GetterSetter;
  4. use Leevel\Database\Ddd\Relation\ManyMany;
  5. class User extends Entity
  6. {
  7. use GetterSetter;
  8. const TABLE = 'user';
  9. const ID = 'id';
  10. const AUTO = 'id';
  11. const STRUCT = [
  12. 'id' => [],
  13. 'name' => [],
  14. 'create_at' => [],
  15. 'role' => [
  16. self::MANY_MANY => Role::class,
  17. self::MIDDLE_ENTITY => UserRole::class,
  18. self::SOURCE_KEY => 'id',
  19. self::TARGET_KEY => 'id',
  20. self::MIDDLE_SOURCE_KEY => 'user_id',
  21. self::MIDDLE_TARGET_KEY => 'role_id',
  22. ],
  23. 'role_soft_deleted' => [
  24. self::MANY_MANY => RoleSoftDeleted::class,
  25. self::MIDDLE_ENTITY => UserRoleSoftDeleted::class,
  26. self::SOURCE_KEY => 'id',
  27. self::TARGET_KEY => 'id',
  28. self::MIDDLE_SOURCE_KEY => 'user_id',
  29. self::MIDDLE_TARGET_KEY => 'role_id',
  30. ],
  31. 'role_middle_with_soft_deleted' => [
  32. self::MANY_MANY => RoleSoftDeleted::class,
  33. self::MIDDLE_ENTITY => UserRoleSoftDeleted::class,
  34. self::SOURCE_KEY => 'id',
  35. self::TARGET_KEY => 'id',
  36. self::MIDDLE_SOURCE_KEY => 'user_id',
  37. self::MIDDLE_TARGET_KEY => 'role_id',
  38. self::RELATION_SCOPE => 'withSoftDeleted',
  39. ],
  40. 'role_middle_only_soft_deleted' => [
  41. self::MANY_MANY => RoleSoftDeleted::class,
  42. self::MIDDLE_ENTITY => UserRoleSoftDeleted::class,
  43. self::SOURCE_KEY => 'id',
  44. self::TARGET_KEY => 'id',
  45. self::MIDDLE_SOURCE_KEY => 'user_id',
  46. self::MIDDLE_TARGET_KEY => 'role_id',
  47. self::RELATION_SCOPE => 'onlySoftDeleted',
  48. ],
  49. 'role_relation_scope_not_found' => [
  50. self::MANY_MANY => RoleSoftDeleted::class,
  51. self::MIDDLE_ENTITY => UserRoleSoftDeleted::class,
  52. self::SOURCE_KEY => 'id',
  53. self::TARGET_KEY => 'id',
  54. self::MIDDLE_SOURCE_KEY => 'user_id',
  55. self::MIDDLE_TARGET_KEY => 'role_id',
  56. self::RELATION_SCOPE => 'notFound',
  57. ],
  58. 'role_relation_scope_found_but_private' => [
  59. self::MANY_MANY => RoleSoftDeleted::class,
  60. self::MIDDLE_ENTITY => UserRoleSoftDeleted::class,
  61. self::SOURCE_KEY => 'id',
  62. self::TARGET_KEY => 'id',
  63. self::MIDDLE_SOURCE_KEY => 'user_id',
  64. self::MIDDLE_TARGET_KEY => 'role_id',
  65. self::RELATION_SCOPE => 'foundButPrivate',
  66. ],
  67. 'role_not_defined_middle_entity' => [
  68. self::MANY_MANY => Role::class,
  69. self::SOURCE_KEY => 'id',
  70. self::TARGET_KEY => 'id',
  71. self::MIDDLE_SOURCE_KEY => 'user_id',
  72. self::MIDDLE_TARGET_KEY => 'role_id',
  73. ],
  74. 'role_not_defined_source_key' => [
  75. self::MANY_MANY => Role::class,
  76. self::MIDDLE_ENTITY => UserRole::class,
  77. self::TARGET_KEY => 'id',
  78. self::MIDDLE_SOURCE_KEY => 'user_id',
  79. self::MIDDLE_TARGET_KEY => 'role_id',
  80. ],
  81. 'role_not_defined_target_key' => [
  82. self::MANY_MANY => Role::class,
  83. self::MIDDLE_ENTITY => UserRole::class,
  84. self::SOURCE_KEY => 'id',
  85. self::MIDDLE_SOURCE_KEY => 'user_id',
  86. self::MIDDLE_TARGET_KEY => 'role_id',
  87. ],
  88. 'role_not_defined_middle_source_key' => [
  89. self::MANY_MANY => Role::class,
  90. self::MIDDLE_ENTITY => UserRole::class,
  91. self::SOURCE_KEY => 'id',
  92. self::TARGET_KEY => 'id',
  93. self::MIDDLE_TARGET_KEY => 'role_id',
  94. ],
  95. 'role_not_defined_middle_target_key' => [
  96. self::MANY_MANY => Role::class,
  97. self::MIDDLE_ENTITY => UserRole::class,
  98. self::SOURCE_KEY => 'id',
  99. self::TARGET_KEY => 'id',
  100. self::MIDDLE_SOURCE_KEY => 'user_id',
  101. ],
  102. 'role_middle_field' => [
  103. self::MANY_MANY => Role::class,
  104. self::MIDDLE_ENTITY => UserRole::class,
  105. self::SOURCE_KEY => 'id',
  106. self::TARGET_KEY => 'id',
  107. self::MIDDLE_SOURCE_KEY => 'user_id',
  108. self::MIDDLE_TARGET_KEY => 'role_id',
  109. self::RELATION_SCOPE => 'middleField',
  110. ],
  111. 'role_middle_only_soft_deleted_and_middle_field_and_other_table_condition' => [
  112. self::MANY_MANY => RoleSoftDeleted::class,
  113. self::MIDDLE_ENTITY => UserRoleSoftDeleted::class,
  114. self::SOURCE_KEY => 'id',
  115. self::TARGET_KEY => 'id',
  116. self::MIDDLE_SOURCE_KEY => 'user_id',
  117. self::MIDDLE_TARGET_KEY => 'role_id',
  118. self::RELATION_SCOPE => 'middleOnlySoftDeletedAndMiddleFieldAndOtherTableCondition',
  119. ],
  120. ];
  121. protected function relationScopeWithSoftDeleted(ManyMany $relation): void
  122. {
  123. $relation->middleWithSoftDeleted();
  124. }
  125. protected function relationScopeOnlySoftDeleted(ManyMany $relation): void
  126. {
  127. $relation->middleOnlySoftDeleted();
  128. }
  129. protected function relationScopeMiddleField(ManyMany $relation): void
  130. {
  131. $relation->middleField(['create_at', 'middle_id' => 'id']);
  132. }
  133. protected function relationScopeMiddleOnlySoftDeletedAndMiddleFieldAndOtherTableCondition(ManyMany $relation): void
  134. {
  135. $relation
  136. ->middleOnlySoftDeleted()
  137. ->middleField(['create_at', 'middle_id' => 'id'])
  138. ->setColumns('id,name')
  139. ->where('id', '>', 3);
  140. }
  141. private function relationScopeFoundButPrivate(ManyMany $relation): void
  142. {
  143. }
  144. }

Tests\Database\Ddd\Entity\Relation\UserRoleSoftDeleted

  1. namespace Tests\Database\Ddd\Entity\Relation;
  2. use Leevel\Database\Ddd\Entity;
  3. use Leevel\Database\Ddd\GetterSetter;
  4. class UserRoleSoftDeleted extends Entity
  5. {
  6. use GetterSetter;
  7. const TABLE = 'user_role_soft_deleted';
  8. const ID = 'id';
  9. const AUTO = 'id';
  10. const STRUCT = [
  11. 'id' => [],
  12. 'user_id' => [],
  13. 'role_id' => [],
  14. 'create_at' => [],
  15. 'delete_at' => [
  16. self::CREATE_FILL => 0,
  17. ],
  18. ];
  19. const DELETE_AT = 'delete_at';
  20. }

Tests\Database\Ddd\Entity\Relation\RoleSoftDeleted

  1. namespace Tests\Database\Ddd\Entity\Relation;
  2. use Leevel\Database\Ddd\Entity;
  3. use Leevel\Database\Ddd\GetterSetter;
  4. class RoleSoftDeleted extends Entity
  5. {
  6. use GetterSetter;
  7. const TABLE = 'role_soft_deleted';
  8. const ID = 'id';
  9. const AUTO = 'id';
  10. const STRUCT = [
  11. 'id' => [],
  12. 'name' => [],
  13. 'create_at' => [],
  14. 'delete_at' => [
  15. self::CREATE_FILL => 0,
  16. ],
  17. ];
  18. const DELETE_AT = 'delete_at';
  19. }
  1. public function testSoftDeleted(): void
  2. {
  3. $user = User::select()->where('id', 1)->findOne();
  4. $this->assertInstanceof(User::class, $user);
  5. $this->assertNull($user->id);
  6. $connect = $this->createDatabaseConnect();
  7. $this->assertSame(
  8. 1,
  9. $connect
  10. ->table('user')
  11. ->insert([
  12. 'name' => 'niu',
  13. ])
  14. );
  15. $this->assertSame(
  16. 1,
  17. $connect
  18. ->table('role_soft_deleted')
  19. ->insert([
  20. 'name' => '管理员',
  21. ])
  22. );
  23. $this->assertSame(
  24. 2,
  25. $connect
  26. ->table('role_soft_deleted')
  27. ->insert([
  28. 'name' => '版主',
  29. ])
  30. );
  31. $this->assertSame(
  32. 3,
  33. $connect
  34. ->table('role_soft_deleted')
  35. ->insert([
  36. 'name' => '会员',
  37. ])
  38. );
  39. $this->assertSame(
  40. 1,
  41. $connect
  42. ->table('user_role_soft_deleted')
  43. ->insert([
  44. 'user_id' => 1,
  45. 'role_id' => 1,
  46. ])
  47. );
  48. $this->assertSame(
  49. 2,
  50. $connect
  51. ->table('user_role_soft_deleted')
  52. ->insert([
  53. 'user_id' => 1,
  54. 'role_id' => 3,
  55. ])
  56. );
  57. $user = User::select()->where('id', 1)->findOne();
  58. $sql = <<<'eot'
  59. SQL: [64] SELECT `user`.* FROM `user` WHERE `user`.`id` = :user_id LIMIT 1 | Params: 1 | Key: Name: [8] :user_id | paramno=0 | name=[8] ":user_id" | is_param=1 | param_type=1 (SELECT `user`.* FROM `user` WHERE `user`.`id` = 1 LIMIT 1)
  60. eot;
  61. $this->assertSame(
  62. $sql,
  63. User::select()->getLastSql(),
  64. );
  65. $this->assertSame(1, $user->id);
  66. $this->assertSame(1, $user['id']);
  67. $this->assertSame(1, $user->getId());
  68. $this->assertSame('niu', $user->name);
  69. $this->assertSame('niu', $user['name']);
  70. $this->assertSame('niu', $user->getName());
  71. $role = $user->roleSoftDeleted;
  72. $sql = <<<'eot'
  73. SQL: [490] SELECT `role_soft_deleted`.*,`user_role_soft_deleted`.`role_id` AS `middle_role_id`,`user_role_soft_deleted`.`user_id` AS `middle_user_id` FROM `role_soft_deleted` INNER JOIN `user_role_soft_deleted` ON `user_role_soft_deleted`.`role_id` = `role_soft_deleted`.`id` AND `user_role_soft_deleted`.`delete_at` = :user_role_soft_deleted_delete_at WHERE `role_soft_deleted`.`delete_at` = :role_soft_deleted_delete_at AND `user_role_soft_deleted`.`user_id` IN (:user_role_soft_deleted_user_id_in0) | Params: 3 | Key: Name: [33] :user_role_soft_deleted_delete_at | paramno=0 | name=[33] ":user_role_soft_deleted_delete_at" | is_param=1 | param_type=1 | Key: Name: [28] :role_soft_deleted_delete_at | paramno=1 | name=[28] ":role_soft_deleted_delete_at" | is_param=1 | param_type=1 | Key: Name: [35] :user_role_soft_deleted_user_id_in0 | paramno=2 | name=[35] ":user_role_soft_deleted_user_id_in0" | is_param=1 | param_type=1 (SELECT `role_soft_deleted`.*,`user_role_soft_deleted`.`role_id` AS `middle_role_id`,`user_role_soft_deleted`.`user_id` AS `middle_user_id` FROM `role_soft_deleted` INNER JOIN `user_role_soft_deleted` ON `user_role_soft_deleted`.`role_id` = `role_soft_deleted`.`id` AND `user_role_soft_deleted`.`delete_at` = 0 WHERE `role_soft_deleted`.`delete_at` = 0 AND `user_role_soft_deleted`.`user_id` IN (1))
  74. eot;
  75. $this->assertSame(
  76. $sql,
  77. User::select()->getLastSql(),
  78. );
  79. $this->assertInstanceof(Collection::class, $role);
  80. $role1 = $role[0];
  81. $this->assertInstanceof(RoleSoftDeleted::class, $role1);
  82. $this->assertSame(1, $role1->id);
  83. $this->assertSame(1, $role1['id']);
  84. $this->assertSame(1, $role1->getId());
  85. $this->assertSame('管理员', $role1->name);
  86. $this->assertSame('管理员', $role1['name']);
  87. $this->assertSame('管理员', $role1->getName());
  88. $role2 = $role[1];
  89. $this->assertInstanceof(RoleSoftDeleted::class, $role2);
  90. $this->assertSame(3, $role2->id);
  91. $this->assertSame(3, $role2['id']);
  92. $this->assertSame(3, $role2->getId());
  93. $this->assertSame('会员', $role2->name);
  94. $this->assertSame('会员', $role2['name']);
  95. $this->assertSame('会员', $role2->getName());
  96. $this->assertCount(2, $role);
  97. $this->assertSame(1, $role[0]['id']);
  98. $this->assertSame('管理员', $role[0]['name']);
  99. $this->assertSame(3, $role[1]['id']);
  100. $this->assertSame('会员', $role[1]['name']);
  101. $middle = $role[0]->middle();
  102. $this->assertInstanceof(UserRoleSoftDeleted::class, $middle);
  103. $this->assertSame(1, $middle->userId);
  104. $this->assertSame(1, $middle->roleId);
  105. $middle = $role[1]->middle();
  106. $this->assertInstanceof(UserRoleSoftDeleted::class, $middle);
  107. $this->assertSame(1, $middle->userId);
  108. $this->assertSame(3, $middle->roleId);
  109. }

middleWithSoftDeleted 中间实体包含软删除数据的数据库查询集合对象

通过关联作用域来设置中间实体包含软删除数据的数据库查询集合对象。

fixture 定义

  1. # Tests\Database\Ddd\Entity\Relation\User::relationScopeWithSoftDeleted
  2. protected function relationScopeWithSoftDeleted(ManyMany $relation): void
  3. {
  4. $relation->middleWithSoftDeleted();
  5. }
  1. public function testWithMiddleSoftDeletedAndMiddleEntityHasSoftDeleted(): void
  2. {
  3. $user = User::select()->where('id', 1)->findOne();
  4. $this->assertInstanceof(User::class, $user);
  5. $this->assertNull($user->id);
  6. $connect = $this->createDatabaseConnect();
  7. $this->assertSame(
  8. 1,
  9. $connect
  10. ->table('user')
  11. ->insert([
  12. 'name' => 'niu',
  13. ])
  14. );
  15. $this->assertSame(
  16. 1,
  17. $connect
  18. ->table('role_soft_deleted')
  19. ->insert([
  20. 'name' => '管理员',
  21. ])
  22. );
  23. $this->assertSame(
  24. 2,
  25. $connect
  26. ->table('role_soft_deleted')
  27. ->insert([
  28. 'name' => '版主',
  29. ])
  30. );
  31. $this->assertSame(
  32. 3,
  33. $connect
  34. ->table('role_soft_deleted')
  35. ->insert([
  36. 'name' => '会员',
  37. ])
  38. );
  39. $this->assertSame(
  40. 1,
  41. $connect
  42. ->table('user_role_soft_deleted')
  43. ->insert([
  44. 'user_id' => 1,
  45. 'role_id' => 1,
  46. ])
  47. );
  48. $this->assertSame(
  49. 2,
  50. $connect
  51. ->table('user_role_soft_deleted')
  52. ->insert([
  53. 'user_id' => 1,
  54. 'role_id' => 3,
  55. 'delete_at' => time(),
  56. ])
  57. );
  58. $user = User::select()->where('id', 1)->findOne();
  59. $sql = <<<'eot'
  60. SQL: [64] SELECT `user`.* FROM `user` WHERE `user`.`id` = :user_id LIMIT 1 | Params: 1 | Key: Name: [8] :user_id | paramno=0 | name=[8] ":user_id" | is_param=1 | param_type=1 (SELECT `user`.* FROM `user` WHERE `user`.`id` = 1 LIMIT 1)
  61. eot;
  62. $this->assertSame(
  63. $sql,
  64. User::select()->getLastSql(),
  65. );
  66. $this->assertSame(1, $user->id);
  67. $this->assertSame(1, $user['id']);
  68. $this->assertSame(1, $user->getId());
  69. $this->assertSame('niu', $user->name);
  70. $this->assertSame('niu', $user['name']);
  71. $this->assertSame('niu', $user->getName());
  72. $role = $user->roleMiddleWithSoftDeleted;
  73. $sql = <<<'eot'
  74. SQL: [413] SELECT `role_soft_deleted`.*,`user_role_soft_deleted`.`role_id` AS `middle_role_id`,`user_role_soft_deleted`.`user_id` AS `middle_user_id` FROM `role_soft_deleted` INNER JOIN `user_role_soft_deleted` ON `user_role_soft_deleted`.`role_id` = `role_soft_deleted`.`id` WHERE `role_soft_deleted`.`delete_at` = :role_soft_deleted_delete_at AND `user_role_soft_deleted`.`user_id` IN (:user_role_soft_deleted_user_id_in0) | Params: 2 | Key: Name: [28] :role_soft_deleted_delete_at | paramno=0 | name=[28] ":role_soft_deleted_delete_at" | is_param=1 | param_type=1 | Key: Name: [35] :user_role_soft_deleted_user_id_in0 | paramno=1 | name=[35] ":user_role_soft_deleted_user_id_in0" | is_param=1 | param_type=1 (SELECT `role_soft_deleted`.*,`user_role_soft_deleted`.`role_id` AS `middle_role_id`,`user_role_soft_deleted`.`user_id` AS `middle_user_id` FROM `role_soft_deleted` INNER JOIN `user_role_soft_deleted` ON `user_role_soft_deleted`.`role_id` = `role_soft_deleted`.`id` WHERE `role_soft_deleted`.`delete_at` = 0 AND `user_role_soft_deleted`.`user_id` IN (1))
  75. eot;
  76. $this->assertSame(
  77. $sql,
  78. User::select()->getLastSql(),
  79. );
  80. $this->assertInstanceof(Collection::class, $role);
  81. $role1 = $role[0];
  82. $this->assertInstanceof(RoleSoftDeleted::class, $role1);
  83. $this->assertSame(1, $role1->id);
  84. $this->assertSame(1, $role1['id']);
  85. $this->assertSame(1, $role1->getId());
  86. $this->assertSame('管理员', $role1->name);
  87. $this->assertSame('管理员', $role1['name']);
  88. $this->assertSame('管理员', $role1->getName());
  89. $role2 = $role[1];
  90. $this->assertInstanceof(RoleSoftDeleted::class, $role2);
  91. $this->assertSame(3, $role2->id);
  92. $this->assertSame(3, $role2['id']);
  93. $this->assertSame(3, $role2->getId());
  94. $this->assertSame('会员', $role2->name);
  95. $this->assertSame('会员', $role2['name']);
  96. $this->assertSame('会员', $role2->getName());
  97. $this->assertCount(2, $role);
  98. $this->assertSame(1, $role[0]['id']);
  99. $this->assertSame('管理员', $role[0]['name']);
  100. $this->assertSame(3, $role[1]['id']);
  101. $this->assertSame('会员', $role[1]['name']);
  102. $middle = $role[0]->middle();
  103. $this->assertInstanceof(UserRoleSoftDeleted::class, $middle);
  104. $this->assertSame(1, $middle->userId);
  105. $this->assertSame(1, $middle->roleId);
  106. $middle = $role[1]->middle();
  107. $this->assertInstanceof(UserRoleSoftDeleted::class, $middle);
  108. $this->assertSame(1, $middle->userId);
  109. $this->assertSame(3, $middle->roleId);
  110. }

middleOnlySoftDeleted 中间实体仅仅包含软删除数据的数据库查询集合对象

通过关联作用域来设置中间实体仅仅包含软删除数据的数据库查询集合对象。

fixture 定义

  1. # Tests\Database\Ddd\Entity\Relation\User::relationScopeOnlySoftDeleted
  2. protected function relationScopeOnlySoftDeleted(ManyMany $relation): void
  3. {
  4. $relation->middleOnlySoftDeleted();
  5. }
  1. public function testOnlyMiddleSoftDeletedAndMiddleEntityHasSoftDeleted(): void
  2. {
  3. $user = User::select()->where('id', 1)->findOne();
  4. $this->assertInstanceof(User::class, $user);
  5. $this->assertNull($user->id);
  6. $connect = $this->createDatabaseConnect();
  7. $this->assertSame(
  8. 1,
  9. $connect
  10. ->table('user')
  11. ->insert([
  12. 'name' => 'niu',
  13. ])
  14. );
  15. $this->assertSame(
  16. 1,
  17. $connect
  18. ->table('role_soft_deleted')
  19. ->insert([
  20. 'name' => '管理员',
  21. ])
  22. );
  23. $this->assertSame(
  24. 2,
  25. $connect
  26. ->table('role_soft_deleted')
  27. ->insert([
  28. 'name' => '版主',
  29. ])
  30. );
  31. $this->assertSame(
  32. 3,
  33. $connect
  34. ->table('role_soft_deleted')
  35. ->insert([
  36. 'name' => '会员',
  37. ])
  38. );
  39. $this->assertSame(
  40. 1,
  41. $connect
  42. ->table('user_role_soft_deleted')
  43. ->insert([
  44. 'user_id' => 1,
  45. 'role_id' => 1,
  46. ])
  47. );
  48. $this->assertSame(
  49. 2,
  50. $connect
  51. ->table('user_role_soft_deleted')
  52. ->insert([
  53. 'user_id' => 1,
  54. 'role_id' => 3,
  55. 'delete_at' => time(),
  56. ])
  57. );
  58. $user = User::select()->where('id', 1)->findOne();
  59. $sql = <<<'eot'
  60. SQL: [64] SELECT `user`.* FROM `user` WHERE `user`.`id` = :user_id LIMIT 1 | Params: 1 | Key: Name: [8] :user_id | paramno=0 | name=[8] ":user_id" | is_param=1 | param_type=1 (SELECT `user`.* FROM `user` WHERE `user`.`id` = 1 LIMIT 1)
  61. eot;
  62. $this->assertSame(
  63. $sql,
  64. User::select()->getLastSql(),
  65. );
  66. $this->assertSame(1, $user->id);
  67. $this->assertSame(1, $user['id']);
  68. $this->assertSame(1, $user->getId());
  69. $this->assertSame('niu', $user->name);
  70. $this->assertSame('niu', $user['name']);
  71. $this->assertSame('niu', $user->getName());
  72. $role = $user->roleMiddleOnlySoftDeleted;
  73. $sql = <<<'eot'
  74. SQL: [490] SELECT `role_soft_deleted`.*,`user_role_soft_deleted`.`role_id` AS `middle_role_id`,`user_role_soft_deleted`.`user_id` AS `middle_user_id` FROM `role_soft_deleted` INNER JOIN `user_role_soft_deleted` ON `user_role_soft_deleted`.`role_id` = `role_soft_deleted`.`id` AND `user_role_soft_deleted`.`delete_at` > :user_role_soft_deleted_delete_at WHERE `role_soft_deleted`.`delete_at` = :role_soft_deleted_delete_at AND `user_role_soft_deleted`.`user_id` IN (:user_role_soft_deleted_user_id_in0) | Params: 3 | Key: Name: [33] :user_role_soft_deleted_delete_at | paramno=0 | name=[33] ":user_role_soft_deleted_delete_at" | is_param=1 | param_type=1 | Key: Name: [28] :role_soft_deleted_delete_at | paramno=1 | name=[28] ":role_soft_deleted_delete_at" | is_param=1 | param_type=1 | Key: Name: [35] :user_role_soft_deleted_user_id_in0 | paramno=2 | name=[35] ":user_role_soft_deleted_user_id_in0" | is_param=1 | param_type=1 (SELECT `role_soft_deleted`.*,`user_role_soft_deleted`.`role_id` AS `middle_role_id`,`user_role_soft_deleted`.`user_id` AS `middle_user_id` FROM `role_soft_deleted` INNER JOIN `user_role_soft_deleted` ON `user_role_soft_deleted`.`role_id` = `role_soft_deleted`.`id` AND `user_role_soft_deleted`.`delete_at` > 0 WHERE `role_soft_deleted`.`delete_at` = 0 AND `user_role_soft_deleted`.`user_id` IN (1))
  75. eot;
  76. $this->assertSame(
  77. $sql,
  78. User::select()->getLastSql(),
  79. );
  80. $this->assertInstanceof(Collection::class, $role);
  81. $role1 = $role[0];
  82. $this->assertInstanceof(RoleSoftDeleted::class, $role1);
  83. $this->assertSame(3, $role1->id);
  84. $this->assertSame(3, $role1['id']);
  85. $this->assertSame(3, $role1->getId());
  86. $this->assertSame('会员', $role1->name);
  87. $this->assertSame('会员', $role1['name']);
  88. $this->assertSame('会员', $role1->getName());
  89. $role2 = $role[1];
  90. $this->assertNull($role2);
  91. $this->assertCount(1, $role);
  92. $this->assertSame(3, $role[0]['id']);
  93. $this->assertSame('会员', $role[0]['name']);
  94. $this->assertNull($role[1]['id'] ?? null);
  95. $this->assertNull($role[1]['name'] ?? null);
  96. $middle = $role[0]->middle();
  97. $this->assertInstanceof(UserRoleSoftDeleted::class, $middle);
  98. $this->assertSame(1, $middle->userId);
  99. $this->assertSame(3, $middle->roleId);
  100. }

middleOnlySoftDeleted.middleField.where 组合条件查询例子

通过关联作用域来设置组合查询条件。

fixture 定义

  1. # Tests\Database\Ddd\Entity\Relation\User::relationScopeMiddleOnlySoftDeletedAndMiddleFieldAndOtherTableCondition
  2. protected function relationScopeMiddleOnlySoftDeletedAndMiddleFieldAndOtherTableCondition(ManyMany $relation): void
  3. {
  4. $relation
  5. ->middleOnlySoftDeleted()
  6. ->middleField(['create_at', 'middle_id' => 'id'])
  7. ->setColumns('id,name')
  8. ->where('id', '>', 3);
  9. }
  1. public function testMiddleOnlySoftDeletedAndMiddleFieldAndOtherTableCondition(): void
  2. {
  3. $user = User::select()->where('id', 1)->findOne();
  4. $this->assertInstanceof(User::class, $user);
  5. $this->assertNull($user->id);
  6. $connect = $this->createDatabaseConnect();
  7. $this->assertSame(
  8. 1,
  9. $connect
  10. ->table('user')
  11. ->insert([
  12. 'name' => 'niu',
  13. ])
  14. );
  15. $this->assertSame(
  16. 1,
  17. $connect
  18. ->table('role_soft_deleted')
  19. ->insert([
  20. 'name' => '管理员',
  21. ])
  22. );
  23. $this->assertSame(
  24. 2,
  25. $connect
  26. ->table('role_soft_deleted')
  27. ->insert([
  28. 'name' => '版主',
  29. ])
  30. );
  31. $this->assertSame(
  32. 3,
  33. $connect
  34. ->table('role_soft_deleted')
  35. ->insert([
  36. 'name' => '会员',
  37. ])
  38. );
  39. $this->assertSame(
  40. 1,
  41. $connect
  42. ->table('user_role_soft_deleted')
  43. ->insert([
  44. 'user_id' => 1,
  45. 'role_id' => 1,
  46. ])
  47. );
  48. $this->assertSame(
  49. 2,
  50. $connect
  51. ->table('user_role_soft_deleted')
  52. ->insert([
  53. 'user_id' => 1,
  54. 'role_id' => 3,
  55. 'delete_at' => time(),
  56. ])
  57. );
  58. $user = User::select()->where('id', 1)->findOne();
  59. $sql = <<<'eot'
  60. SQL: [64] SELECT `user`.* FROM `user` WHERE `user`.`id` = :user_id LIMIT 1 | Params: 1 | Key: Name: [8] :user_id | paramno=0 | name=[8] ":user_id" | is_param=1 | param_type=1 (SELECT `user`.* FROM `user` WHERE `user`.`id` = 1 LIMIT 1)
  61. eot;
  62. $this->assertSame(
  63. $sql,
  64. User::select()->getLastSql(),
  65. );
  66. $this->assertSame(1, $user->id);
  67. $this->assertSame(1, $user['id']);
  68. $this->assertSame(1, $user->getId());
  69. $this->assertSame('niu', $user->name);
  70. $this->assertSame('niu', $user['name']);
  71. $this->assertSame('niu', $user->getName());
  72. $role = $user->roleMiddleOnlySoftDeletedAndMiddleFieldAndOtherTableCondition;
  73. $sql = <<<'eot'
  74. SQL: [655] SELECT `role_soft_deleted`.`id`,`role_soft_deleted`.`name`,`user_role_soft_deleted`.`create_at`,`user_role_soft_deleted`.`id` AS `middle_id`,`user_role_soft_deleted`.`role_id` AS `middle_role_id`,`user_role_soft_deleted`.`user_id` AS `middle_user_id` FROM `role_soft_deleted` INNER JOIN `user_role_soft_deleted` ON `user_role_soft_deleted`.`role_id` = `role_soft_deleted`.`id` AND `user_role_soft_deleted`.`delete_at` > :user_role_soft_deleted_delete_at WHERE `role_soft_deleted`.`delete_at` = :role_soft_deleted_delete_at AND `role_soft_deleted`.`id` > :role_soft_deleted_id AND `user_role_soft_deleted`.`user_id` IN (:user_role_soft_deleted_user_id_in0) | Params: 4 | Key: Name: [33] :user_role_soft_deleted_delete_at | paramno=0 | name=[33] ":user_role_soft_deleted_delete_at" | is_param=1 | param_type=1 | Key: Name: [28] :role_soft_deleted_delete_at | paramno=1 | name=[28] ":role_soft_deleted_delete_at" | is_param=1 | param_type=1 | Key: Name: [21] :role_soft_deleted_id | paramno=2 | name=[21] ":role_soft_deleted_id" | is_param=1 | param_type=1 | Key: Name: [35] :user_role_soft_deleted_user_id_in0 | paramno=3 | name=[35] ":user_role_soft_deleted_user_id_in0" | is_param=1 | param_type=1 (SELECT `role_soft_deleted`.`id`,`role_soft_deleted`.`name`,`user_role_soft_deleted`.`create_at`,`user_role_soft_deleted`.`id` AS `middle_id`,`user_role_soft_deleted`.`role_id` AS `middle_role_id`,`user_role_soft_deleted`.`user_id` AS `middle_user_id` FROM `role_soft_deleted` INNER JOIN `user_role_soft_deleted` ON `user_role_soft_deleted`.`role_id` = `role_soft_deleted`.`id` AND `user_role_soft_deleted`.`delete_at` > 0 WHERE `role_soft_deleted`.`delete_at` = 0 AND `role_soft_deleted`.`id` > 3 AND `user_role_soft_deleted`.`user_id` IN (1))
  75. eot;
  76. $this->assertSame(
  77. $sql,
  78. User::select()->getLastSql(),
  79. );
  80. $this->assertInstanceof(Collection::class, $role);
  81. $this->assertFalse(isset($role[0]));
  82. }

middleField 中间实体查询字段

通过关联作用域来设置中间实体查询字段。

fixture 定义

  1. # Tests\Database\Ddd\Entity\Relation\User::relationScopeMiddleField
  2. protected function relationScopeMiddleField(ManyMany $relation): void
  3. {
  4. $relation->middleField(['create_at', 'middle_id' => 'id']);
  5. }
  1. public function testMiddleField(): void
  2. {
  3. $user = User::select()->where('id', 1)->findOne();
  4. $this->assertInstanceof(User::class, $user);
  5. $this->assertNull($user->id);
  6. $connect = $this->createDatabaseConnect();
  7. $this->assertSame(
  8. 1,
  9. $connect
  10. ->table('user')
  11. ->insert([
  12. 'name' => 'niu',
  13. ])
  14. );
  15. $this->assertSame(
  16. 1,
  17. $connect
  18. ->table('role')
  19. ->insert([
  20. 'name' => '管理员',
  21. ])
  22. );
  23. $this->assertSame(
  24. 2,
  25. $connect
  26. ->table('role')
  27. ->insert([
  28. 'name' => '版主',
  29. ])
  30. );
  31. $this->assertSame(
  32. 1,
  33. $connect
  34. ->table('user_role')
  35. ->insert([
  36. 'user_id' => 1,
  37. 'role_id' => 2,
  38. ])
  39. );
  40. $user = User::select()->where('id', 1)->findOne();
  41. $sql = <<<'eot'
  42. SQL: [64] SELECT `user`.* FROM `user` WHERE `user`.`id` = :user_id LIMIT 1 | Params: 1 | Key: Name: [8] :user_id | paramno=0 | name=[8] ":user_id" | is_param=1 | param_type=1 (SELECT `user`.* FROM `user` WHERE `user`.`id` = 1 LIMIT 1)
  43. eot;
  44. $this->assertSame(
  45. $sql,
  46. User::select()->getLastSql(),
  47. );
  48. $this->assertSame(1, $user->id);
  49. $this->assertSame(1, $user['id']);
  50. $this->assertSame(1, $user->getId());
  51. $this->assertSame('niu', $user->name);
  52. $this->assertSame('niu', $user['name']);
  53. $this->assertSame('niu', $user->getName());
  54. $role = $user->roleMiddleField;
  55. $sql = <<<'eot'
  56. SQL: [285] SELECT `role`.*,`user_role`.`create_at`,`user_role`.`id` AS `middle_id`,`user_role`.`role_id` AS `middle_role_id`,`user_role`.`user_id` AS `middle_user_id` FROM `role` INNER JOIN `user_role` ON `user_role`.`role_id` = `role`.`id` WHERE `user_role`.`user_id` IN (:user_role_user_id_in0) | Params: 1 | Key: Name: [22] :user_role_user_id_in0 | paramno=0 | name=[22] ":user_role_user_id_in0" | is_param=1 | param_type=1 (SELECT `role`.*,`user_role`.`create_at`,`user_role`.`id` AS `middle_id`,`user_role`.`role_id` AS `middle_role_id`,`user_role`.`user_id` AS `middle_user_id` FROM `role` INNER JOIN `user_role` ON `user_role`.`role_id` = `role`.`id` WHERE `user_role`.`user_id` IN (1))
  57. eot;
  58. $this->assertSame(
  59. $sql,
  60. User::select()->getLastSql(),
  61. );
  62. $this->assertInstanceof(Collection::class, $role);
  63. $this->assertCount(1, $role);
  64. $role1 = $role[0];
  65. $this->assertInstanceof(Role::class, $role1);
  66. $this->assertSame(2, $role1->id);
  67. $this->assertSame(2, $role1['id']);
  68. $this->assertSame(2, $role1->getId());
  69. $this->assertSame('版主', $role1->name);
  70. $this->assertSame('版主', $role1['name']);
  71. $this->assertSame('版主', $role1->getName());
  72. $middle = $role[0]->middle();
  73. $this->assertInstanceof(UserRole::class, $middle);
  74. $this->assertSame(1, $middle->userId);
  75. $this->assertSame(2, $middle->roleId);
  76. }