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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/20931020/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-25 03:41:04  来源:igfitidea点击:

Laravel: Get Object From Collection By Attribute

phpmysqllaravel

提问by Leng

In Laravel, if I perform a query:

在 Laravel 中,如果我执行查询:

$foods = Food::where(...)->get();

...then $foodsis an Illuminate Collectionof Foodmodel objects. (Essentially an array of models.)

......然后$foods照亮收集Food模型对象。(本质上是一系列模型。)

However, the keys of this array are simply:

然而,这个数组的键很简单:

[0, 1, 2, 3, ...]

...so if I want to alter, say, the Foodobject with an idof 24, I can't do this:

...因此,如果我想更改24的Food对象id,我不能这样做:

$desired_object = $foods->get(24);
$desired_object->color = 'Green';
$desired_object->save();

...because this will merely alter the 25th element in the array, not the element with an idof 24.

...因为这只会改变数组中的第 25 个元素,而不是具有id24的元素。

How do I get a single (or multiple) element(s) from a collection by ANY attribute/column (such as, but not limited to, id / color / age / etc.)?

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

Of course, I can do this:

当然,我可以这样做:

foreach ($foods as $food) {
    if ($food->id == 24) {
        $desired_object = $food;
        break;
    }
}
$desired_object->color = 'Green';
$desired_object->save();

...but, that's just gross.

……但是,这太恶心了。

And, of course, I can do this:

而且,当然,我可以这样做:

$desired_object = Food::find(24);
$desired_object->color = 'Green';
$desired_object->save();

...but that's even more gross, because it performs an additional unnecessary query when I already have the desired object in the $foodscollection.

...但这更糟糕,因为当我已经在$foods集合中拥有所需的对象时,它会执行额外的不必要的查询。

Thanks in advance for any guidance.

在此先感谢您的任何指导。

EDIT:

编辑:

To be clear, you cancall ->find()on an Illuminate Collection without spawning another query, but it onlyaccepts a primary ID. For instance:

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

$foods = Food::all();
$desired_food = $foods->find(21);  // Grab the food with an ID of 21

However, there is still no clean (non-looping, non-querying) way to grab an element(s) by an attribute from a Collection, like this:

但是,仍然没有干净(非循环、非查询)的方式通过集合中的属性来获取元素,如下所示:

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

回答by kalley

You can use filter, like so:

你可以使用filter,像这样:

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

filterwill also return a Collection, but since you know there will be only one, you can call firston that Collection.

filter也会返回 a Collection,但既然你知道只有一个,你可以调用first那个Collection

You don't need the filter anymore (or maybe ever, I don't know this is almost 4 years old). You can just use first:

您不再需要过滤器(或者也许永远,我不知道这已经快 4 岁了)。你可以只使用first

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

回答by Maksym Cierzniak

Laravel provides a method called keyBywhich allows to set keys by given key in model.

Laravel 提供了一个被调用的方法keyBy,它允许通过模型中的给定键来设置键。

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

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

will return the collection but with keys being the values of idattribute from any model.

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

Then you can say:

然后你可以说:

$desired_food = $foods->get(21); // Grab the food with an ID of 21

$desired_food = $foods->get(21); // Grab the food with an ID of 21

and it will grab the correct item without the mess of using a filter function.

它将抓取正确的项目,而无需使用过滤功能。

回答by Victor Timoftii

As from Laravel 5.5 you can use firstWhere()

从 Laravel 5.5 开始,您可以使用firstWhere()

In you case:

在你的情况下:

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

回答by Ziad Hilal

Use the built in collection methods containand find, which will search by primary ids (instead of array keys). Example:

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

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

contains() actually just calls find() and checks for null, so you could shorten it down to:

contains() 实际上只是调用 find() 并检查 null,因此您可以将其缩短为:

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

回答by Rohith Raveendran

Since I don't need to loop entire collection, I think it is better to have helper function like this

由于我不需要循环整个集合,我认为最好有这样的辅助函数

/**
 * 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;
}

回答by patricus

I know this question was originally asked before Laravel 5.0 was released, but as of Laravel 5.0, Collections support the where()method for this purpose.

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

For Laravel 5.0, 5.1, and 5.2, the where()method on the Collectionwill only do an equals comparison. Also, it does a strict equals comparison (===) by default. To do a loose comparison (==), you can either pass falseas the third parameter or use the whereLoose()method.

对于 Laravel 5.0、5.1 和 5.2,上面的where()方法Collection只会做一个 equals 比较。此外,===默认情况下它会进行严格的等于比较 ( )。要进行松散比较 ( ==),您可以false作为第三个参数传递或使用该whereLoose()方法。

As of Laravel 5.3, the where()method was expanded to work more like the where()method for the query builder, which accepts an operator as the second parameter. Also like the query builder, the operator will default to an equals comparison if none is supplied. The default comparison was also switched from strict by default to loose by default. So, if you'd like a strict comparison, you can use whereStrict(), or just use ===as the operator for where().

从 Laravel 5.3 开始,该where()方法被扩展为更像where()查询构建器的方法,它接受一个运算符作为第二个参数。也与查询构建器一样,如果没有提供,运算符将默认为等于比较。默认比较也从默认的严格切换到默认的宽松。因此,如果您想要进行严格的比较,可以使用whereStrict(),或者仅用===作 的运算符where()

Therefore, as of Laravel 5.0, the last code example in the question will work exactly as intended:

因此,从 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');

回答by squaretastic

I have to point out that there is a small but absolutely CRITICAL error in kalley's answer. I struggled with this for several hours before realizing:

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

Inside the function, what you are returning is a comparison, and thus something like this would be more correct:

在函数内部,您返回的是一个比较,因此这样的事情会更正确:

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

回答by softfrog

Elegant solution for finding a value (http://betamode.de/2013/10/17/laravel-4-eloquent-check-if-there-is-a-model-with-certain-key-value-pair-in-a-collection/) can be adapted:

寻找值的优雅解决方案(http://betamode.de/2013/10/17/laravel-4-eloquent-check-if-there-is-a-model-with-certain-key-value-pair-in -a-collection/) 可以调整:

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

回答by Marco

As the question above when you are using the where clause you also need to use the get Or first method to get the result.

正如上面的问题,当您使用 where 子句时,您还需要使用 get Or first 方法来获取结果。

/**
*Get all food
*
*/

$foods = Food::all();

/**
*Get green food 
*
*/

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