38

I have a collection of objects. Let's say the objects are tags:

$tags = Tag::all();

I want to retrieve a certain attribute for each tag, say its name. Of course I can do

foreach ($tags as $tag) {
    $tag_names[] = $tag->name;
}

But is there a more laravelish solution to this problem?

Something like $tags->name?

Antonio Carlos Ribeiro
  • 86,191
  • 22
  • 213
  • 204
severin
  • 2,106
  • 1
  • 17
  • 25
  • `$tags->name` should work – Patrick Reck Aug 06 '13 at 21:24
  • I had also hoped so at first, but it doesn't: `Undefined property: Illuminate\Database\Eloquent\Collection::$name` – severin Aug 06 '13 at 21:30
  • @severin $tags is a collection of object not a single object that has name property. You need to iterate through $tags to get each tag name. It doesn't make sense to get name property from tags. How will it assume that which name property you actually want to print. – Basheer Kharoti Nov 12 '15 at 11:27

4 Answers4

73

Collections have a lists method similar to the method for tables described by @Gadoma. It returns an array containing the value of a given attribute for each item in the collection.

To retrieve the desired array of names from my collection of tags I can simply use:

$tags->lists('name');

Update: As of laravel 5.2 lists is replaced by pluck.

$tags->pluck('name');

More specifically, the laravel 5.2 upgrade guide states that "[t]he lists method on the Collection, query builder and Eloquent query builder objects has been renamed to pluck. The method signature remains the same."

severin
  • 2,106
  • 1
  • 17
  • 25
  • The `lists` method is a very nice finding. – Rico Leuthold Aug 23 '13 at 10:51
  • 1
    In case of creating html select form, lists works too good: `Form::select('subcategory', array(null=>'Please Choose') + $category->firstSubcategories->lists('name', 'id'))` – Bishal Paudel Dec 14 '14 at 13:56
  • 1
    @BishalPaudel or you can do `$firsSubcategories = $category->firstSubcategories->lists('name', 'id');` in the controller, then `Form::select('subcategory', array(null=>'Please Choose') +$firsSubcategories )`, in blade, all the same though. – briankip Feb 24 '15 at 14:00
  • 1
    @deprecated since version 5.2. Use the "pluck" method directly. – ruuter Jan 12 '16 at 10:09
26

Yep, you can do it nice and easily. As the Laravel 4 Documentation states, you can do

Retrieving All Rows From A Table

$users = DB::table('users')->get();

foreach ($users as $user)
{
var_dump($user->name);
}

Retrieving A Single Row From A Table

$user = DB::table('users')->where('name', 'John')->first();

var_dump($user->name);

Retrieving A Single Column From A Row

$name = DB::table('users')->where('name', 'John')->pluck('name');

Retrieving A List Of Column Values

$roles = DB::table('roles')->lists('title');

This method will return an array of role titles. You may also specify a custom key column for the returned array:

$roles = DB::table('roles')->lists('title', 'name');

Specifying A Select Clause

$users = DB::table('users')->select('name', 'email')->get();

$users = DB::table('users')->distinct()->get();

$users = DB::table('users')->select('name as user_name')->get();

EDIT:

The above examples show how to access data with the help of Laravel's fluent query builder. If you are using models you can access the data with Laravel's Eloquent ORM

Because Eloquent is internaly using the query builder, you can without any problem do the following things:

$tag_names = $tags->lists('tag_name_label', 'tag_name_column')->get();

which could be also done with:

$tag_names = DB::table('tags')->lists('tag_name_label', 'tag_name_column')->get();
Benubird
  • 18,551
  • 27
  • 90
  • 141
Gadoma
  • 6,475
  • 1
  • 31
  • 34
  • Thanks. This did in fact lead me to an appropriate solution, but there seems to be some confusion in your answer between DB methods and methods that apply to collections. – severin Aug 08 '13 at 07:56
  • Edited as per your comment. Regards, – Gadoma Aug 08 '13 at 08:47
  • I think, in your Edit it should be Tag::lists('tag_name_label')->get(); – Anji Dec 02 '14 at 05:08
8

Here are a few snippets from my own experimentation on the matter this morning. I only wish (and maybe someone else knows the solution) that the Collection had a $collection->distinct() method, so I could easily generate a list of column values based on an already filtered collection.

Thoughts?

I hope these snippets help clarify some alternative options for generating a list of unique values from a Table, Collection, and Eloquent Model.

Using a Collection (Happy)

/**
 * Method A
 *     Store Collection to reduce queries when building multiple lists
 */
$people = Person::get();
$cities = array_unique( $people->lists('city') );
$states = array_unique( $people->lists('state') );
// etc...

Using an Eloquent Model (Happier)

/**
 * Method B
 *     Utilize the Eloquent model's methods
 *     One query per list
 */
// This will return an array of unique cities present in the list
$cities = Person::distinct()->lists('city');
$states = Person::distinct()->lists('state');

Using an Eloquent Model PLUS Caching (Happiest)

/**
 * Method C
 *     Utilize the Eloquent model's methods PLUS the built in Caching
 *     Queries only run once expiry is reached
 */
$expiry = 60; // One Hour
$cities = Person::remember($expiry)->distinct()->lists('city');
$states = Person::remember($expiry)->distinct()->lists('state');

I would love to hear some alternatives to this if you guys have one!

@ErikOnTheWeb

Erik Aybar
  • 4,761
  • 1
  • 23
  • 29
5

You could use array_column for this (it's a PHP 5.5 function but Laravel has a helper function that replicates the behavior, for the most part).

Something like this should suffice.

$tag_names = array_column($tags->toArray(), 'name');
Jason Lewis
  • 18,537
  • 4
  • 61
  • 64