Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

bellaratmelia's avatar

Populate Dropdownlist with array of strings at the controller

Hi guys,

So i need some help with populating data into an array at the controller, which i can later pass to my view's dropdownlist as its data. I am not sure if the list() function can help. But in my scenario, i am not intending to give my the options an ID value.

Anyway this is my code.

$room2 = Room::find(4);

foreach ($room2->equipments as $eq)
{               
    $eqCatName = EquipmentCategory::where('equipmentcategory_id' , '=', $eq->equipmentcategory_id)->Select('equipmentcategory_name')->first();              
    $fullName = $eqCatName->equipmentcategory_name." - ".$eq->equipment_name." - ".$eq->pivot->quantity;
    //THis will translate to "Logistic - Chairs - 24" for example
}

Thanks in advanced!

0 likes
18 replies
grahamd's avatar

If you really don't want to use the value attribute of the option, and just use the options content between the close tags it's probably still a good idea to define the 'value'.

You can tackle this by using http://php.net/manual/en/function.array-combine.php to create an array combining the same data as key and value, or by using lists(), but that'd probably require a little more tinkering since you've set full name as a combination of fields.

Unless anyone else has managed to find out how to turn off value in Laravel's Form Builder, then array-combine would probably be the 'quickest'.

You could also look at extending and overriding Illuminate\Html\FormBuilder's method 'option'.

bellaratmelia's avatar

Hi grahamd, Thanks for the reply.

Hi anyone,

What if i were to assign a random value example value=0 for "Logistic - Chairs - 24". Do you have any idea how i can translate my code to an array which i can pass onto the view with the laravel list() function. Which i can call with the

 {{ Form::select('fullname', $fullname, null, array('class'=>'form-control input-md')) }}  

code at my view.

Thanks in advanced!

JarekTkaczyk's avatar

@bellaratmelia I have no idea what you want to achieve, bc the question doesn't tell us, but here's how to get the list for a select:

// simple select, no groups
$users = User::lists('name', 'id');

// add first, empty entry:
$users = ['' => 'Choose a user'] + $users;

// get some users to be selected
$selectedUsers = User::where('account_id', 5)->lists('id');

// print the dropdown
Form::select('users[]', $users, $selectedUsers, ['multiselect'])

Of course you can do the same using DB::table('users')....

lists('name', 'id') returns this for example:

[1] > User::take(5)->lists('name', 'id');
// array(
//   1 => 'Random name',
//   3 => 'John Doe',
//   4 => 'Jane Doe',
//   6 => 'yetAnotherOne',
//   7 => ''
// )

so id becomes the array key, and name becomes the value - it's ready to use in the Form::select in such form.

If that's not what you wanted, then please rephrase the question and specify the output you'd like to get.

bellaratmelia's avatar

Hi @JarekTkaczyk This is what i am trying to achieve.

// array(
//   x => 'Logistic - Chairs - 24',
//   x => 'Logistic - Table - 33',
//   x => 'Audio - Speaker - 8',
//   x => 'Audio - Mic - 4',
// )

these values are generated at my controller with this:

 $fullName = $eqCatName->equipmentcategory_name." - ".$eq->equipment_name." - ".$eq->pivot->quantity;
 //THis will translate to "Logistic - Chairs - 24" for example

The value isnt really important, i dont use it in my scenario.

So what i can't figure out is, (hoping you can help me) Is how i can create an array for $fullname and pass it to the view so i can do this at the view: Form::select('fullname', $fullname, null, array('class'=>'form-control input-md')) }}

JarekTkaczyk's avatar
Level 53

In your current setup this will do:

$fullNames = [];

foreach ($room2->equipments as $eq)
{               
  $eqCatName = EquipmentCategory::where('equipmentcategory_id' , '=', $eq->equipmentcategory_id)->Select('equipmentcategory_name')->first();              
  $fullNames[] = $eqCatName->equipmentcategory_name." - ".$eq->equipment_name." - ".$eq->pivot->quantity;
}

