Search code examples
phplaravel-5laravelcollective

Laravel 5.2 injecting object into Blade template


I am binding an employee model into a Blade template, and want to place the result of an eager load relation into a field.

In my controller I build the collection for the page as:

$employee = User::with('country', 'activeOrganisationRole')->first();

My form open statement is:

{!! Form::model($employee, ['route' => ['employee.role', $employee->uuid], 'method' => 'POST']) !!}

So I want to populate $employee->country->name into an input Laravel Collective form::text statement, but I cannot get the country name to load. All other fields on the form load perfectly from the parent collection.

My Country field is:

<div class="form-group">
    <label for="phone" class="control-label">Country</label>
    {!! Form::text('country', null, ['id'=>'country', 'placeholder' => 'Country', 'class' => 'form-control']) !!}
</div>

The above country field loads the entire relation result into the input. What is the correct syntax for injecting $employee->country->name into this input?

By the way , this works perfectly, but I have learned nothing by doing this way!

<label for="title" class="control-label">Country</label>
<input id="country" class="form-control" value="{!! $employee->country->country !!}" readonly>

Solution

  • I believe the FormBuilder in LaravelCollective uses data_get (a Laravel helper function) to get attributes from objects. However, dots in names of elements is kind of strange so I delved a little into the source for you.

    You have one of the following choices (ordered by my preference):

    1. You can add a method called getFormValue in your Employee model. This takes a single parameter which is the name of the form element that is requesting a value. Implement it something like this:

      public function getFormValue($name)
      {
          if(empty($name)) {
              return null;
          }
      
          switch ($name) {
              case 'country':
                  return $this->country->country;
          }
      
          // May want some other logic here:
          return $this->getAttribute($name);
      }
      

      I couldn't really find any documentation on this (such is sometimes the way with Laravel). I only found it by trawling the source - although it really is easy with PhpStormShamless Plug

      The downside with this is that you lose the transformation and attempt at extracting values from your employee object with data_get.

    2. Change the name of your text field to be country[country]. In the source the builder replaces '[' and ']' with '.' and '' respectively when looking in an object for an attribute. This means data_get will be looking for country.country.

    3. I put this here for people with the issue in the future, but it's not recommended.

      Give your employee model a getCountryAttribute method. As explained under the "Form Model Accessors" heading in the documentation, you can overwrite what gets returned from $employee->country. This means you can't access the real object though.