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

rbroberts's avatar

How to validate a checkbox as boolean for a form submission

When submitting a form for a create, I wanted to take the shortcut of passing the validated input directly into the model. But...one of the fields is an "active" flag. In my form, I have this:

<div class="input-group">
    <input type="hidden" name="active" value="0">
    <input class="checkbox" type="checkbox" name="active" id="active" id="active"
            @if($person->active) checked @endif value="1">
</div>

The class Illuminate\Validation\Concerns\ValidatesAttributes includes a validateBoolean which looks like it should accept the 0 and 1 strings. But... form submission always fails on that attribute. I know its that one, because if I put a dd($request) just after the validation, it never gets there unless I remove the validation for the boolean:

public function update(Request $request, Person $person)
{
    $validatedAttributes = request()->validate([
        'first_name' => 'required',
        'last_name' => 'required',
        'dob' => 'date_format:Y-m-d|nullable',
        'email' => 'email:rfc,dns',
        'bsa_id' => 'integer|min:1|nullable',
        'active' => 'boolean'
    ]);
    $person->update($validatedAttributes);
    return view('person.show', ['person' => $person]);
}

If I remove the active attribute validation, it hits the dd.

So...is there some magic I'm missing to get this to validate, or is this shortcut just not possible with a checkbox in the form?

0 likes
13 replies
rbroberts's avatar

What I've ended up doing, which works but obviously can't be collapsed down to a since statement, is this

public function update(Person $person)
{
    $validatedAttributes = request()->validate([
        'first_name' => 'required',
        'last_name' => 'required',
        'dob' => 'date_format:Y-m-d|nullable',
        'email' => 'email:rfc,dns',
        'bsa_id' => 'integer|min:1|nullable'
    ]);
    $validatedAttributes['active'] = request('active');
    $person->update($validatedAttributes);
    return view('person.show', ['person' => $person]);
}

What I'd really love is for the validation pass through the value as okay. Eloquent seems to convert string "1" or "0" to an actual boolean for the insert/update, so this works, but I really need to add an extra manual validation for safety.

jlrdw's avatar

So you are saying it has to be checked? Is that correct?

rbroberts's avatar

No, I'm not saying it has to be checked. It has to be effectively true or false, and the hidden input insures that the form submits active="0" if the box is not checked, but if it is checked, the form submits active="1".

Apart from paranoia, that's sufficient. If the post is coming from my form, those are the only two values it can get. What I don't understand is, given there is a validateBoolean method, why it fails on that variable whether the box is checked or not. ValidatesAttributes.php has this code:

public function validateBoolean($attribute, $value)
{
    $acceptable = [true, false, 0, 1, '0', '1'];
     return in_array($value, $acceptable, true);
}

So I expected that by flipping over to use 0|1, I'd be good for the validator. But I'm not.

rbroberts's avatar

Ah, well, it looks like ValidateAttributes.php is probably not what is being called for the form validation. That's what I get for poking around where I don't understand. Looks like that is probably being called by the database code which is why they 0|1 are fine being passed straight to the model for update.

jlrdw's avatar

Nothing is passed if a checkbox isn't checked.

You have to use has request:

if ($request->has('active')) {
    // do whatever
}

Also https://laracasts.com/discuss/channels/general-discussion/blade-checkbox-and-eloquent

Also if that field is a tinyint, really validation is a mute point, it's going to be a 0 or 1. I usually don't llow nulls, and set default to 0.

in php

$adopted = (isset($_POST['adopted']) == '1' ? '1' : '0');

But just use laravel's request, which Symfony uses anyway, but handles safely.

1 like
rbroberts's avatar

Uhm, something is passed; which is the point of the hidden input. But I can see why using has() without the hidden input would be cleaner.

jlrdw's avatar

Well, if you are passing a one or a zero just store it. Why bother validating it's going to be a 1 or a 0.

Basically if validating you are saying This has to be a 1 or 0. When it can only be a 1 or a 0 no matter what.

Again validating a tinyint is a mute point.

patrickcm's avatar

OP, your code as originally posted should work I would think... what does dd($_POST) (assuming it was POSTed) look like when validation fails? What are the actual validation error messages from the validator for the "active" field?

You can also do this without the hidden input by simply using the sometimes rule if you have a default value for 'active' to 0.

'active' => 'sometimes|boolean'

$adopted = (isset($_POST['adopted']) == '1' ? '1' : '0');

Just a note to the OP that this code would only work without the hidden active. First, isset returns a boolean true/false, so why compare it to 1? Simply $adopted = isset($_POST['adopted']) does what you are doing but type-correct. Second, As we move to type hinting and more type strictness in what's accepted as "good" PHP, I think it's important to point out the return values should be true : false, or 1 : 0 - not the strings '1' or '0'.

Just IMO but a cleaner way of doing this: (or 1 instead of true)

PHP: $adopted = ($_POST['adopted'] ?? false) == true;

Laravel: $adopted = (request('adopted') ?? false) == true; (replace the request part with $request->post('adopted') or whatever is appropriate for you :)

Well, if you are passing a one or a zero just store it. Why bother validating it's going to be a 1 or a 0. Basically if validating you are saying This has to be a 1 or 0. When it can only be a 1 or a 0 no matter what. Again validating a tinyint is a mute point.

I disagree with this completely. Anyone can submit any value to the form, what if they submit an 11? For data consistency, I would ensure a 0 or 1 gets saved. So, not a moot point :)

rbroberts's avatar

Without the hidden field the issue is that there is nothing set for the checkbox field; it's null.

I did switch at this point to drop the hidden field and use request->has('active'). And I agree with both of you and @jlrdw that approach is cleaner (without the hidden and checking that the value is set). I factored it out into

    public function validatePerson()
    {
        $validatedAttributes = request()->validate([
            'first_name' => 'required',
            'last_name' => 'required',
            'dob' => 'date_format:Y-m-d|nullable',
            'email' => 'email:rfc,dns',
            'bsa_id' => 'integer|min:1|nullable'
        ]);
        $validatedAttributes['active'] = request()->post()->has('active');
        return $validatedAttributes;
    }

Now I'm going to go try the sometimes setting because the table definition does have the default as 0.

rbroberts's avatar

Heh, heh. Nope, sometimes won't cut it. The issue is that the box is either set (user is active) or not (user is not active). Blank means it gets dropped from updates (it's fine for create), so I can never set a user inactive. In the original context of creating a user, it works; but since I refactored it into something workable for both create and update, I need the explicit has().

patrickcm's avatar

Keep in mind that using the proposed default would only work on a new Person - not when you are updating.

If the person is existing and active=1, and you unclicked "active" and save, with that method it would not change active to 0.

Edit: Beat me to it.

1 like
artcore's avatar

A checkbox is either its value or non-existent. That's the validation ;) And you know the value so no need to take it from the request.

$active = $request('active') ? 1 : 0;

mateo-cecchi-davinci's avatar

$request->merge([ 'checkbox' => $request->has('checkbox'), ]);

$request->validate([ 'checkbox' => 'boolean', ]);

Please or to participate in this conversation.