However, this is bad ;) It calls unknown number of queries and loads bunch of objects just to get simple array, so I would rather do it in the query, something like this - adjust to your schema:

$fullnames = SomeModel::join('pivot_table', 'model.id', '=', 'pivot_table.model_id')
    ->join('other_model', 'other_model.id', '=', 'pivot_table.other_model_id')
    ->selectRaw("concat_ws(' - ', model.name, other_model.name, pivot_table.quantity) as fullname")
    ->lists('fullname');

or using relationships and eager loading, to avoid those all queries in a foreach loop. Tell me the relations and/or tables schema if you have problems with this.

4 likes
bellaratmelia's avatar

Thanks @JarekTkaczyk, It works like a charm.

For anyone that needs reference.

Controller
$eqfullname = Room::join('room_equipment', 'room.room_id', '=', 'room_equipment.room_id')
        ->join('equipment', 'equipment.equipment_id', '=', 'room_equipment.equipment_id')
        ->join('equipment_category', 'equipment.equipmentcategory_id', '=', 'equipment_category.equipmentcategory_id')
        ->selectRaw("concat_ws(' - ', equipment_category.equipmentcategory_name, equipment.equipment_name, room_equipment.quantity) as fullname")
        ->lists('fullname');

View
{{Form::select('SelectedValues[]',$eqfullname,null,array('class' => 'form-control','id'=>'SelectedValues','size' =>'5')) }}              
Jeffberry's avatar

I'm not sure why array_combine was suggested here. You can use the lists method without specifying an ID like so:

$users = User::lists('name');

There is no need to use array_combine to add keys, remove the value attribute in blade, or circumvent this situation in any way. All arrays have keys -- always. If you don't specify the keys then they are just going to be incrementing integer keys (0-n). The select will still be built appropriately.

@bellaratmelia just a word of advice / favor to ask you, please put your code in code blocks with highlighting so that it can be read. It's difficult to read your code when it's just mixed in with your paragraph. It's easy to do, see here: https://help.github.com/articles/github-flavored-markdown/#syntax-highlighting ; you would just use "php" instead of "ruby" obviously.

Your join seems like it would work fine though :) I think the same thing could've been accomplished with Eloquent though, would be the same result but would look a little bit cleaner.

bellaratmelia's avatar

Hi @Jeffberry,

thanks for the code-block advice I didnt know that i can do that. It sure looks alot better now. Anyway, do you have any idea how to translate this

$eqfullname = Equipment::join('room_equipment', 'equipment.equipment_id', '=', 'room_equipment.equipment_id')             ->join('equipment_category', 'equipment.equipmentcategory_id', '=', 'equipment_category.equipmentcategory_id')         ->selectRaw("concat_ws(' - ', equipment_category.equipmentcategory_name, equipment.equipment_name,         room_equipment.quantity) as fullname") ->lists('fullname');

to eloquent codes? Would sure appreciate the extra knowledge. Thanks in advanced!

bellaratmelia's avatar

Hi @JarekTkaczyk,

I created the query with the example you provided. Some::Model. I assume to replace some model with room model. Can u advice me on the better way to draft my query?

Thanks in advance!

Jeffberry's avatar

Note that it's midnight here and I just got home from a 10 hour code binge at work, so my mind is almost done, but this is how I imagine it could be done. Understand that I know very little of your schema or your current setup. Also know that this approach will require quite a few more queries than @JarekTkaczyk's query will, however the benefits are that it is cleaner, easier to maintain, and it gets the relationships setup in Eloquent which you can reuse infinitely.

We start with the Room. If I read your queries correctly, every room can have many different equipments in it. So we setup that relationship.

$room = Room::find(4);
d($room->equipment); // array of all pieces of equipment in the room

class Room extends Model {

    public function equipment()
    {
        return $this->belongsToMany('Equipment')->withPivot('quantity');
    }
}

