这是我的范围,apply()
方法非常有用。
use Illuminate\Database\Eloquent\ScopeInterface;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Carbon\Carbon;
class JobStatusScope implements ScopeInterface
{
/**
* Apply scope on the query.
*
* @param \Illuminate\Database\Eloquent\Builder $builder
* @param \Illuminate\Database\Eloquent\Model $model
* @return void
*/
public function apply(Builder $builder, Model $model)
{
$builder
->where('active', true)
->whereHas('user', function($q) {
$q->where('account_type', 'company')
->whereNested(function($r) {
$r->where('stripe_active', true)
->orWhereNotNull('subscription_ends_at')
->where('subscription_ends_at', '>', Carbon::now())
->orWhereNotNull('trial_ends_at')
->where('trial_ends_at', '>', Carbon::today());
});
});
}
/**
* Remove scope from the query.
*
* @param \Illuminate\Database\Eloquent\Builder $builder
* @param \Illuminate\Database\Eloquent\Model $model
* @return void
*/
public function remove(Builder $builder, Model $model)
{
$query = $builder->getQuery();
//dd($query->wheres);
$columns = ['stripe_active', 'subscription_ends_at', 'active', 'trial_ends_at'];
foreach ((array) $query->wheres as $key => $where) {
if (in_array($where['column'], $columns)) {
unset($query->wheres[$key]);
$query->wheres = array_values($query->wheres);
}
}
}
}
我在remove()
方法中尝试的内容无效。
我在trait文件中有这个,并附加到我的模型
use App\Cable\Traits\Scopes\JobStatusScope;
trait JobStatusTrait {
public static function bootJobStatusTrait()
{
static::addGlobalScope(new JobStatusScope);
}
/**
* Get the query builder without the scope applied.
*
* @return \Illuminate\Database\Eloquent\Builder
*/
public static function withAll()
{
return with(new static)->newQueryWithoutScope(new JobStatusScope);
}
}
当我尝试运行MyModel::withAll()->get()
时,它应该返回没有apply()
约束的所有记录,但它不会。
当我dd($query->wheres)
方法中的remove()
并致电->withAll()
时,我得到了这个
array:3 [▼
0 => array:3 [▼
"type" => "Null"
"column" => "jobs.deleted_at"
"boolean" => "and"
]
1 => array:5 [▼
"type" => "Basic"
"column" => "active"
"operator" => "="
"value" => true
"boolean" => "and"
]
2 => array:5 [▼
"type" => "Basic"
"column" => Expression {#478 ▼
#value: "(select count(*) from `users` where `jobs`.`user_id` = `users`.`id` and `account_type` = ? and (`stripe_active` = ? or `subscription_ends_at` is not null and `subscription_ends_at` > ? or `trial_ends_at` is not null and `trial_ends_at` > ?) and `users`.`deleted_at` is null)"
}
"operator" => ">="
"value" => Expression {#476 ▶}
"boolean" => "and"
]
]
我似乎无法弄清楚这一点。 Laravel的大部分都很容易理解,它是如此“雄辩”,但这让我感到厌烦。
任何帮助将不胜感激。谢谢!
答案 0 :(得分:0)
whereHas()
限制通过使用子查询来获取相关记录的计数。
从dd()
输出中可以看出,目标column
子句的where
不仅仅是一个纯字符串(如'active'),而是一个Expression对象,包含子查询。
您需要编写一些逻辑来确定此Expression是否与whereHas()
生成的子查询匹配,因此您可以删除它。
一个简单的例子如下(n.b.没有语法检查或测试):
public function remove(Builder $builder, Model $model)
{
$query = $builder->getQuery();
// your plain column names
$columns = ['active'];
// columns present in the user relationship subquery
$userColumns = ['stripe_active', 'subscription_ends_at', 'trial_ends_at'];
foreach ((array) $query->wheres as $key => $where) {
// first check if the column is really an Expression
// if it is not an expression, do the normal check on strings
if ($where['column'] instanceof \Illuminate\Database\Query\Expression) {
// get the sql value of the Expression
$sql = $where['column']->getValue();
// see if all the user columns are in the sql statement
$count = 0;
foreach($userColumns as $name) {
// increment count if the user column was found
$count += (stripos($sql, $name) !== false) ? 1 : 0;
}
// if all the user columns were found, assume this is the where and remove it
if ($count == count($userColumns)) {
unset($query->wheres[$key]);
$query->wheres = array_values($query->wheres);
}
} elseif (in_array($where['column'], $columns)) {
unset($query->wheres[$key]);
$query->wheres = array_values($query->wheres);
}
}
}
你可能想要提出一些比检查所有列名是否都在SQL中更严格的东西,但这应该让你开始。