如何自定义 Laravel 的 DatabaseQueryBuilder(制作更好的子查询)
我正在开发 Laravel 4.据我所知,我可以做子查询:
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');
});
我发现了一些复杂情况,即我无法在子查询中使用作用域并禁用 soft_delete 使我对源代码进行了大量更改.
I found complications, that I can't use scope in subquery and disable soft_delete make me change source code so much.
我希望它是:
Project::whereIn('project_id', function(&$q) {
$q = Company::select('project_id')->getQuery();
});
现在,我可以添加范围,轻松禁用 soft_delete.
Now, I can add scope, disable soft_delete easily.
我尝试并找到了一个解决方案,即我必须更改 Laravel 的 DatabaseQueryBuilder 代码,函数 whereInSub,第 786 行.
I tried, and found a solution, that I must change Laravel's DatabaseQueryBuilder code, function whereInSub, line 786.
call_user_func($callback, $query = $this->newQuery());
到:
$query = $this->newQuery();
call_user_func_array($callback, array(&$query));
修改 Laravel 框架的供应商是有害的.所以想问一下怎么安全的做.
It's harmful to modify Laravel framework's vendor. So I want to ask how to do it safely.
对不起,因为我的英语不好.
Sorry because my bad English.
感谢您的阅读.
推荐答案
哦!这是一个相当棘手的问题,因为您的模型将扩展 Eloquent
,然后 Eloquent
使用 IlluminateDatabaseQueryBuilder
.
Oooh! This is quite a tricky one since your model would extend Eloquent
, then Eloquent
uses IlluminateDatabaseQueryBuilder
.
但我注意到 Eloquent
实际上是 app/config/app.php
文件中的别名.因此,您可以执行以下步骤.
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.
- 使用自定义的
whereInSub()
将IlluminateDatabaseQueryBuilder
扩展到MyQueryBuilder
. - 将
IlluminateDatabaseEloquentModel
扩展到MyModel
并使其use
你的MyQueryBuilder
.莉> - 将
app/config/app.php
中的Eloquent
别名设置为新的MyModel
类.
- Extend
IlluminateDatabaseQueryBuilder
toMyQueryBuilder
with your customwhereInSub()
. - Extend
IlluminateDatabaseEloquentModel
toMyModel
and make ituse
yourMyQueryBuilder
. - Set
Eloquent
alias inapp/config/app.php
to your newMyModel
class.
像这样:
MyQueryBuilder.php:
use Closure;
use IlluminateSupportCollection;
use IlluminateDatabaseConnectionInterface;
use IlluminateDatabaseQueryGrammarsGrammar;
use IlluminateDatabaseQueryProcessorsProcessor;
class MyQueryBuilder extends IlluminateDatabaseQueryBuilder
{
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 CarbonCarbon;
use LogicException;
use IlluminateEventsDispatcher;
use IlluminateDatabaseEloquentRelationsPivot;
use IlluminateDatabaseEloquentRelationsHasOne;
use IlluminateDatabaseEloquentRelationsHasMany;
use IlluminateDatabaseEloquentRelationsMorphTo;
use IlluminateSupportContractsJsonableInterface;
use IlluminateSupportContractsArrayableInterface;
use IlluminateDatabaseEloquentRelationsRelation;
use IlluminateDatabaseEloquentRelationsMorphOne;
use IlluminateDatabaseEloquentRelationsMorphMany;
use IlluminateDatabaseEloquentRelationsBelongsTo;
// use IlluminateDatabaseQueryBuilder as QueryBuilder;
use IlluminateDatabaseEloquentRelationsMorphToMany;
use IlluminateDatabaseEloquentRelationsBelongsToMany;
use IlluminateDatabaseEloquentRelationsHasManyThrough;
use IlluminateDatabaseConnectionResolverInterface 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 IlluminateDatabaseEloquentModel
{
}
app/config/app.php:
'aliases' => array(
...
'Eloquent' => 'MyModel',
...
);
请注意,我将一长串 use
放在那里,因为 "use" 关键字不会被继承.此外,为了简单起见,我没有将 MyQueryBuilder
和 MyModel
放在命名空间中.根据我们使用的 Laravel 版本,我的 use
列表也可能与您的不同,因此请检查用途.
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.
相关文章