Since we got our Room set up and we know that it has Equipment in it, let's create the Equipment. Based on your query I noticed that all equipment can belong to a (single) certain category. So we set up that relationship here. I wasn't a big fan of your choice in key names on this one, it deviates from Laravel's recommendation of CamelCase being translated to snake_case). Anyway, we already established that all Equipment belongs to a Room. So we setup the inverse of the relationship we did on the Room here. I noticed that you have a "quantity" field on your pivot table, so you'll see we're pulling that in here too. You'll see the "getCategoryFullName" attribute -- we'll come back to that.

foreach (Equipment::all() as $equipment)
{
    d($equipment->equipmentCategory); // will dump out the category that each piece of equipment belongs to. 
}

class Equipment extends Model {

    protected $with = ['full_name'];

    public function equipmentCategory()
    {
        return $this->belongsTo('EquipmentCategory', 'equipmentcategory_id', 'equipmentcategory_id');
    }

    public function room()
    {
        return $this->belongsToMany('Room')->withPivot('quantity');
    }

    public function getFullNameAttribute()
    {
        return sprintf(
            '%s - %s - %d',
            $this->equipmentCategory->equipmentcategory_name,
            $this->equipment_name,
            $this->pivot->quantity
        );
    }
}

Lastly, we create the EquipmentCategory, since we already know our Equipment has to belong to it. This one is easy and the only relationship we'll set up here is the inverse of the one we did for the Equipment. This relationship will just list all Equipment that belongs to that EquipmentCategory. (Wasn't a huge fan of your column names on this one either.)

$equipmentCategory = EquipmentCategory::find(7);

d($equipmentCategory->equipment); // array of all Equipment that belongs to EquipmentCategory#7

class EquipmentCategory extends Model {

    public function equipment()
    {
        return $this->hasMany('Equipment', 'equipmentcategory_id', 'equipmentcategory_id');
    }
}

Now, the reason we did this, let's go back to the Equipment model. We've set up all relationships between these three objects, essentially we've programmatically accomplished the joins you had written. What this allows us to do is add an easy property onto each piece of Equipment that also gets you the EquipmentCategory name as well as the quantity of that equipment. All we have to do here is call the property.

$equipment = Equipment::find(13);

echo $equipment->full_name; // If I did all this write, this should print out your example of "Audio - Mic - 4"

class Equipment extends Model {

    protected $with = ['full_name'];

    /* snip snip */

    public function getFullNameAttribute()
    {
        return sprintf(
            '%s - %s - %d',
            $this->equipmentCategory->equipmentcategory_name,
            $this->equipment_name,
            $this->pivot->quantity
        );
    }
}

In order to get a list of all pieces of Equipments' full name, you could do this:

$equipmentList = Equipment::all()->list('full_name');

Want just a list of Equipment from a certain room? No problem (this is why having all your relationships set up is nice).

$room2 = Room::find(2);
$equipmentList = $room2->equipment->list('full_name');

I hope I got all that right. I also wouldn't expect you to even put this to the test because it would be a lot to set up, but I figured I'd just show you another method (and probably the more OOP approach) to get this done. The downside is it will take more than the single query from the join you've already derived :)

JarekTkaczyk's avatar

@Jeffberry There are a few things here:

  1. I don't find it simpler in fact (and mind that I am an Eloquent evangelist)
  2. You probably meant appends('full_name'), definitely not with('full_name')
  3. This will work only in the context of a relation, so you can't rely on $this->pivot->quantity, because it will cause trying to get property of non-object whenever you use toArray/toJson on Equipment not being loaded as a related (because of append above), like Equipment::all()->lists('full-name');
  4. With this approach you're loading whole Collections of Models just to get a simple, flat array
bellaratmelia's avatar

Hey @JarekTkaczyk

You are right. It sure looks more simpler now.

