ella-stinnes's avatar

Duplicate Query when Passing Eloquent Query to Blade Component

I have the following select blade component:

@props([
    'id' => '', 
    'options' => array(), 
    ])

<select name="{{ $id }}" id="{{ $id }}">

    @foreach($options as $value => $name)
        <option value="{{ $value }}">{{ $name }}</option>
    @endforeach
    
</select>

I'm then using this component as follows:

<x-input.field-select id="company_id" :options="\App\Models\Company::orderBy('name')->pluck('name', 'id')->toArray()" />

When debugging, I'm finding that the query is executing twice, but I don't understand why?

Amending my usage to the following solves the issue, but I'd like to understand why the above doesn't work as I think it looks cleaner:

@php
$options = \App\Models\Company::orderBy('name')->pluck('name', 'id')->toArray();
@endphp

<x-input.field-select id="company_id" :options="$options" />
0 likes
13 replies
Tray2's avatar

I would suggest moving the query from your view to your controller instead, and pass it to the view. Let the controller talk to the db.

1 like
ella-stinnes's avatar

Makes sense. The select is used on both the create and edit forms, therefore should I place the query in a generic method within the controller or the model?

Tray2's avatar

If you use the same query in two places, I'd suggest the model.

Glukinho's avatar

as I think it looks cleaner

Really? PHP Laravel specific code inside quotes, inside an attribute, inside an HTML-like tag, inside Blade view looks clean to you? My eyes bleed when I see it :(

Glukinho's avatar

Mostly the same as @tray2 told above: prepare data in controller, pass data to view, show already prepared data in view. It's basic MVC model and it makes sense.

ella-stinnes's avatar

Thank you.

I know the drop down is currently used on the create and edit pages. It could potentially be required when filtering the index page or other areas of the system. Would the query then move to the model instead of the controller in this scenario (when other controllers require the same query)?

Glukinho's avatar

When your model has a query used here and there in your app then utilize model scope: https://laravel.com/docs/12.x/eloquent#local-scopes

As for me, I don't think ->pluck(...)->toArray() should be done in a model, it is what I call "data preparing", not "data storing" which is model's responsibility. I would do it in a controller or something like CompanyService. Of course, this is not a dogma, you can do whatever you prefer.

Snapey's avatar

one line query I would NOT create a method for

Just put it in the controller and pass $options to the view, then move on with more important stuff

If you think the query is complex or might change over time then feel free to centralise it.

Glukinho's avatar

Answering your question, most probably the code is passed to a component as a code (not as evaluated value) and is evaluated twice somewhere inside blade parser, due to a bug. Maybe foreach loop is involved.

Did you try to upgrade Laravel to latest? Bugs are fixed constantly.

ella-stinnes's avatar

Thank you, I looked at the parsed view in the framework storage and the query is duplicated on the following two lines:

<?php $component = Illuminate\View\AnonymousComponent::resolve(['view' => 'components.input.field-select','data' => ['id' => 'company_id','options' => \App\Models\Company::orderBy('company_name')->pluck('company_name', 'id')->toArray()]] + (isset($attributes) && $attributes instanceof Illuminate\View\ComponentAttributeBag ? $attributes->all() : [])); ?>
<?php $component->withAttributes(['id' => 'company_id','options' => \Illuminate\View\Compilers\BladeCompiler::sanitizeComponentAttribute(\App\Models\Company::orderBy('company_name')->pluck('company_name', 'id')->toArray())]); ?>

I'm running the latest version of the framework.

Glukinho's avatar

Sorry, I don't know if it is a bug or normal behaviour.

Snapey's avatar

If this query is for use solely with a component, then you could create a class based component and do the data preparation in the class rather than the blade file.

1 like

Please or to participate in this conversation.