Dans Laravel, si j'effectue une requête:
$foods = Food::where(...)->get();
... $foods
est alors une collection Illuminate d' Food
objets modèles. (Essentiellement un tableau de modèles.)
Cependant, les clés de ce tableau sont simplement:
[0, 1, 2, 3, ...]
... donc si je veux modifier, par exemple, l' Food
objet avec un id
de 24, je ne peux pas faire ceci:
$desired_object = $foods->get(24);
$desired_object->color = 'Green';
$desired_object->save();
... car cela modifiera simplement le 25e élément du tableau, pas l'élément avec un id
de 24.
Comment obtenir un (des) élément (s) unique (ou plusieurs) d'une collection par TOUT attribut / colonne (tel que, mais sans s'y limiter, id / couleur / âge / etc.)?
Bien sûr, je peux faire ceci:
foreach ($foods as $food) {
if ($food->id == 24) {
$desired_object = $food;
break;
}
}
$desired_object->color = 'Green';
$desired_object->save();
... mais c'est juste dégoûtant.
Et, bien sûr, je peux faire ceci:
$desired_object = Food::find(24);
$desired_object->color = 'Green';
$desired_object->save();
... mais c'est encore plus grossier , car il effectue une requête supplémentaire inutile lorsque j'ai déjà l'objet souhaité dans la $foods
collection.
Merci d'avance pour tous conseils.
ÉDITER:
Pour être clair, vous pouvez appeler ->find()
sur une collection Illuminate sans fraie une autre requête, mais il n'accepte une pièce d' identité primaire. Par exemple:
$foods = Food::all();
$desired_food = $foods->find(21); // Grab the food with an ID of 21
Cependant, il n'y a toujours pas de moyen propre (sans boucle, sans requête) de récupérer un ou plusieurs éléments par un attribut d'une collection, comme ceci:
$foods = Food::all();
$green_foods = $foods->where('color', 'green'); // This won't work. :(
filter()->first()
vous pouvez simplement appelerfirst(function(...))
collect([1, 2, 3, 4])->first(function ($value, $key) { return $value == 2; });
$desired_object = $food->where('id', 24)->first();
Laravel fournit une méthode appelée
keyBy
qui permet de définir des clés par clé donnée dans le modèle.$collection = $collection->keyBy('id');
retournera la collection mais avec les clés étant les valeurs d'
id
attribut de n'importe quel modèle.Ensuite, vous pouvez dire:
$desired_food = $foods->get(21); // Grab the food with an ID of 21
et il récupérera l'élément correct sans le désordre d'utiliser une fonction de filtre.
la source
$exceptions->keyBy(function ($exception) { return $exception->category_id . ' ' . $exception->manufacturer_id;
et utiliser->get($category->id . ' ' . $manufacturer->id)
after!keyBy
renvoie une nouvelle collection de ce dont je me souviens, pas sûr cependant, vous pouvez vérifierIlluminate/Support/Collection
pour le savoir. (Ne travaille pas à Laravel depuis un certain temps donc quelqu'un peut me corriger).À partir de Laravel 5.5, vous pouvez utiliser firstWhere ()
Dans votre cas:
$green_foods = $foods->firstWhere('color', 'green');
la source
Comme je n'ai pas besoin de boucler toute la collection, je pense qu'il est préférable d'avoir une fonction d'aide comme celle-ci
/** * 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; }
la source
Utilisez les méthodes de collection intégrées contain et find , qui effectueront une recherche par ID primaire (au lieu de clés de tableau). Exemple:
if ($model->collection->contains($primaryId)) { var_dump($model->collection->find($primaryId); }
contains () appelle en fait find () et vérifie la valeur null, vous pouvez donc le raccourcir à:
if ($myModel = $model->collection->find($primaryId)) { var_dump($myModel); }
la source
Je sais que cette question a été posée à l'origine avant la sortie de Laravel 5.0, mais à partir de Laravel 5.0, les collections prennent en charge la
where()
méthode à cet effet.Pour Laravel 5.0, 5.1 et 5.2, la
where()
méthode duCollection
ne fera qu'une comparaison égale. En outre, il effectue une comparaison stricte égale (===
) par défaut. Pour faire une comparaison lâche (==
), vous pouvez passerfalse
comme troisième paramètre ou utiliser lawhereLoose()
méthode.À partir de Laravel 5.3, la
where()
méthode a été étendue pour fonctionner davantage comme lawhere()
méthode du générateur de requêtes, qui accepte un opérateur comme deuxième paramètre. De même que le générateur de requêtes, l'opérateur utilisera par défaut une comparaison égale si aucune n'est fournie. La comparaison par défaut est également passée de strict par défaut à loose par défaut. Donc, si vous souhaitez une comparaison stricte, vous pouvez utiliserwhereStrict()
ou simplement utiliser===
comme opérateur pourwhere()
.Par conséquent, à partir de Laravel 5.0, le dernier exemple de code de la question fonctionnera exactement comme prévu:
$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');
la source
Je dois souligner qu'il y a une petite mais absolument CRITIQUE erreur dans la réponse de Kalley. J'ai lutté avec cela pendant plusieurs heures avant de réaliser:
À l'intérieur de la fonction, ce que vous retournez est une comparaison, et donc quelque chose comme ça serait plus correct:
$desired_object = $food->filter(function($item) { return ($item->id **==** 24); })->first();
la source
foreach()
exemple en termes de performances, car elle fait simplement le même type de boucle ... en fait, monforeach()
exemple est plus performant car il se rompt lors de la recherche du bon modèle. Aussi ...{Collection}->find(24)
saisira par clé primaire, ce qui en fait la meilleure option ici. Le filtre proposé par Kalley est en fait identique à$desired_object = $foods->find(24);
.**==**
opérateur, que fait-il?Solution élégante pour trouver une valeur ( http://betamode.de/2013/10/17/laravel-4-eloquent-check-if-there-is-a-model-with-certain-key-value-pair-in -a-collection / ) peut être adapté:
$desired_object_key = $food->array_search(24, $food->lists('id')); if ($desired_object_key !== false) { $desired_object = $food[$desired_object_key]; }
la source
Comme la question ci-dessus lorsque vous utilisez la clause where, vous devez également utiliser la méthode get Or first pour obtenir le résultat.
/** *Get all food * */ $foods = Food::all(); /** *Get green food * */ $green_foods = Food::where('color', 'green')->get();
la source