我在关系字段上做了一个特征来排序。我对具有状态关系的网店订单有这个问题,并且状态有一个名称字段。
情况示例
使用 eloquent 模型的“连接”进行排序是不可能的,因为它们不是连接。它们是在第一个查询完成后运行的查询。所以我所做的就是做了一个小技巧来读取雄辩的关系数据(如表、连接键和其他位置,如果包括)并将其加入到主查询中。这仅适用于一对一的关系。
第一步是创建一个特征并在模型上使用它。在该特征中,您有 2 个功能。第一个:
/**
* @param string $relation - The relation to create the query for
* @param string|null $overwrite_table - In case if you want to overwrite the table (join as)
* @return Builder
*/
public static function RelationToJoin(string $relation, $overwrite_table = false) {
$instance = (new self());
if(!method_exists($instance, $relation))
throw new \Error('Method ' . $relation . ' does not exists on class ' . self::class);
$relationData = $instance->{$relation}();
if(gettype($relationData) !== 'object')
throw new \Error('Method ' . $relation . ' is not a relation of class ' . self::class);
if(!is_subclass_of(get_class($relationData), Relation::class))
throw new \Error('Method ' . $relation . ' is not a relation of class ' . self::class);
$related = $relationData->getRelated();
$me = new self();
$query = $relationData->getQuery()->getQuery();
switch(get_class($relationData)) {
case HasOne::class:
$keys = [
'foreign' => $relationData->getForeignKeyName(),
'local' => $relationData->getLocalKeyName()
];
break;
case BelongsTo::class:
$keys = [
'foreign' => $relationData->getOwnerKeyName(),
'local' => $relationData->getForeignKeyName()
];
break;
default:
throw new \Error('Relation join only works with one to one relationships');
}
$checks = [];
$other_table = ($overwrite_table ? $overwrite_table : $related->getTable());
foreach($keys as $key) {
array_push($checks, $key);
array_push($checks, $related->getTable() . '.' . $key);
}
foreach($query->wheres as $key => $where)
if(in_array($where['type'], ['Null', 'NotNull']) && in_array($where['column'], $checks))
unset($query->wheres[$key]);
$query = $query->whereRaw('`' . $other_table . '`.`' . $keys['foreign'] . '` = `' . $me->getTable() . '`.`' . $keys['local'] . '`');
return (object) [
'query' => $query,
'table' => $related->getTable(),
'wheres' => $query->wheres,
'bindings' => $query->bindings
];
}
这是读取雄辩数据的“检测”功能。
第二个:
/**
* @param Builder $builder
* @param string $relation - The relation to join
*/
public function scopeJoinRelation(Builder $query, string $relation) {
$join_query = self::RelationToJoin($relation, $relation);
$query->join($join_query->table . ' AS ' . $relation, function(JoinClause $builder) use($join_query) {
return $builder->mergeWheres($join_query->wheres, $join_query->bindings);
});
return $query;
}
这是向模型添加范围以在查询中使用的函数。现在只需在您的模型上使用该特征,您就可以像这样使用它:
Order::joinRelation('status')->select([
'orders.*',
'status.name AS status_name'
])->orderBy('status_name')->get();