I have a model with a JSON column which gets cast to a Collection by Eloquent.
To keep application logic simple, I don't want to allow null values in this column. Instead, I want to ensure that the column defaults to an empty array when no value is provided.
This is easy with the following bit of migration code:
$table->json('example_field')->default(new Expression('(JSON_ARRAY())'));
One slight issue with this approach shows up while writing tests.
If I use a factory to create an instance of this model, that field will not yet be set to the default in my new instance:
$model = Model::factory()->create();
$model->example_field; // null
This is because the default value is applied at the database level, and the model was created in-memory, persisted to the database, but not read back from the database.
One solution would be to add this field to my factory definition with an empty array, but that would have meant duplicating the default value in two places, which I don't like.
Instead, I solved this issue by calling $model->refresh()
to read the model back from the database right after the factory call as part of my test data setup.
Yes, this introduces an extra database query, but the marginal performance hit in some tests is worth it to me to keep my code clean.
And because this is not a normal thing to do, I added a comment to my test code to explain why this is necessary.
Here to help,
Joel
P.S. The next time you're struggling with a problem, don't forget that the community and Get Unstuck sessions are here to help you out.