Php Laravel:按属性从集合中获取对象

Php Laravel:按属性从集合中获取对象,php,mysql,laravel,Php,Mysql,Laravel,在Laravel中,如果执行查询: $foods = Food::where(...)->get(); …然后,$foods是Food模型对象的一个集合。(基本上是一系列模型。) 但是,此数组的键仅为: [0, 1, 2, 3, ...] …因此,如果我想更改,Food对象的id为24,我不能这样做: $desired_object = $foods->get(24); $desired_object->color = 'Green'; $desired_object-&g

在Laravel中,如果执行查询:

$foods = Food::where(...)->get();
…然后,
$foods
Food
模型对象的一个集合。(基本上是一系列模型。)

但是,此数组的键仅为:

[0, 1, 2, 3, ...]
…因此,如果我想更改,
Food
对象的
id
为24,我不能这样做:

$desired_object = $foods->get(24);
$desired_object->color = 'Green';
$desired_object->save();
…因为这只会更改数组中的第25个元素,而不是id为24的元素

如何通过任何属性/列(例如但不限于id/颜色/年龄等)从集合中获取单个(或多个)元素?

当然,我可以这样做:

foreach ($foods as $food) {
    if ($food->id == 24) {
        $desired_object = $food;
        break;
    }
}
$desired_object->color = 'Green';
$desired_object->save();
$desired_object = Food::find(24);
$desired_object->color = 'Green';
$desired_object->save();
…但是,那太恶心了

当然,我可以做到:

foreach ($foods as $food) {
    if ($food->id == 24) {
        $desired_object = $food;
        break;
    }
}
$desired_object->color = 'Green';
$desired_object->save();
$desired_object = Food::find(24);
$desired_object->color = 'Green';
$desired_object->save();
…但这更糟糕,因为当我在
$foods
集合中已经有了所需的对象时,它会执行额外的不必要的查询

提前感谢您的指导

编辑:

明确地说,您可以在不生成另一个查询的情况下对一个集合调用
->find()
,但它只接受一个主ID。例如:

$foods = Food::all();
$desired_food = $foods->find(21);  // Grab the food with an ID of 21
但是,仍然没有干净(非循环、非查询)的方法通过集合中的属性获取元素,如下所示:

$foods = Food::all();
$green_foods = $foods->where('color', 'green'); // This won't work.  :(
您可以这样使用:

$desired_object = $food->filter(function($item) {
    return $item->id == 24;
})->first();
过滤器
也将返回一个
集合
,但由于您知道只有一个集合,因此可以首先调用该
集合

你再也不需要过滤器了(也许永远都不需要,我不知道这已经快4年了)。您只需使用:


我必须指出,kalley的回答中有一个很小但绝对严重的错误。我挣扎了几个小时才意识到:

在函数内部,您返回的是一个比较,因此类似这样的内容更为正确:

$desired_object = $food->filter(function($item) {
    return ($item->id **==** 24);
})->first();

因为我不需要循环整个集合,所以我认为最好有这样的helper函数

/**
 * Check if there is a item in a collection by given key and value
 * @param Illuminate\Support\Collection $collection collection in which search is to be made
 * @param string $key name of key to be checked
 * @param string $value value of key to be checkied
 * @return boolean|object false if not found, object if it is found
 */
function findInCollection(Illuminate\Support\Collection $collection, $key, $value) {
    foreach ($collection as $item) {
        if (isset($item->$key) && $item->$key == $value) {
            return $item;
        }
    }
    return FALSE;
}

可以采用查找值()的优雅解决方案:

$desired_object_key = $food->array_search(24, $food->lists('id'));
if ($desired_object_key !== false) {
   $desired_object = $food[$desired_object_key];
}

使用内置的收集方法containfind,它们将按主ID(而不是数组键)进行搜索。例如:

if ($model->collection->contains($primaryId)) {
    var_dump($model->collection->find($primaryId);
}
contains()实际上只是调用find()并检查null,因此可以将其缩短为:

if ($myModel = $model->collection->find($primaryId)) {
    var_dump($myModel);
}

Laravel提供了一个名为
keyBy
的方法,该方法允许在模型中根据给定的键设置键

$collection=$collection->keyBy('id')

将返回集合,但键是来自任何模型的
id
属性的值

然后你可以说:

$desired_food=$foods->get(21);//抓取ID为21的食物


而且它可以抓取正确的项目,而不需要使用筛选函数。

我知道这个问题最初是在Laravel 5.0发布之前提出的,但从Laravel 5.0开始,集合为此支持
where()
方法

对于Laravel 5.0、5.1和5.2,集合
上的
where()
方法只能进行相等比较。此外,默认情况下,它执行严格的等于比较(
==
)。要进行松散比较(
=
),可以传递
false
作为第三个参数,或者使用
whereLoose()
方法

从Laravel 5.3开始,扩展了
where()
方法,使其更像查询生成器的
where()
方法,该方法接受运算符作为第二个参数。与查询生成器一样,如果未提供任何值,则运算符将默认为等于比较。默认比较也从严格默认切换为宽松默认。因此,如果希望进行严格比较,可以使用
whereStrict()
,或者只使用
==
作为
where()
的运算符

因此,从Laravel 5.0开始,问题中的最后一个代码示例将完全按照预期工作:

$foods = Food::all();
$green_foods = $foods->where('color', 'green'); // This will work.  :)

// This will only work in Laravel 5.3+
$cheap_foods = $foods->where('price', '<', 5);

// Assuming "quantity" is an integer...
// This will not match any records in 5.0, 5.1, 5.2 due to the default strict comparison.
// This will match records just fine in 5.3+ due to the default loose comparison.
$dozen_foods = $foods->where('quantity', '12');
$foods=Food::all();
$green_foods=$foods->where('color','green');//这将起作用。:)
//这仅适用于Laravel 5.3+

$cheap_foods=$foods->where('price','如上所述,当您使用where子句时,还需要使用get或first方法来获得结果

/**
*Get all food
*
*/

$foods = Food::all();

/**
*Get green food 
*
*/

$green_foods = Food::where('color', 'green')->get();

从Laravel 5.5开始,您可以使用

就你而言:

$green_foods = $foods->firstWhere('color', 'green');

如果您在Laravel中有一对多关系,您可以简单地编写以下内容。
(例如,您有汽车制造商和车型)

/**初始化数组*/
$data=[];
/**摘录集*/
foreach(Model::all()作为$Model){
/**初始化关系模型数组*/
$relationObjects=[];
/**迭代并生成关联数组*/
foreach($model->relationObjects作为$relObject){
$relationObjects[]=$relObject->name;//名称或任何您想要的属性
}
/**将“relationObjects”推送到共同响应的“modelName”键*/
$data[$model->name][]=$relationObjects;
} 
$data
的格式如下:

[
“保时捷”:[
[
“卡宴”,
“911 GT3”
]
],
“福特”:[
[
“野马”
]
],
]

嘿,谢谢!我想我可以接受。在我看来,这通常是一个“雄辩”的框架,但它仍然非常冗长,哈哈。但到目前为止,它仍然比其他替代方案干净得多,所以我接受它。正如@squartastic在另一个答案中指出的,在你的闭包中,你是在进行分配,而不是比较(也就是说,您应该==而不是=)实际上甚至不需要调用
filter()->first()
您可以从Laravel集合文档中调用
first(函数(…)
collect([1,2,3,4])->first(函数($value,$key){