Blog coding and discussion of coding about JavaScript, PHP, CGI, general web building etc.

Monday, June 6, 2016

Laravel: Get Object From Collection By Attribute

Laravel: Get Object From Collection By Attribute


In Laravel, if I perform a query:

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

...then $foods is an Illuminate Collection of Food model objects. (Essentially an array of models.)

However, the keys of this array are simply:

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

...so if I want to alter, say, the Food object with an id of 24, I can't do this:

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

...because this will merely alter the 25th element in the array, not the element with an id of 24.

How do I get a single (or multiple) element(s) from a collection by ANY attribute/column (such as, but not limited to, id / color / age / etc.)?

Of course, I can do this:

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

...but, that's just gross.

And, of course, I can do this:

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

...but that's even more gross, because it performs an additional unnecessary query when I already have the desired object in the $foods collection.

Thanks in advance for any guidance.

EDIT:

To be clear, you can call ->find() on an Illuminate Collection without spawning another query, but it only accepts a primary ID. For instance:

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

However, there is still no clean (non-looping, non-querying) way to grab an element(s) by an attribute from a Collection, like this:

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

Answer by kalley for Laravel: Get Object From Collection By Attribute


You can use filter (under Support), like so:

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

filter will also return a Collection, but since you know there will be only one, you can call first on that Collection.

Answer by squaretastic for Laravel: Get Object From Collection By Attribute


I have to point out that there is a small but absolutely CRITICAL error in kalley's answer. I struggled with this for several hours before realizing:

Inside the function, what you are returning is a comparison, and thus something like this would be more correct:

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

Answer by Rohith Raveendran for Laravel: Get Object From Collection By Attribute


Since I don't need to loop entire collection, I think it is better to have helper function like this

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

Answer by softfrog for Laravel: Get Object From Collection By Attribute


Elegant solution for finding a value (http://betamode.de/2013/10/17/laravel-4-eloquent-check-if-there-is-a-model-with-certain-key-value-pair-in-a-collection/) can be adapted:

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

Answer by Ziad Hilal for Laravel: Get Object From Collection By Attribute


Use the built in collection methods contain and find, which will search by primary ids (instead of array keys). Example:

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

contains() actually just calls find() and checks for null, so you could shorten it down to:

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

Answer by Maksym Cierzniak for Laravel: Get Object From Collection By Attribute


Laravel provides a method called keyBy which allows to set keys by given key in model.

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

will return the collection but with keys being the values of id attribute from any model.

Then you can say:

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

and it will grab the correct item without the mess of using a filter function.


Fatal error: Call to a member function getElementsByTagName() on a non-object in D:\XAMPP INSTALLASTION\xampp\htdocs\endunpratama9i\www-stackoverflow-info-proses.php on line 72

0 comments:

Post a Comment

Popular Posts

Powered by Blogger.