Skip to content

Commit

Permalink
Implement higher order orWhere for simpler scopes
Browse files Browse the repository at this point in the history
  • Loading branch information
erikgaal committed Jan 23, 2019
1 parent 8351049 commit 33eff6c
Show file tree
Hide file tree
Showing 3 changed files with 107 additions and 0 deletions.
20 changes: 20 additions & 0 deletions src/Illuminate/Database/Eloquent/Builder.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,20 @@
namespace Illuminate\Database\Eloquent;

use Closure;
use Exception;
use BadMethodCallException;
use Illuminate\Support\Arr;
use Illuminate\Support\Str;
use Illuminate\Pagination\Paginator;
use Illuminate\Contracts\Support\Arrayable;
use Illuminate\Support\Traits\ForwardsCalls;
use Illuminate\Database\Concerns\BuildsQueries;
use Illuminate\Support\HigherOrderBuilderProxy;
use Illuminate\Database\Eloquent\Relations\Relation;
use Illuminate\Database\Query\Builder as QueryBuilder;

/**
* @property-read HigherOrderBuilderProxy $orWhere
* @mixin \Illuminate\Database\Query\Builder
*/
class Builder
Expand Down Expand Up @@ -1360,4 +1363,21 @@ public function __clone()
{
$this->query = clone $this->query;
}

/**
* Dynamically access builder proxies.
*
* @param string $key
* @return mixed
*
* @throws \Exception
*/
public function __get($key)
{
if ($key === 'orWhere') {
return new HigherOrderBuilderProxy($this, $key);
}

throw new Exception("Property [{$key}] does not exist on this builder instance.");
}
}
51 changes: 51 additions & 0 deletions src/Illuminate/Support/HigherOrderBuilderProxy.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<?php

namespace Illuminate\Support;

use Illuminate\Database\Eloquent\Builder;

/**
* @mixin \Illuminate\Database\Eloquent\Builder
*/
class HigherOrderBuilderProxy
{
/**
* The collection being operated on.
*
* @var \Illuminate\Database\Eloquent\Builder
*/
protected $builder;

/**
* The method being proxied.
*
* @var string
*/
protected $method;

/**
* Create a new proxy instance.
*
* @param Builder $builder
* @param string $method
*/
public function __construct(Builder $builder, $method)
{
$this->method = $method;
$this->builder = $builder;
}

/**
* Proxy a scope call onto the query builder.
*
* @param string $method
* @param array $parameters
* @return mixed
*/
public function __call($method, $parameters)
{
return $this->builder->{$this->method}(function ($value) use ($method, $parameters) {
return $value->{$method}(...$parameters);
});
}
}
36 changes: 36 additions & 0 deletions tests/Database/DatabaseEloquentBuilderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -628,6 +628,22 @@ public function testRealNestedWhereWithMultipleScopesAndOneDeadScope()
$this->assertEquals(['bar', 9000], $query->getBindings());
}

public function testRealQueryHigherOrderOrWhereScopes()
{
$model = new EloquentBuilderTestHigherOrderWhereScopeStub;
$this->mockConnectionForModel($model, 'SQLite');
$query = $model->newQuery()->one()->orWhere->two();
$this->assertEquals('select * from "table" where "one" = ? or ("two" = ?)', $query->toSql());
}

public function testRealQueryChainedHigherOrderOrWhereScopes()
{
$model = new EloquentBuilderTestHigherOrderWhereScopeStub;
$this->mockConnectionForModel($model, 'SQLite');
$query = $model->newQuery()->one()->orWhere->two()->orWhere->three();
$this->assertEquals('select * from "table" where "one" = ? or ("two" = ?) or ("three" = ?)', $query->toSql());
}

public function testSimpleWhere()
{
$builder = $this->getBuilder();
Expand Down Expand Up @@ -1105,6 +1121,26 @@ public function scopeApproved($query)
}
}

class EloquentBuilderTestHigherOrderWhereScopeStub extends Model
{
protected $table = 'table';

public function scopeOne($query)
{
$query->where('one', 'foo');
}

public function scopeTwo($query)
{
$query->where('two', 'bar');
}

public function scopeThree($query)
{
$query->where('three', 'baz');
}
}

class EloquentBuilderTestNestedStub extends Model
{
protected $table = 'table';
Expand Down

0 comments on commit 33eff6c

Please sign in to comment.