DatabaseEloquentMorphOneOfManyTest.php 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. <?php
  2. namespace Illuminate\Tests\Database;
  3. use Illuminate\Database\Capsule\Manager as DB;
  4. use Illuminate\Database\Eloquent\Model as Eloquent;
  5. use PHPUnit\Framework\TestCase;
  6. class DatabaseEloquentMorphOneOfManyTest extends TestCase
  7. {
  8. protected function setUp(): void
  9. {
  10. $db = new DB;
  11. $db->addConnection([
  12. 'driver' => 'sqlite',
  13. 'database' => ':memory:',
  14. ]);
  15. $db->bootEloquent();
  16. $db->setAsGlobal();
  17. $this->createSchema();
  18. }
  19. /**
  20. * Setup the database schema.
  21. *
  22. * @return void
  23. */
  24. public function createSchema()
  25. {
  26. $this->schema()->create('products', function ($table) {
  27. $table->increments('id');
  28. });
  29. $this->schema()->create('states', function ($table) {
  30. $table->increments('id');
  31. $table->morphs('stateful');
  32. $table->string('state');
  33. $table->string('type')->nullable();
  34. });
  35. }
  36. /**
  37. * Tear down the database schema.
  38. *
  39. * @return void
  40. */
  41. protected function tearDown(): void
  42. {
  43. $this->schema()->drop('products');
  44. $this->schema()->drop('states');
  45. }
  46. public function testEagerLoadingAppliesConstraintsToInnerJoinSubQuery()
  47. {
  48. $product = MorphOneOfManyTestProduct::create();
  49. $relation = $product->current_state();
  50. $relation->addEagerConstraints([$product]);
  51. $this->assertSame('select MAX("states"."id") as "id_aggregate", "states"."stateful_id", "states"."stateful_type" from "states" where "states"."stateful_type" = ? and "states"."stateful_id" = ? and "states"."stateful_id" is not null and "states"."stateful_id" in (1) and "states"."stateful_type" = ? group by "states"."stateful_id", "states"."stateful_type"', $relation->getOneOfManySubQuery()->toSql());
  52. }
  53. public function testReceivingModel()
  54. {
  55. $product = MorphOneOfManyTestProduct::create();
  56. $product->states()->create([
  57. 'state' => 'draft',
  58. ]);
  59. $product->states()->create([
  60. 'state' => 'active',
  61. ]);
  62. $this->assertNotNull($product->current_state);
  63. $this->assertSame('active', $product->current_state->state);
  64. }
  65. public function testMorphType()
  66. {
  67. $product = MorphOneOfManyTestProduct::create();
  68. $product->states()->create([
  69. 'state' => 'draft',
  70. ]);
  71. $product->states()->create([
  72. 'state' => 'active',
  73. ]);
  74. $state = $product->states()->make([
  75. 'state' => 'foo',
  76. ]);
  77. $state->stateful_type = 'bar';
  78. $state->save();
  79. $this->assertNotNull($product->current_state);
  80. $this->assertSame('active', $product->current_state->state);
  81. }
  82. public function testForceCreateMorphType()
  83. {
  84. $product = MorphOneOfManyTestProduct::create();
  85. $state = $product->states()->forceCreate([
  86. 'state' => 'active',
  87. ]);
  88. $this->assertNotNull($state);
  89. $this->assertSame(MorphOneOfManyTestProduct::class, $product->current_state->stateful_type);
  90. }
  91. public function testExists()
  92. {
  93. $product = MorphOneOfManyTestProduct::create();
  94. $previousState = $product->states()->create([
  95. 'state' => 'draft',
  96. ]);
  97. $currentState = $product->states()->create([
  98. 'state' => 'active',
  99. ]);
  100. $exists = MorphOneOfManyTestProduct::whereHas('current_state', function ($q) use ($previousState) {
  101. $q->whereKey($previousState->getKey());
  102. })->exists();
  103. $this->assertFalse($exists);
  104. $exists = MorphOneOfManyTestProduct::whereHas('current_state', function ($q) use ($currentState) {
  105. $q->whereKey($currentState->getKey());
  106. })->exists();
  107. $this->assertTrue($exists);
  108. }
  109. public function testWithExists()
  110. {
  111. $product = MorphOneOfManyTestProduct::create();
  112. $product = MorphOneOfManyTestProduct::withExists('current_state')->first();
  113. $this->assertFalse($product->current_state_exists);
  114. $product->states()->create([
  115. 'state' => 'draft',
  116. ]);
  117. $product = MorphOneOfManyTestProduct::withExists('current_state')->first();
  118. $this->assertTrue($product->current_state_exists);
  119. }
  120. public function testWithExistsWithConstraintsInJoinSubSelect()
  121. {
  122. $product = MorphOneOfManyTestProduct::create();
  123. $product = MorphOneOfManyTestProduct::withExists('current_foo_state')->first();
  124. $this->assertFalse($product->current_foo_state_exists);
  125. $product->states()->create([
  126. 'state' => 'draft',
  127. 'type' => 'foo',
  128. ]);
  129. $product = MorphOneOfManyTestProduct::withExists('current_foo_state')->first();
  130. $this->assertTrue($product->current_foo_state_exists);
  131. }
  132. /**
  133. * Get a database connection instance.
  134. *
  135. * @return \Illuminate\Database\Connection
  136. */
  137. protected function connection()
  138. {
  139. return Eloquent::getConnectionResolver()->connection();
  140. }
  141. /**
  142. * Get a schema builder instance.
  143. *
  144. * @return \Illuminate\Database\Schema\Builder
  145. */
  146. protected function schema()
  147. {
  148. return $this->connection()->getSchemaBuilder();
  149. }
  150. }
  151. /**
  152. * Eloquent Models...
  153. */
  154. class MorphOneOfManyTestProduct extends Eloquent
  155. {
  156. protected $table = 'products';
  157. protected $guarded = [];
  158. public $timestamps = false;
  159. public function states()
  160. {
  161. return $this->morphMany(MorphOneOfManyTestState::class, 'stateful');
  162. }
  163. public function current_state()
  164. {
  165. return $this->morphOne(MorphOneOfManyTestState::class, 'stateful')->ofMany();
  166. }
  167. public function current_foo_state()
  168. {
  169. return $this->morphOne(MorphOneOfManyTestState::class, 'stateful')->ofMany(
  170. ['id' => 'max'],
  171. function ($q) {
  172. $q->where('type', 'foo');
  173. }
  174. );
  175. }
  176. }
  177. class MorphOneOfManyTestState extends Eloquent
  178. {
  179. protected $table = 'states';
  180. protected $guarded = [];
  181. public $timestamps = false;
  182. protected $fillable = ['state', 'type'];
  183. }