Clayton Leis
Clayton Leis

Reputation: 1298

How to use a checkbox group with Laravel's from model binding

I'm trying to save a checkbox group as a serialized string in my main model's database table. AudienceGroups is simply a property of my main eloquent model. If I simply do

{{Form::checkbox('AudienceGroups[]', 'preschool');}}
{{Form::checkbox('AudienceGroups[]', 'elementary');}}

with no logic in my model, then the database column is set as the string Array. If I drop the brackets and just use {{Form::checkbox('AudienceGroups', 'preschool');}} then the column is set to the value of the last checkbox, in my case "seniors".

If I serialize the array before saving the instance of my model, it saves as a serialized array like it's supposed to, but I'm having trouble getting it to repopulate the proper checkboxes on page load (from old input or from the the saved model).

How should I attack this? Serialize the array myself and then use my own logic to control the third parameter to Form::checkbox() which controls the checked status? If so, can someone help me with that bit. I attempted it with Input::old and in_array but could never get it to work.

Thanks

Upvotes: 2

Views: 8477

Answers (2)

Clayton Leis
Clayton Leis

Reputation: 1298

Update

Looks like the html helper was removed from the core repo without this ever being fixed. https://github.com/laravel/framework/issues/5078


The problem I was running into was that the third parameter of Form::checkbox() doesn't function as expected when form-model binding is used.

The laravel documentation states that the value priority is:

  1. Session Flash Data (Old Input)
  2. Explicitly Passed Value
  3. Model Attribute Data

However, if you look at getCheckboxCheckedStatus() in /Illuminate/Html/FormBuilder.php, you'll see that the priority for checked status is actually:

  1. Old Input
  2. Model Data
  3. Explicitly Passed Value

    protected function getCheckboxCheckedState($name, $value, $checked)
    {
        if (isset($this->session) && !$this->oldInputIsEmpty()
            && is_null($this->old($name))
        ) {
            return false;
        }
        if ($this->missingOldAndModel($name)) {
            return $checked;
        }
        $posted = $this->getValueAttribute($name);
        return is_array($posted) ? in_array($value, $posted) : (bool)$posted;
    }
    


While I was in the code I also saw that Laravel has in_array built in provided that the parameter is an array. So I unserialized $myModelInstance->AudienceGroups right before calling View::make() in my controller.

Upvotes: 2

Marcin Nabiałek
Marcin Nabiałek

Reputation: 111859

First, it's not a best solution to put properties serialized in one column. You should not do that because if you want to search something in future in DB for this data you won't be able to do that.

Solution for your problem is not complicated I think.

I've prepared 2 simple routes:

Route::get('/checkbox',function() {

    // normally you would get it from model and unserialize it
    $fromModel = ['preschool','elementary','something'];

    return View::make('form')->with('fromModel',$fromModel);

});

Route::post('/checkbox-post',function() {

    $agroups = Input::get('AudienceGroups');

    foreach ($agroups as $item) {
        echo $item."<br />";

    }
    $toModel = serialize($agroups);

    echo $toModel;

    // now you insert it into model

});

and form:

{{ Form::open(['url' => 'checkbox-post', 'role' => 'form']) }}
Preschool:
{{Form::checkbox('AudienceGroups[]', 'preschool', (in_array('preschool', $fromModel) ? true : false))}}<br />

Elementary:
{{Form::checkbox('AudienceGroups[]', 'elementary', (in_array('elementary', $fromModel) ? true : false))}}<br />

Something else:
{{Form::checkbox('AudienceGroups[]', 'somethingelse', (in_array('somethingelse', $fromModel) ? true : false))}}<br />

Something:
{{Form::checkbox('AudienceGroups[]', 'something', (in_array('something', $fromModel) ? true : false))}}<br />

{{Form::submit('Send')}}

{{ Form::close() }}

You can run it using http://localhost/yourproject/checkbox - form is initalized with 3 checkbox checked. In blade you can use in_array to check correct checkboxes and in POST route you can simple use this Input::get('AudienceGroups') as array and serialize it.

Upvotes: 2

Related Questions