[php] Laravel : 속성 별 컬렉션에서 객체 가져 오기

Laravel에서 쿼리를 수행하면 :

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

… 모델 객체 $foodsIlluminate 컬렉션 입니다 Food. (본질적으로 모델의 배열입니다.)

그러나이 배열의 키는 다음과 같습니다.

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

… 24의 값을 Food가진 객체 를 변경하려면 id이 작업을 수행 할 수 없습니다.

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

… 이는 id24 의 요소가 아닌 배열의 25 번째 요소 만 변경하기 때문 입니다.

모든 속성 / 열 (예 : 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();

…하지만 컬렉션에 원하는 개체가 이미있을 때 불필요한 추가 쿼리를 수행하기 때문에 훨씬 더 복잡 합니다 $foods.

모든 안내에 미리 감사드립니다.

편집하다:

명확하게 말하면 다른 쿼리를 생성하지 않고 Illuminate 컬렉션을 호출 할 ->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.  :(



답변

다음 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;
});


답변

라 라벨은 keyBy모델에서 주어진 키로 키를 설정할 수 있는 메서드를 제공합니다 .

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

컬렉션을 반환하지만 키는 id모든 모델 의 속성 값입니다 .

그런 다음 다음과 같이 말할 수 있습니다.

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

필터 기능을 사용하지 않고도 올바른 항목을 잡을 수 있습니다.


답변

Laravel 5.5에서와 같이 firstWhere () 사용할 수 있습니다.

당신의 경우 :

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


답변

전체 컬렉션을 반복 할 필요가 없기 때문에 이와 같은 도우미 기능을 갖는 것이 더 좋다고 생각합니다.

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


답변

기본 제공되는 컬렉션 메서드 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);
}


답변

이 질문은 원래 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');


답변

나는 kalley의 대답에 작지만 절대적으로 중요한 오류가 있음을 지적해야합니다. 나는 깨닫기 전에 몇 시간 동안 이것으로 어려움을 겪었습니다.

함수 내에서 반환하는 것은 비교이므로 다음과 같은 것이 더 정확할 것입니다.

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