Preventing Child Record Display When Parent is Soft Deleted Using Laravel Scopes

Yash Kumar Prasad
3 min readOct 7, 2024

--

Introduction

When soft deletions are involved, managing parent-child relationships in Laravel applications can be difficult. By default, Child records are visible even if the parent has been deleted. This can cause inconsistencies in your app’s data presentation. In this post, we’ll explain how to use Laravel’s query scope to prevent child records from appearing when the parent is soft-deleted.

Understanding Soft Deletes in Laravel

Laravel’s soft delete feature allows you to “delete” records without leaving the database. Instead, it marks the record with the delete_at timestamp, placing it into the database. but separated from the query results.

To enable soft deletes, simply add the SoftDeletes trait to your model:

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class ParentModel extends Model
{
use SoftDeletes;
}

Using this feature, Laravel will automatically exclude soft deleted records from the query results. Unless you explicitly request it via the withTrashed or onlyTrashed… method.

The Problem: Child Records Still Show

Even if soft erase is enabled. Problems also arise when querying child records that have a relationship with a soft-deleted parent. By default, Laravel still shows child records. Even if the parent is gently deleted. This can cause confusion. This is because it does not accurately reflect the relationship in your API views or responses.

For example:

$parent = ParentModel::with('children')->get();

This query returns all child items. Even for soft deleted parent records, this may not be the desired behavior in your application.

Solution: Using Eloquent Scopes to Filter Child Records

To solve this problem We can leverage Laravel’s global query scope. Scopes allow you to define general query constraints for your model. In this case, we will define a global scope on the child model to filter any records. where the parent is soft deleted

Step-by-Step Implementation

  1. Create the Parent and Child Models

Let’s assume we have a ParentModel and a ChildModel where a parent has many children:

class ParentModel extends Model
{
use SoftDeletes;
public function children()
{
return $this->hasMany(ChildModel::class);
}
}
class ChildModel extends Model
{
public function parent()
{
return $this->belongsTo(ParentModel::class);
}
}

2. Define a Global Scope on the Child Model

Next, we need to create a global scope that ensures child records are only returned if their parent is not soft deleted. You can do this by adding a custom scope to the ChildModel.

use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class ChildModel extends Model
{
// Optional SoftDeletes trait for ChildModel
use SoftDeletes;
protected static function booted()
{
static::addGlobalScope('parentNotDeleted', function (Builder $builder) {
$builder->whereHas('parent', function ($query) {
$query->whereNull('deleted_at'); // Ensure parent is not soft deleted
});
});
}
public function parent()
{
return $this->belongsTo(ParentModel::class);
}
}

In this code, the global scope parentNotDeleted ensures that only child records whose parents are not soft deleted will be returned in queries.

3. Testing the Scope

Now, when you query the child model, it will automatically filter out children whose parent has been soft deleted:

$children = ChildModel::all();

You no longer need to worry about manually applying constraints to each query — the global scope takes care of it.

4. Optional: Handling Soft Deleted Children

If your application also uses soft deletes for child records, you can modify the global scope to handle cases where both the parent and child might be soft deleted:

use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class ChildModel extends Model
{
use SoftDeletes;
protected static function booted()
{
static::addGlobalScope('parentNotDeleted', function (Builder $builder) {
$builder->whereHas('parent', function ($query) {
$query->whereNull('deleted_at'); // Parent not soft deleted
});
});
}
public function parent()
{
return $this->belongsTo(ParentModel::class)->withTrashed(); // Include soft-deleted parents if needed
}
}

This configuration ensures that if both the parent and child are soft deleted, you can still manage their visibility flexibly based on your application’s needs.

Conclusion

Using Laravel’s global scope, you can effectively control the visibility of child records relative to the parent record. This technique ensures that your information is presented evenly. Therefore, none of the soft-deleted parent records can show the corresponding child records. Therefore, it maintains the logic of your application intact and a smooth user experience.… With this approach You can make your visualizations clean and easy to use. And take full advantage of Laravel’s strong features like soft delete and query scoping…

This blog post provides a thorough guide on the topic, explaining the problem, solution, and key steps for implementation. Let me know if you need any modifications!

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

--

--

Yash Kumar Prasad
Yash Kumar Prasad

Written by Yash Kumar Prasad

Full-stack developer with a passion for crafting robust web solutions. Experienced in creating scalable applications that prioritize user experience.

No responses yet

Write a response