I'm working on Laravel 4. As I knew, I can do subquery:
Project::whereIn('project_id', function($q) {
$q->select('project_id')
->from('company')
->whereNull('deleted_at');
});
I found complications, that I can't use scope in subquery and disable soft_delete make me change source code so much.
I wish it was:
Project::whereIn('project_id', function(&$q) {
$q = Company::select('project_id')->getQuery();
});
Now, I can add scope, disable soft_delete easily.
I tried, and found a solution, that I must change Laravel's Database\Query\Builder code, function whereInSub, line 786.
call_user_func($callback, $query = $this->newQuery());
to:
$query = $this->newQuery();
call_user_func_array($callback, array(&$query));
It's harmful to modify Laravel framework's vendor. So I want to ask how to do it safely.
Sorry because my bad English.
Thank you for reading.
Oooh! This is quite a tricky one since your model would extend Eloquent
, then Eloquent
uses Illuminate\Database\Query\Builder
.
But what I noticed is that Eloquent
is actually an alias in app/config/app.php
file. So what you can do is following these steps.
Illuminate\Database\Query\Builder
to MyQueryBuilder
with your custom whereInSub()
.Illuminate\Database\Eloquent\Model
to MyModel
and make it use
your MyQueryBuilder
.Eloquent
alias in app/config/app.php
to your new MyModel
class.Something like this:
MyQueryBuilder.php:
use Closure;
use Illuminate\Support\Collection;
use Illuminate\Database\ConnectionInterface;
use Illuminate\Database\Query\Grammars\Grammar;
use Illuminate\Database\Query\Processors\Processor;
class MyQueryBuilder extends Illuminate\Database\Query\Builder
{
protected function whereInSub($column, Closure $callback, $boolean, $not)
{
$type = $not ? 'NotInSub' : 'InSub';
$query = $this->newQuery(); // Your changes
call_user_func_array($callback, array(&$query)); // Your changes
$this->wheres[] = compact('type', 'column', 'query', 'boolean');
$this->mergeBindings($query);
return $this;
}
}
MyModel.php:
use DateTime;
use ArrayAccess;
use Carbon\Carbon;
use LogicException;
use Illuminate\Events\Dispatcher;
use Illuminate\Database\Eloquent\Relations\Pivot;
use Illuminate\Database\Eloquent\Relations\HasOne;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\MorphTo;
use Illuminate\Support\Contracts\JsonableInterface;
use Illuminate\Support\Contracts\ArrayableInterface;
use Illuminate\Database\Eloquent\Relations\Relation;
use Illuminate\Database\Eloquent\Relations\MorphOne;
use Illuminate\Database\Eloquent\Relations\MorphMany;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
// use Illuminate\Database\Query\Builder as QueryBuilder;
use Illuminate\Database\Eloquent\Relations\MorphToMany;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasManyThrough;
use Illuminate\Database\ConnectionResolverInterface as Resolver;
use MyQueryBuilder as QueryBuilder; // MyModel should now use your MyQueryBuilder instead of the default which I commented out above
abstract class MyModel extends Illuminate\Database\Eloquent\Model
{
}
app/config/app.php:
'aliases' => array(
...
'Eloquent' => 'MyModel',
...
);
Note that I put long lists of use
up there because "use" keyword does not get inherited. Also I did not put MyQueryBuilder
and MyModel
in a namespace for the sake of simplicity. My use
list might also be different from yours depending on Laravel versions we use, so please check the uses too.
You can create a custom query builder and use it like this.
My Custom Query Builder:
use Illuminate\Database\Query\Builder as QueryBuilder;
class MyCustomBuilder extends QueryBuilder{
protected function whereInSub($column, Closure $callback, $boolean, $not)
{
$type = $not ? 'NotInSub' : 'InSub';
$query = $this->newQuery(); // Your changes
call_user_func_array($callback, array(&$query)); // Your changes
$this->wheres[] = compact('type', 'column', 'query', 'boolean');
$this->mergeBindings($query);
return $this;
}
}
In any Model overwrite the method newBaseQueryBuilder() and return an instance of your own query builder
class MyModel extends Model{
protected function newBaseQueryBuilder()
{
$connection = $this->getConnection();
return new MyQueryBuilder(
$connection, $connection->getQueryGrammar(),
$connection->getPostProcessor()
);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With