web-dev-qa-db-ja.com

Laravel:属性からコレクションからオブジェクトを取得

Laravelでクエリを実行すると:

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

...次に$foodsIlluminate Collection of Foodモデルオブジェクトです。 (本質的にモデルの配列。)

ただし、この配列のキーは次のとおりです。

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

...つまり、Foodが24のidオブジェクトを変更したい場合、これはできません。

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

...これは、配列の25番目の要素を変更するだけで、idが24の要素ではないためです。

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コレクションに目的のオブジェクトが既にある場合に追加の不要なクエリを実行するためです。

ガイダンスを事前に感謝します。

編集:

明確にするために、can Illuminate Collectionで別のクエリを生成せずに->find()を呼び出しますが、onlyはプライマリ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.  :(
69
Leng

filter を次のように使用できます。

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

filterCollectionを返しますが、1つしかないことを知っているので、そのfirstCollectionを呼び出すことができます。

フィルターはもう必要ありません(または、これがほぼ4年前であることはわかりません)。 first を使用するだけです。

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

LaravelはkeyByと呼ばれるメソッドを提供します。これにより、モデル内の特定のキーによってキーを設定できます。

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

コレクションを返しますが、キーは任意のモデルのid属性の値です。

その後、あなたは言うことができます:

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

フィルター機能を使用することなく、正しいアイテムを取得します。

95

Laravel 5.5から firstWhere() を使用できます

あなたの場合:

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

コレクション全体をループする必要はないので、このようなヘルパー関数を持つ方が良いと思います

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

組み込みのコレクションメソッドcontainおよびfindを使用します。これらは(配列キーの代わりに)プライマリIDで検索します。例:

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

contains()は実際にはfind()を呼び出してnullをチェックするだけなので、次のように短縮できます。

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

この質問はLaravel 5.0がリリースされる前に最初に尋ねられたことを知っていますが、Laravel 5.0では、コレクションはこの目的でwhere()メソッドをサポートします。

Laravel 5.0、5.1、および5.2の場合、Collectionwhere()メソッドは等値比較のみを行います。また、デフォルトで厳密な等値比較(===)を実行します。大まかな比較(==)を行うには、3番目のパラメーターとしてfalseを渡すか、whereLoose()メソッドを使用します。

Laravel 5.3の時点で、where()メソッドは、2番目のパラメーターとして演算子を受け入れるクエリビルダーの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');
5
patricus

Kalleyの答えには、小さいが絶対的に重大なエラーがあることを指摘しなければなりません。気づくまでに数時間これに苦労しました。

関数内では、返されるのは比較であるため、このようなものの方が正しいでしょう。

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

Where句を使用する場合の上記の質問として、get Or firstメソッドを使用して結果を取得する必要もあります。

/**
*Get all food
*
*/

$foods = Food::all();

/**
*Get green food 
*
*/

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

値を見つけるためのエレガントなソリューション( 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];
}
1
softfrog