DatabaseEloquentGlobalScopesTest.php 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. <?php
  2. namespace Illuminate\Tests\Database;
  3. use Illuminate\Database\Capsule\Manager as DB;
  4. use Illuminate\Database\Eloquent\Builder;
  5. use Illuminate\Database\Eloquent\Model;
  6. use Illuminate\Database\Eloquent\Scope;
  7. use PHPUnit\Framework\TestCase;
  8. class DatabaseEloquentGlobalScopesTest extends TestCase
  9. {
  10. protected function setUp(): void
  11. {
  12. parent::setUp();
  13. tap(new DB)->addConnection([
  14. 'driver' => 'sqlite',
  15. 'database' => ':memory:',
  16. ])->bootEloquent();
  17. }
  18. protected function tearDown(): void
  19. {
  20. parent::tearDown();
  21. Model::unsetConnectionResolver();
  22. }
  23. public function testGlobalScopeIsApplied()
  24. {
  25. $model = new EloquentGlobalScopesTestModel;
  26. $query = $model->newQuery();
  27. $this->assertSame('select * from "table" where "active" = ?', $query->toSql());
  28. $this->assertEquals([1], $query->getBindings());
  29. }
  30. public function testGlobalScopeCanBeRemoved()
  31. {
  32. $model = new EloquentGlobalScopesTestModel;
  33. $query = $model->newQuery()->withoutGlobalScope(ActiveScope::class);
  34. $this->assertSame('select * from "table"', $query->toSql());
  35. $this->assertEquals([], $query->getBindings());
  36. }
  37. public function testClosureGlobalScopeIsApplied()
  38. {
  39. $model = new EloquentClosureGlobalScopesTestModel;
  40. $query = $model->newQuery();
  41. $this->assertSame('select * from "table" where "active" = ? order by "name" asc', $query->toSql());
  42. $this->assertEquals([1], $query->getBindings());
  43. }
  44. public function testClosureGlobalScopeCanBeRemoved()
  45. {
  46. $model = new EloquentClosureGlobalScopesTestModel;
  47. $query = $model->newQuery()->withoutGlobalScope('active_scope');
  48. $this->assertSame('select * from "table" order by "name" asc', $query->toSql());
  49. $this->assertEquals([], $query->getBindings());
  50. }
  51. public function testGlobalScopeCanBeRemovedAfterTheQueryIsExecuted()
  52. {
  53. $model = new EloquentClosureGlobalScopesTestModel;
  54. $query = $model->newQuery();
  55. $this->assertSame('select * from "table" where "active" = ? order by "name" asc', $query->toSql());
  56. $this->assertEquals([1], $query->getBindings());
  57. $query->withoutGlobalScope('active_scope');
  58. $this->assertSame('select * from "table" order by "name" asc', $query->toSql());
  59. $this->assertEquals([], $query->getBindings());
  60. }
  61. public function testAllGlobalScopesCanBeRemoved()
  62. {
  63. $model = new EloquentClosureGlobalScopesTestModel;
  64. $query = $model->newQuery()->withoutGlobalScopes();
  65. $this->assertSame('select * from "table"', $query->toSql());
  66. $this->assertEquals([], $query->getBindings());
  67. $query = EloquentClosureGlobalScopesTestModel::withoutGlobalScopes();
  68. $this->assertSame('select * from "table"', $query->toSql());
  69. $this->assertEquals([], $query->getBindings());
  70. }
  71. public function testGlobalScopesWithOrWhereConditionsAreNested()
  72. {
  73. $model = new EloquentClosureGlobalScopesWithOrTestModel;
  74. $query = $model->newQuery();
  75. $this->assertSame('select "email", "password" from "table" where ("email" = ? or "email" = ?) and "active" = ? order by "name" asc', $query->toSql());
  76. $this->assertEquals(['taylor@gmail.com', 'someone@else.com', 1], $query->getBindings());
  77. $query = $model->newQuery()->where('col1', 'val1')->orWhere('col2', 'val2');
  78. $this->assertSame('select "email", "password" from "table" where ("col1" = ? or "col2" = ?) and ("email" = ? or "email" = ?) and "active" = ? order by "name" asc', $query->toSql());
  79. $this->assertEquals(['val1', 'val2', 'taylor@gmail.com', 'someone@else.com', 1], $query->getBindings());
  80. }
  81. public function testRegularScopesWithOrWhereConditionsAreNested()
  82. {
  83. $query = EloquentClosureGlobalScopesTestModel::withoutGlobalScopes()->where('foo', 'foo')->orWhere('bar', 'bar')->approved();
  84. $this->assertSame('select * from "table" where ("foo" = ? or "bar" = ?) and ("approved" = ? or "should_approve" = ?)', $query->toSql());
  85. $this->assertEquals(['foo', 'bar', 1, 0], $query->getBindings());
  86. }
  87. public function testScopesStartingWithOrBooleanArePreserved()
  88. {
  89. $query = EloquentClosureGlobalScopesTestModel::withoutGlobalScopes()->where('foo', 'foo')->orWhere('bar', 'bar')->orApproved();
  90. $this->assertSame('select * from "table" where ("foo" = ? or "bar" = ?) or ("approved" = ? or "should_approve" = ?)', $query->toSql());
  91. $this->assertEquals(['foo', 'bar', 1, 0], $query->getBindings());
  92. }
  93. public function testHasQueryWhereBothModelsHaveGlobalScopes()
  94. {
  95. $query = EloquentGlobalScopesWithRelationModel::has('related')->where('bar', 'baz');
  96. $subQuery = 'select * from "table" where "table2"."id" = "table"."related_id" and "foo" = ? and "active" = ?';
  97. $mainQuery = 'select * from "table2" where exists ('.$subQuery.') and "bar" = ? and "active" = ? order by "name" asc';
  98. $this->assertEquals($mainQuery, $query->toSql());
  99. $this->assertEquals(['bar', 1, 'baz', 1], $query->getBindings());
  100. }
  101. }
  102. class EloquentClosureGlobalScopesTestModel extends Model
  103. {
  104. protected $table = 'table';
  105. public static function boot()
  106. {
  107. static::addGlobalScope(function ($query) {
  108. $query->orderBy('name');
  109. });
  110. static::addGlobalScope('active_scope', function ($query) {
  111. $query->where('active', 1);
  112. });
  113. parent::boot();
  114. }
  115. public function scopeApproved($query)
  116. {
  117. return $query->where('approved', 1)->orWhere('should_approve', 0);
  118. }
  119. public function scopeOrApproved($query)
  120. {
  121. return $query->orWhere('approved', 1)->orWhere('should_approve', 0);
  122. }
  123. }
  124. class EloquentGlobalScopesWithRelationModel extends EloquentClosureGlobalScopesTestModel
  125. {
  126. protected $table = 'table2';
  127. public function related()
  128. {
  129. return $this->hasMany(EloquentGlobalScopesTestModel::class, 'related_id')->where('foo', 'bar');
  130. }
  131. }
  132. class EloquentClosureGlobalScopesWithOrTestModel extends EloquentClosureGlobalScopesTestModel
  133. {
  134. public static function boot()
  135. {
  136. static::addGlobalScope('or_scope', function ($query) {
  137. $query->where('email', 'taylor@gmail.com')->orWhere('email', 'someone@else.com');
  138. });
  139. static::addGlobalScope(function ($query) {
  140. $query->select('email', 'password');
  141. });
  142. parent::boot();
  143. }
  144. }
  145. class EloquentGlobalScopesTestModel extends Model
  146. {
  147. protected $table = 'table';
  148. public static function boot()
  149. {
  150. static::addGlobalScope(new ActiveScope);
  151. parent::boot();
  152. }
  153. }
  154. class ActiveScope implements Scope
  155. {
  156. public function apply(Builder $builder, Model $model)
  157. {
  158. return $builder->where('active', 1);
  159. }
  160. }