I've discussed how we catch lazy loading issues in our code during testing, but this approach doesn't help us if a lazy loading issue slips through to production.
Here's an idea: what if we still watch for lazy loading in production, but instead of throwing an exception, we log the error so we can investigate later? This is the best of both worlds: we don't interrupt the user experience, but we still know the issue exists and can fix it.
The new implementation would look like this in our AppServiceProvider
:
public function boot(): void
{
Model::preventLazyLoading();
Model::handleLazyLoadingViolationUsing(function ($model, $relation) {
$exception = new LazyLoadingViolationException($model, $relation);
if ($this->app->isProduction()) {
report($exception);
} else {
throw $exception;
}
});
}
Notice how we no longer have the environment check inside preventLazyLoading()
.
We are now watching for lazy loading in all environments, but the next method we added lets us handle the violation differently based on whether we're in production or not.
In production, we simply log the exception using Laravel's report()
function, which sends it to the configured logging channels, like the daily log file or a service like Sentry.
And if we aren't in production, we throw the exception as before, so we can catch it during testing or development.
You could use this same approach with the other model strictness checks too:
handleDiscardedAttributeViolationUsing()
handleMissingAttributeViolationUsing()
.
One final bit of advice: If you do catch something in production, before fixing the lazy loading error, first add a test that would have caught it in the first place. This way, you ensure that the issue won't pop up again in the future.
Here to help,
Joel
P.S. When you read my final bit of advice, did you think "Wow, I really wish we had tests in place to catch bugs like this"? We can help you get a rock-solid test suite in your app!