$eqfullname = Equipment::join('room_equipment', 'equipment.equipment_id', '=', 'room_equipment.equipment_id')             ->join('equipment_category', 'equipment.equipmentcategory_id', '=', 'equipment_category.equipmentcategory_id')         ->selectRaw("concat_ws(' - ', equipment_category.equipmentcategory_name, equipment.equipment_name,         room_equipment.quantity) as fullname") ->lists('fullname');

Thanks for the advice! I will edit the previous query too for people referencing.

Jeffberry's avatar

@JarekTkaczyk - I can't say that I agree with much of your statement. The first example here is exponentially simpler than the second -- both for readability and reusability:

$equipmentList = Equipment::all()->list('full_name');
$eqfullname = Equipment::join('room_equipment', 'equipment.equipment_id', '=', 'room_equipment.equipment_id')             ->join('equipment_category', 'equipment.equipmentcategory_id', '=', 'equipment_category.equipmentcategory_id')         ->selectRaw("concat_ws(' - ', equipment_category.equipmentcategory_name, equipment.equipment_name,         room_equipment.quantity) as fullname") ->lists('fullname');

You are correct, I did mean appends -- my mistake. He could use "with" if he wished to eager load these relationships though.

As for it only working in a context of a relation -- so will your manual join query you've built. If all parts of the relationships do not exist, your result will be void, that is after all the definition of an INNER JOIN. Avoiding the undefined property error would be simple -- you can either put a few checks in place to make sure that $this->pivot is set, or you can simply $this->load() the relationship inside the FullNameAttribute method. Again, this was not a working example, it was a demonstration of the alternative.

You are correct, this example does load an entire collection of models for a flat array; this could also be avoided by creating a helper function that eager loads these models only with the columns needed, which would hardly be more taxing than the manual join -- objects are very cheap in PHP, it rather disappoints me when programmers are afraid to use them. However, that is why I stated several times that although this was definitely not the more efficient solution -- it is absolutely the simpler one. My reason for that belief is because these are relationships between his entities, and therefore it makes sense those relationships should be programmatically defined. The relationships set up through Eloquent are reusable, whereas every time he wants a slight alternative of what the manual query returns, he has to duplicate that code -- that's a potential mess for a big application. The benefits of having these relationships set up are infinite, whereas the join simply returns a concatenated un-reusable string. Why even use the query builder if all you are trying to do is write a manual statement? I find this to be even simpler, at least this way the query is in a valid SQL syntax, and if you're truly concerned with the overhead a model causes then this would also remove the overhead of the query builder -- but like I said before, objects are very cheap, so Eloquent all the way for me!

select concat_ws(' - ', equipment_category.equipmentcategory_name, equipment.equipment_name,         room_equipment.quantity) as fullname 
from `listings` 
inner join `room_equipment` 
    on `equipment`.`equipment_id` = `room_equipment`.`equipment_id` 
inner join `equipment_category` 
    on `equipment`.`equipmentcategory_id` = `equipment_category`.`equipmentcategory_id` 
where `listings`.`deleted_at` is null
JarekTkaczyk's avatar

@Jeffberry Well.. As far as I can tell, it's her not him, who asked the question. I can see your point is to say I'm right - you tell me you can't agree with much, while 3 of 4 points are facts, so hard to agree or not.. I don't think there's any sense in such discussion anymore.

Just for the posterity's sake and for you to learn why:

  1. $this->pivot from your example is never set on the Equipment model, because it works in the context of relation - you didn't understand that one at all. It means, that Equipment model must be loaded as relation in order to have pivot relation set (yes, pivot is set as a relation).

  2. Even if it wasn't the case, check this:

    Equipment::all()->lists('full_name'); // n+1 qeries, so eager load
    Equipment::with('equipmentCategory')->get()->lists('full_name'); // now we got all the equipment rows, so:
    // array(
    // 'some - full name - with quantity',
    // 'another -full name - with quantity',
    // ...
    // NULL,
    // ...
    // )
    

    there is NULL for each Equipment that has no related EquipmentCategory - definitely wrong. You cannot adjust accessor in any way to avoid this. And that is why there's an inner join.

  3. There's your final piece then:

    $rooms = Room::with(['equipment' => function ($q) {
       $q->has('equipmentCategory');
    }, 'equipment.equipmentCategory'])->get();
    
    $equipment = (new Equipment)->newCollection();
    
    foreach ($rooms as $room) {
      $equipment = $equipment->merge($room->equipment);
    }
    
    $fullNames = $equipment->lists('full_name');
    

