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

时间:2014-01-05 07:00:06

标签: php mysql laravel

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

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

...然后$foodsFood[0, 1, 2, 3, ...] 模型对象。 (基本上是一系列模型。)

但是,这个数组的键只是:

Food

...所以,如果我想改变id对象$desired_object = $foods->get(24); $desired_object->color = 'Green'; $desired_object->save(); 为24,我不能这样做:

id

...因为这只会改变数组中的第25个元素,而不是foreach ($foods as $food) { if ($food->id == 24) { $desired_object = $food; break; } } $desired_object->color = 'Green'; $desired_object->save(); 为24的元素。

如何通过ANY属性/列(例如但不限于id / color / age / etc)从集合中获取单个(或多个)元素?

当然,我可以这样做:

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

......但是,这只是粗略的。

当然,我可以这样做:

$foods

...但更严重,因为当我在->find()集合中已经拥有所需对象时,它会执行额外的不必要查询。

提前感谢任何指导。

编辑:

要明确的是,您可以在Illuminate Collection上调用$foods = Food::all(); $desired_food = $foods->find(21); // Grab the food with an ID of 21 而不会生成其他查询,但接受主ID。例如:

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

但是,仍然没有干净(非循环,非查询)方法来从Collection中抓取元素,如下所示:

{{1}}

10 个答案:

答案 0 :(得分:92)

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

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

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

然后你可以说:

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

它将获取正确的项目,而不会使用过滤器功能。

答案 1 :(得分:86)

您可以使用filter,如下所示:

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

filter也会返回Collection,但由于您知道只有一个first,因此您可以在Collection上致电$desired_object = $food->first(function($item) { return $item->id == 24; });

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

{{1}}

答案 2 :(得分:7)

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

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

答案 3 :(得分:6)

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

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

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

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

答案 4 :(得分:6)

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

在这种情况下:

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

答案 5 :(得分:5)

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

对于Laravel 5.0,5.1和5.2,where()上的Collection方法只会进行等于比较。此外,默认情况下,它执行严格等于比较(===)。要进行宽松的比较(==),您可以将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');

答案 6 :(得分:3)

我必须指出,卡利的回答中存在一个很小但绝对严重的错误。在意识到这一点之前,我挣扎了好几个小时:

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

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

答案 7 :(得分:1)

可以调整用于查找值(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];
}

答案 8 :(得分:0)

当您使用where子句时,如上所述,您还需要使用get或first方法来获得结果。

/**
*Get all food
*
*/

$foods = Food::all();

/**
*Get green food 
*
*/

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

答案 9 :(得分:0)

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

            /** Initialize array */
            $data = [];

            /** Extract collection*/
            foreach (Model::all() as $model) {
                /** Initialize relation model array */
                $relationObjects = [];

                /** Iterate and make associative array */
                foreach ($model->relationObjects as $relObject) {
                    $relationObjects[] = $relObject->name; // name or whatever property you want
                }

                /** Push 'relationObjects' to coresponding 'modelName' key */
                $data[$model->name][] = $relationObjects;
            } 

$data 的形式如下:

 [   
    "Porsche": [
        [
            "Cayenne",
            "911 GT3"
        ]
    ],
    "Ford": [
        [
            "Mustang"
        ]
    ],
]