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

 嘿听tj说你是被搞出来的 发布于 2023-02-06 14:54

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

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

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

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

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

...所以如果我想改变Food一个id24 的对象,我不能这样做:

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

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

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

当然,我可以这样做:

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()Illuminate Collection而不会生成另一个查询,但它只接受主ID.例如:

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

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

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

kalley.. 105

您可以这样使用filter:

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

filter也将返回一个Collection,但既然你知道只有一个,你可以打电话first给那个Collection.

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

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

实际上甚至不需要调用`filter() - > first()`你可以调用`first(function(...))` (23认同)

嘿,谢谢!我想我可以忍受.在我看来,通常是这样一个"雄辩"的框架,仍然异常冗长哈哈.但到目前为止,它仍然比替代品更清洁,所以我会接受它. (7认同)

你可以用功能做同样的事情.`$ desired_object = $ food-> where('id',24) - > first();` (2认同)


Maksym Cierz.. 100

Laravel提供了一种方法keyBy,允许通过模型中的给定键来设置键.

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

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

然后你可以说:

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

它会抓住正确的项目,而不会使用过滤功能.

6 个回答
  • 您可以这样使用filter:

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

    filter也将返回一个Collection,但既然你知道只有一个,你可以打电话first给那个Collection.

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

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

    2023-02-06 14:55 回答
  • 由于我不需要循环整个集合,我认为最好有这样的辅助函数

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

    2023-02-06 14:55 回答
  • Laravel提供了一种方法keyBy,允许通过模型中的给定键来设置键.

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

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

    然后你可以说:

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

    它会抓住正确的项目,而不会使用过滤功能.

    2023-02-06 14:55 回答
  • 使用内置的集合方法containsfind,它将按主要ID(而不是数组键)进行搜索.例:

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

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

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

    2023-02-06 14:55 回答
  • 我知道这个问题最初是在Laravel 5.0发布之前提出的,但是从Laravel 5.0开始,Collections就支持这个where()方法.

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

    2023-02-06 14:56 回答
  • 从Laravel 5.5开始,您可以使用firstWhere()

    在您的情况下:

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

    2023-02-06 14:56 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有