Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Cascade Deletes Laravel Package

shiftonelabs/laravel-cascade-deletes

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require shiftonelabs/laravel-cascade-deletes
    

    Publish the config (optional, but recommended for customization):

    php artisan vendor:publish --provider="ShiftOneLabs\LaravelCascadeDeletes\CascadeDeletesServiceProvider"
    
  2. Basic Usage: Extend your Eloquent model with \ShiftOneLabs\LaravelCascadeDeletes\CascadeDeletes:

    use ShiftOneLabs\LaravelCascadeDeletes\CascadeDeletes;
    
    class ParentModel extends Model
    {
        use CascadeDeletes;
    }
    
  3. Define Cascade Rules: In your model, define which relationships should cascade:

    protected $cascadeDeletes = ['children', 'posts']; // Relationship names
    
  4. First Use Case: Delete a parent record, and all related records (as defined in $cascadeDeletes) will also be deleted:

    $parent = ParentModel::find(1);
    $parent->delete(); // Automatically deletes related records
    

Implementation Patterns

Common Workflows

1. Basic Cascading

  • Define relationships in $cascadeDeletes and let the package handle the rest.
  • Works seamlessly with Laravel’s built-in relationships (hasMany, belongsToMany, etc.).

2. Conditional Cascading

Use a closure to conditionally include/exclude relationships:

protected $cascadeDeletes = [
    'posts' => function ($model) {
        return $model->isActive(); // Only cascade if active
    },
    'comments' => true, // Always cascade
];

3. Soft Deletes Integration

If using SoftDeletes, ensure the package is configured to handle soft deletes:

protected $cascadeSoftDeletes = ['children', 'posts']; // Soft-delete related models

Configure in config/cascade-deletes.php:

'soft_deletes' => true,

4. Polymorphic Relationships

Handle polymorphic relationships by specifying the morphMap or using closures:

protected $cascadeDeletes = [
    'images' => function ($model) {
        return $model->images()->where('type', 'avatar');
    },
];

5. Custom Deletion Logic

Override the performCascadeDeletes method for custom logic:

protected function performCascadeDeletes()
{
    // Custom logic before/after deletion
    $this->logDeletion();
    parent::performCascadeDeletes();
}

6. Bulk Operations

Use delete() on collections or query results:

ParentModel::where('status', 'active')->delete(); // Cascades for all matching records

Integration Tips

Database Transactions

Wrap deletions in transactions to ensure atomicity:

DB::transaction(function () {
    $parent->delete(); // All cascading happens within the transaction
});

Event Listeners

Listen for deleting or deleted events to hook into the cascade process:

public function boot()
{
    static::deleting(function ($model) {
        // Pre-deletion logic
    });

    static::deleted(function ($model) {
        // Post-deletion logic (e.g., cleanup)
    });
}

API Endpoints

Use the package in API controllers to ensure cascading works as expected:

public function destroy(ParentModel $parent)
{
    $parent->delete(); // Cascades automatically
    return response()->noContent();
}

Gotchas and Tips

Pitfalls

1. Infinite Recursion

  • Issue: Circular relationships (e.g., Parent has Children, Child has Parent) can cause infinite loops.
  • Fix: Exclude the reciprocal relationship or use depth limits:
    protected $cascadeDeletes = ['children'];
    protected $cascadeDeletesDepth = 1; // Limit recursion depth
    

2. Soft Deletes vs. Hard Deletes

  • Issue: Mixing soft and hard deletes can lead to unexpected behavior (e.g., soft-deleted parents with hard-deleted children).
  • Fix: Ensure consistency in config/cascade-deletes.php:
    'soft_deletes' => true, // or false
    'force_delete' => false, // Force hard delete even if soft deletes are enabled
    

3. Performance Overhead

  • Issue: Cascading deletes can be slow for large datasets.
  • Fix:
    • Use withoutEvents() to skip event firing during bulk operations.
    • Add indexes to foreign keys for faster queries.
    • Consider batching deletions for very large datasets.

4. Polymorphic Ambiguity

  • Issue: Polymorphic relationships may not cascade as expected if the morphMap is incomplete.
  • Fix: Explicitly define polymorphic relationships in $cascadeDeletes:
    protected $cascadeDeletes = [
        'images' => function ($model) {
            return $model->images()->where('type', 'avatar')->get();
        },
    ];
    

5. Observer Conflicts

  • Issue: Model observers or accessors might interfere with cascade logic.
  • Fix: Ensure observers are not modifying relationships during deletion:
    public function deleting($model)
    {
        // Avoid modifying $model->relationships here
    }
    

Debugging Tips

1. Enable Logging

Add debug logging to config/cascade-deletes.php:

'debug' => env('CASCADE_DELETES_DEBUG', false),

Check Laravel logs for cascade operations.

2. Check Config Values

Verify config/cascade-deletes.php settings:

  • soft_deletes
  • force_delete
  • depth_limit
  • excluded_models

3. Test with dd()

Temporarily add dd() to debug relationships:

protected function performCascadeDeletes()
{
    dd($this->cascadeDeletes); // Inspect relationships
    parent::performCascadeDeletes();
}

4. Database Constraints

  • If using database-level constraints, ensure they don’t conflict with application-level cascading.
  • Disable constraints temporarily if needed (not recommended for production).

Extension Points

1. Custom Cascade Logic

Override performCascadeDeletes or getCascadeDeletes:

protected function getCascadeDeletes()
{
    $deletes = parent::getCascadeDeletes();
    // Add/remove relationships dynamically
    return $deletes;
}

2. Dynamic Relationships

Use closures to dynamically determine cascading:

protected $cascadeDeletes = [
    'dynamic_relation' => function ($model) {
        return $model->isAdmin() ? ['comments', 'reports'] : [];
    },
];

3. Event-Based Extensions

Listen for cascade.deleting and cascade.deleted events:

Event::listen('cascade.deleting', function ($model, $relationship) {
    // Custom logic before cascading
});

4. Custom Storage Engines

Extend the package to support non-Eloquent storage (e.g., MongoDB):

  • Override ShiftOneLabs\LaravelCascadeDeletes\CascadeDeletes traits.
  • Publish and modify the service provider.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
hamzi/corewatch
minionfactory/raw-hydrator
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours
renatovdemoura/blade-elements-ui
devgeek/beacon-admin
benjamin-rqt/data-watcher-bundle
atriumphp/atrium
sandermuller/package-boost-laravel
sandermuller/boost-skills
redaxo/core
yusufgenc/filament-api-forge
l3aro/rating-star-for-filament
leek/filament-subtenant-scope