web-dev-qa-db-de.com

Laravel: Objekt aus Sammlung durch Attribut abrufen

Wenn ich in Laravel eine Abfrage durchführe:

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

... dann ist $foods eine Illuminate Collection von Food Modellobjekten. (Im Wesentlichen eine Reihe von Modellen.)

Die Schlüssel dieses Arrays sind jedoch einfach:

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

... wenn ich also das Food-Objekt mit einer id von 24 ändern möchte, kann ich dies nicht tun:

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

... weil dadurch lediglich das 25. Element im Array geändert wird, nicht das Element mit einer id von 24.

Wie bekomme ich ein einzelnes (oder mehrere) Elemente aus einer Collection nach ANY-Attribut/Spalte (z. B. id/color/age/etc.)?

Natürlich kann ich das machen:

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

... aber das ist nur grob.

Und das kann ich natürlich auch:

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

... aber das ist noch schlimmer, weil es eine zusätzliche unnötige Abfrage durchführt, wenn ich bereits das gewünschte Objekt in der $foods-Sammlung habe.

Vielen Dank im Voraus für Hinweise.

BEARBEITEN:

Um klar zu sein, Sie can rufen ->find() für eine Illuminate Collection auf, ohne eine andere Abfrage zu starten, aber nur akzeptiert eine primäre ID. Zum Beispiel:

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

Es gibt jedoch immer noch keine saubere Methode (keine Schleife, keine Abfrage), um ein oder mehrere Elemente anhand eines Attributs aus einer Collection zu erfassen.

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

Sie können filter wie folgt verwenden:

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

filter gibt auch eine Collection zurück. Da Sie wissen, dass es nur eine gibt, können Sie first für diese Collection aufrufen.

Sie brauchen den Filter nicht mehr (oder vielleicht weiß ich nicht, dass er fast 4 Jahre alt ist). Sie können einfach first verwenden:

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

Laravel bietet eine Methode mit dem Namen keyBy, mit der Schlüssel anhand eines bestimmten Schlüssels im Modell festgelegt werden können.

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

gibt die Auflistung zurück, wobei die Schlüssel jedoch die Werte des Attributs id eines beliebigen Modells sind.

Dann können Sie sagen:

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

und es greift nach dem richtigen Gegenstand, ohne eine Filterfunktion verwenden zu müssen.

95

Da ich nicht die gesamte Sammlung schleifen muss, denke ich, ist es besser, eine solche Helferfunktion zu haben 

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

Verwenden Sie die integrierten Erfassungsmethoden contain und find , die nach Primär-IDs (anstelle von Array-Schlüsseln) suchen. Beispiel:

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

contains () ruft tatsächlich nur find () auf und sucht nach null, sodass Sie es auf Folgendes reduzieren können:

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

Ich weiß, dass diese Frage ursprünglich gestellt wurde, bevor Laravel 5.0 veröffentlicht wurde, aber seit Laravel 5.0 unterstützen Collections die where()-Methode für diesen Zweck.

Für Laravel 5.0, 5.1 und 5.2 führt die where()-Methode für die Collection nur einen Gleichheitsvergleich durch. Außerdem führt es standardmäßig einen strengen Gleichheitsvergleich (===) durch. Für einen losen Vergleich (==) können Sie entweder false als dritten Parameter übergeben oder die whereLoose()-Methode verwenden.

Ab Laravel 5.3 wurde die where()-Methode erweitert, um der where()-Methode für den Query Builder zu ähneln, die einen Operator als zweiten Parameter akzeptiert. Ebenso wie beim Query Builder verwendet der Operator standardmäßig einen Gleichheitsvergleich, wenn keiner angegeben wird. Der Standardvergleich wurde ebenfalls standardmäßig von strikt auf verlustfrei umgestellt. Wenn Sie einen strengen Vergleich wünschen, können Sie whereStrict() verwenden oder einfach === als Operator für where() verwenden.

Daher funktioniert das letzte Codebeispiel in der Frage ab Laravel 5.0 genau wie beabsichtigt:

$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

Ich muss darauf hinweisen, dass Kalleys Antwort einen kleinen, aber absolut kritischen Fehler enthält. Ich hatte einige Stunden damit zu kämpfen, bevor mir klar wurde: 

Innerhalb der Funktion erhalten Sie einen Vergleich, und daher wäre etwas wie dieses korrekter: 

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

Elegante Lösung für die Suche nach einem Wert ( http://betamode.de/2013/10/17/laravel-4-eloquent-check-if-there-is-a-model-mit-certain-key-value-pair -in-a-a-collection/ ) kann angepasst werden:

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

Ab Laravel 5.5 können Sie firstWhere () verwenden.

In deinem Fall:

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

Als obige Frage, wenn Sie die where-Klausel verwenden, müssen Sie auch die get-Methode verwenden, um das Ergebnis zu erhalten.

/**
*Get all food
*
*/

$foods = Food::all();

/**
*Get green food 
*
*/

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