Askedio / laravel-soft-cascade

Cascade Delete & Restore when using Laravel SoftDeletes
https://medium.com/asked-io/cascading-softdeletes-with-laravel-5-a1a9335a5b4d
MIT License
705 stars 63 forks source link

Error when deleting model #54

Closed rbruhn closed 6 years ago

rbruhn commented 6 years ago

I get the following error when trying to delete a record. The model in question does not use SoftCascade. However, there two other models higher in the hierarchy that do. For example, I have Project => Expedition => Subject relationships where if a Project or Expedition is deleted, soft cascade handles deleting all the subjects. The subjects are in MongoDB and use jenssegers/laravel-mongodb package.

I've not had an issue with this until recently. Has something changed?

[2018-02-04 00:27:15] local.ERROR: Call to a member function beginTransaction() on null {"exception":"[object] (Symfony\\Component\\Debug\\Exception\\FatalThrowableError(code: 0): Call to a member function beginTransaction() on null at /home/vagrant/sites/biospex/production/vendor/laravel/framework/src/Illuminate/Database/Concerns/ManagesTransactions.php:108)
[stacktrace]
#0 /home/vagrant/sites/biospex/production/vendor/laravel/framework/src/Illuminate/Database/Concerns/ManagesTransactions.php(92): Illuminate\\Database\\Connection->createTransaction()
#1 /home/vagrant/sites/biospex/production/vendor/askedio/laravel5-soft-cascade/src/SoftCascade.php(65): Illuminate\\Database\\Connection->beginTransaction()
#2 /home/vagrant/sites/biospex/production/vendor/askedio/laravel5-soft-cascade/src/SoftCascade.php(35): Askedio\\SoftCascade\\SoftCascade->run(Object(Illuminate\\Support\\Collection))
#3 /home/vagrant/sites/biospex/production/vendor/askedio/laravel5-soft-cascade/src/Listeners/CascadeDeleteListener.php(20): Askedio\\SoftCascade\\SoftCascade->cascade(Array, 'delete')
#4 [internal function]: Askedio\\SoftCascade\\Listeners\\CascadeDeleteListener->handle('eloquent.deleti...', Array)
#5 /home/vagrant/sites/biospex/production/vendor/laravel/framework/src/Illuminate/Events/Dispatcher.php(365): call_user_func(Array, 'eloquent.deleti...', Array)
#6 /home/vagrant/sites/biospex/production/vendor/laravel/framework/src/Illuminate/Events/Dispatcher.php(200): Illuminate\\Events\\Dispatcher->Illuminate\\Events\\{closure}('eloquent.deleti...', Array)
#7 /home/vagrant/sites/biospex/production/vendor/laravel/framework/src/Illuminate/Events/Dispatcher.php(160): Illuminate\\Events\\Dispatcher->dispatch('eloquent.deleti...', Array, true)
#8 /home/vagrant/sites/biospex/production/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Concerns/HasEvents.php(148): Illuminate\\Events\\Dispatcher->until('eloquent.deleti...', Object(App\\Models\\Subject))
#9 /home/vagrant/sites/biospex/production/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php(776): Illuminate\\Database\\Eloquent\\Model->fireModelEvent('deleting')
#10 /home/vagrant/sites/biospex/production/app/Console/Commands/TestAppCommand.php(46): Illuminate\\Database\\Eloquent\\Model->delete()
#11 [internal function]: App\\Console\\Commands\\TestAppCommand->handle()
rbruhn commented 6 years ago

I looked at where the error is occurring:

SoftCascade.php

protected function run($models)
{
    $models = collect($models);
    if ($models->count() > 0) {
        $model = $models->first();

        if (!in_array($model->getConnectionName(), $this->connectionsToTransact)) {
            $this->connectionsToTransact[] = $model->getConnectionName();
            DB::connection($model->getConnectionName())->beginTransaction();
        }

        if (!is_object($model)) {
            return;
        }

        if (!$this->isCascadable($model)) {
            return;
        }

        $this->relations($model, $models->pluck($model->getKeyName()));
    }
}

Basically, MongoDB doesn't have transactions. A simple work around would be to change the checks so they occur before creating the transaction

protected function run($models)
{
    $models = collect($models);
    if ($models->count() > 0) {
        $model = $models->first();

        if (!is_object($model)) {
            return;
        }

        if (!$this->isCascadable($model)) {
            return;
        }

        if (!in_array($model->getConnectionName(), $this->connectionsToTransact)) {
            $this->connectionsToTransact[] = $model->getConnectionName();
            DB::connection($model->getConnectionName())->beginTransaction();
        }

        $this->relations($model, $models->pluck($model->getKeyName()));
    }
}
maguilar92 commented 6 years ago

Merged in 5.5.13