Still that simple? Not mentioning it returns different thing - Eloquent will override each equipment in the final collection, so you will get no duplicates. While it's ok for models, it's not valid in this case, since pivot->quantity is different for each room-equipment association.

You'd better just hide these joins behind a method on the Equipment model, even a public static method would do in this case:

// this is simple:
Equipment::getFullNames();

// model
public static function getFullNames()
{
  // all the joins go here
}
Jeffberry's avatar

My point is not to say I'm right, my point is to express the benefit of using Laravel, Eloquent, and their relationships as they were meant to be used. I tell you I can't agree with much because you only expressed one view. The fact that it's not as efficient as a single query? Absolutely it's not (in the technical standpoint). Is it more efficient for the programmer? Absolutely because it is reusable for whatever other use cases he may come up with. I stated that in my initial post. The fact that I used $with by mistake instead of $appends? Yeah. Oops. The third "fact" is that pivot is undefined, however that is an easy issue to resolve. You'd possibly just need to call the method in a different way, still simpler in my mind:

Room::find(4)->equipment->list('full_name')

I don't know why instead of trying to evolve an idea and show some alternatives you're choosing to argue with me. You go as far as to insult me. That is not beneficial to any community. Trust me, I understand very well how Eloquent works, I understand very well how the relationships work. I work exclusively with Laravel 40hrs/week. To tell me that Eloquent is not capable of doing the same thing as the manually built query is ridiculous considering Laravel build's it's relationships using the same Query Builder join methods. The reasoning behind my approach is that the Eloquent relationships are significantly more useful than littered code. They are re-usable. They're extendable. They're portable.

You're making an assumption that some of his equipment won't have a category. For all we know everything is assigned a category. According to you:

Equipment::all()->lists('full_name'); // n+1 qeries, so eager load
Equipment::with('equipmentCategory')->get()->lists('full_name'); // now we got all the equipment rows, so:
// array(
// 'some - full name - with quantity',
// 'another -full name - with quantity',
// ...
// NULL,
// ...
// )

A working solution:

$equipmentList = Equipment::all()->filter(function($model)
{
    return ! empty($model->equipmentCategory);
})->lists('full_name');

// array(
// 'some - full name - with quantity',
// 'another -full name - with quantity',
// )

Done. Want an even simpler solution?

class Equipment extends Model {

    protected $with = ['equipmentCategory'];

    public static function fullEquipmentList()
    {
        $equipmentList = self::all()->filter(function($model)
        {
            return ! empty($model->equipmentCategory);
        });

        return $equipmentList->list('full_name');
    }
}

d(Equipment::fullEquipmentList());

You seem to be trying to overcomplicate the solution and tell me that it simply will not work just to show that you are right. That is of no benefit to anybody and I don't much appreciate it. The fact is this is a pretty standard relationship he is doing and is absolutely possible through Eloquent models. My apologies for not assuming his schema and setting an entire environment up to give him a working example, my example was written here in this 3-inch tall text-box just to show what is possible.

You seem intelligent enough to reason through all this, and I feel that you could be helping in the situation by expanding upon the idea. I feel rather took-back that you would ask to hear my solution and then attack me in such a way instead of expanding on the alternative and expressing the power of the built in relationships. However, this is the internet and there seems to be argumentative people anywhere you go. I see no reason for me to continue conversing with you, you obviously are welcoming to my input and I will do my best to steer clear of you around here -- I hope you can work towards being more productive instead of going back and forth with another users' suggestion.

1 like

Please or to participate in this conversation.