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