bigboss's avatar

issue with boolean field when migrating with mysql

I'm having a issue with boolean fields with mysql, I've a migration set like this

        Schema::create('clients', function (Blueprint $table) {
            $table->increments('id');
            $table->string('name');
            $table->string('phone');
            $table->boolean('has_whatsapp')->default(0);
            $table->timestamps();
        });

Since mysql uses tinyint as field type I tried using $table->tinyInteger() without success.

My ClientsController has a method to store, my model has the guarded fields set and it woks with all requests except from this one that come from a checkbox.

The store method looks like this

        Client::create([
            'name' => request('name'),
            'phone' => request('phone'),
            'has_whatsapp' => request('has_whatsapp')
        ]);

and my checkbox in the form looks like this

<div class="control">
    <label class="checkbox" for="has_whatsapp">
        <input type="checkbox" name="has_whatsapp" id="has_whatsapp"> Whatsapp?
    </label>
</div>

I receive this message when I try to store the data with the checkbox checked "SQLSTATE[HY000]: General error: 1366 Incorrect integer value: 'on' for column 'has_whatsapp' at row 1 (SQL: insert into 'clients' ('has_whatsapp', 'name', 'phone'..., and I leave it unchecked it try to store the field as null even with the default value set as 0.

If I use sqlite as db everthing works fine, but I need it working with mysql. What I'm doing wrong? Or the mysql just don't handle booleans well?

0 likes
7 replies
ksungcaya's avatar
Level 8

boolean will be converted to tiny int so using it is fine.

Try putting a value attribute on your checkbox like 1 or true. And if you want to make sure, before saving it, cast the value to boolean..

Client::create([
    'name' => request('name'),
    'phone' => request('phone'),
    'has_whatsapp' => (bool) request('has_whatsapp')
]);
3 likes
andreich1980's avatar

try this

'has_whatsapp' => !! request('has_whatsapp')
1 like
bigboss's avatar

@ksungcaya Casting the value as boolean did the trick to save it. Thanks! I was missing the value attribute in the checkbox, but it didn't worked out when the checkbox was uncheck since the request was trying to store null even with the default value been set to 0. Do you know why?

@andreich1980 This works as well! Thanks!

ksungcaya's avatar

@bigboss I think because you're boolean field is not nullable hence the error when you're trying to put null value on it.

btw I have to correct my answer although putting a value in the checkbox will do the trick, you can simplify your creation if you use has method rather than casting it to boolean like this.

Client::create([
    'name' => request('name'),
    'phone' => request('phone'),
    'has_whatsapp' => request()->has('has_whatsapp')
]);
bigboss's avatar

@ksungcaya I think I miss understood the default behavior in the migration, to me the default value would override the null value that was passed by the request.

Ive tried using both the has method and casting (bool) without the default(0) at migration and it works, and I've tried set the field to nullable() but it doenst work without using one of your solutions, so I think there is something wrong with the mysql migration since it works as intended when I use sqlite.

ksungcaya's avatar

@bigboss

tried just now. I have a migration like this

public function up()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->boolean('is_logged_in')->nullable()->default(0);
        });
    }

and I've quickly run this in tinker

factory(App\User::class)->create(['is_logged_in' => null]);

it creates a user record with NULL value on is_logged_in field and not **0**. Not sure about the difference of their behavior but on my understanding, as long as a field is not nullable you wont be able to insert a null value on it. And in database perspective null value is different from an int or string value.

luchmewep's avatar

Hello! I hope you can read this before doing anything funny. I have the same problem and I thought parsing with (bool) fixed it but later I found out that it does not because as long as it is any string, it will return as true. Not long after, I tried reading another solution here which was to use something like this: $request->has('completed'). It was actually wrong again because it will always return 'true' if there exists 'completed' variable on the request. So regardless of the value of the variable 'completed', may it be true or false, it will always return 'true'.

So how to fix this? I found the answer at StackOverflow when I tried searching how to parse a string to boolean. What I found was a GEM really. It solved the problem and extended the idea! What if I typed 1, yes, true and on? It should be equivalent to TRUE , right? So this is the SOLUTION:

Client::create([ 'name' => request('name'), 'phone' => request('phone'), 'has_whatsapp' => filter_var(request('has_whatsapp')->completed, FILTER_VALIDATE_BOOLEAN) ]);

Read more here: https://stackoverflow.com/questions/4775294/parsing-a-string-into-a-boolean-value-in-php

YOU ARE ALL WELCOME! <3

Please or to participate in this conversation.