是否可以在仍然通过关系访问时使用单独的ID数组来订购关系集合?
设置Checklist
有很多ChecklistItems
,我以正常方式访问此关系:
foreach ($list->items as $item) {
// More Code Here
}
现在$item
的所需顺序作为属性$list
下$list->item_order
的属性存在,它只是$item
ID中的一个数组{用户所需的订单,特定于正在迭代的$list
。
是否有可行的方法根据$items
模型所拥有的$list
数组订购item_order
附加的$list
?
(我无法在'项目表中添加'订单'列,b / c订单根据特定的'列表更改'关系)。
感谢您的帮助!
答案 0 :(得分:11)
你可以这样做:
$order = $list->item_order;
$list->items->sortBy(function($model) use ($order){
return array_search($model->getKey(), $order);
}
您还可以向模型添加属性访问器,该属性访问器执行相同的
public function getSortedItemsAttribute()
{
if ( ! is_null($this->item_order)) {
$order = $this->item_order;
$list = $this->items->sortBy(function($model) use ($order){
return array_search($model->getKey(), $order);
});
return $list;
}
return $this->items;
}
用法:
foreach ($list->sortedItems as $item) {
// More Code Here
}
如果您需要在多个地方使用此类功能,我建议您创建自己的Collection类:
class MyCollection extends Illuminate\Database\Eloquent\Collection {
public function sortByIds(array $ids){
return $this->sortBy(function($model) use ($ids){
return array_search($model->getKey(), $ids);
}
}
}
然后,在模型中实际使用该类覆盖newCollection()
。在这种情况下,它将在ChecklistItems
类:
public function newCollection(array $models = array())
{
return new MyCollection($models);
}
答案 1 :(得分:1)
您可以尝试设置一个关系,按照您要查找的顺序返回结果。您仍然可以急切加载关系,并按指定的顺序生成结果。这是假设item_order
字段是逗号分隔的ID列表。
public function itemsOrdered()
{
/**
* Adds conditions to the original 'items' relationship. Due to the
* join, we must specify to only select the fields for the related
* table. Then, order by the results of the FIND_IN_SET function.
*/
return $this->items()
->select('checklist_items.*')
->join('checklists', 'checklist_items.checklist_id', '=', 'checklists.id')
->orderByRaw('FIND_IN_SET(checklist_items.id, checklists.item_order)');
}
或者,如果您不想对表格/字段进行硬编码:
public function itemsOrdered()
{
$orderField = 'item_order';
$relation = $this->items();
$parentTable = $relation->getParent()->getTable();
$related = $relation->getRelated();
$relatedTable = $related->getTable();
return $relation
->select($relatedTable.'.*')
->join($parentTable, $relation->getForeignKey(), '=', $relation->getQualifiedParentKeyName())
->orderByRaw('FIND_IN_SET('.$related->getQualifiedKeyName().', '.$parentTable.'.'.$orderField.')');
}
现在,您可以:
$list = Checklist::with('items', 'itemsOrdered')->first();
var_export($list->item_order);
var_export($list->items->lists('id'));
var_export($list->itemsOrdered->lists('id'));
只是一个警告:这是相当实验性的代码。它看起来可以使用我可用的少量测试数据,但我在生产环境中没有做过这样的事情。此外,这仅在HasMany关系上进行测试。如果你在BelongsToMany或类似的东西上尝试这个确切的代码,你就会遇到问题。