I recently ran into an issue where Laravel wasn't running an accessor when serializing my Eloquent model to JSON. I had one property called is_drop_off_location
and another called is_24_hour_drop_off_location
. These values were stored in an SQLite database that doesn't support booleans, and when serializing the model to JSON it would return "0"
or "1"
as a string.
I added the following accessors to my model to convert these strings to proper booleans:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Location extends Model
{
public function getIsDropOffLocationAttribute($value)
{
return $value == "1" ? true : false;
}
public function getIs24HourDropOffLocationAttribute($value)
{
return $value == "1" ? true : false;
}
}
However, when I serialized to JSON, I'd get the following:
{
"is_drop_off_location": true,
"is_24_hour_drop_off_location": "0"
}
As I looked around, I wasn't the only person having problems with numbers and serialization.
As far as I can tell, this bug occurs because Laravel is trying to convert the StudlyCase
attribute name to snake_case
, and the conversion function has no way of knowing that there's an underscore before the number.
The good news is this is a solvable problem. Laravel allows you to explicitly append values to JSON with the protected $appends
property on the Eloquent model. This feature exists for adding dynamic attributes that don't correspond to database columns, but we can use it to ensure that Laravel serializes our accessor for an attribute with a number in it.
Here is what our model looks like afterwards:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Location extends Model
{
// This will make Laravel serialize our accessor.
protected $appends = ['is_24_hour_drop_off_location'];
public function getIsDropOffLocationAttribute($value)
{
return $value == "1" ? true : false;
}
public function getIs24HourDropOffLocationAttribute($value)
{
return $value == "1" ? true : false;
}
}
Now when I serialize this to JSON, Laravel knows to look at the accessor.
Here is the JSON serialized output from the code above:
{
"is_drop_off_location": true,
"is_24_hour_drop_off_location": false
}
Happy coding.
Top comments (0)