Issues (8)

src/Traits/CascadedSoftDeletes.php (6 issues)

1
<?php
2
3
namespace RaziAlsayyed\LaravelCascadedSoftDeletes\Traits;
4
5
use Illuminate\Support\Str;
6
use RaziAlsayyed\LaravelCascadedSoftDeletes\Exceptions\LogicException;
7
use RaziAlsayyed\LaravelCascadedSoftDeletes\Exceptions\RuntimeException;
8
use RaziAlsayyed\LaravelCascadedSoftDeletes\Jobs\CascadeSoftDeletes;
9
10
trait CascadedSoftDeletes
11
{
12
    /**
13
     * Keeps track of Instance deleted_at time.
14
     *
15
     * @var \Carbon\Carbon
16
     */
17
    public static $instanceDeletedAt;
18
19
    /**
20
     * Sign on model events.
21
     */
22
    protected static function bootCascadedSoftDeletes()
23
    {
24
        static::deleted(function ($model) {
25
            $model->deleteCascadedSoftDeletes();
26
        });
27
28
        if (static::instanceUsesSoftDelete()) {
29
            static::restoring(function ($model) {
30
                static::$instanceDeletedAt = $model->{$model->getDeletedAtColumn()};
31
            });
32
33
            static::restored(function ($model) {
34
                $model->restoreCascadedSoftDeleted();
35
            });
36
        }
37
    }
38
39
    /**
40
     * Delete the cascaded relations.
41
     */
42
    protected function deleteCascadedSoftDeletes() : void
43
    {
44
        if ($this->isHardDeleting()) {
45
            return;
46
        }
47
48
        if (config('cascaded-soft-deletes.queue_cascades_by_default') === true) {
49
            CascadeSoftDeletes::dispatch($this, 'delete', null)->onQueue(config('cascaded-soft-deletes.queue_name'));
50
        } else {
51
            // @codeCoverageIgnoreStart
52
            Str::startsWith(app()->version(), '7') ?
0 ignored issues
show
The method version() does not exist on Illuminate\Container\Container. Are you sure you never get this type here, but always one of the subclasses? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

52
            Str::startsWith(app()->/** @scrutinizer ignore-call */ version(), '7') ?
Loading history...
53
                CascadeSoftDeletes::dispatchNow($this, 'delete', null) :
0 ignored issues
show
Deprecated Code introduced by
The function RaziAlsayyed\LaravelCasc...tDeletes::dispatchNow() has been deprecated: Will be removed in a future Laravel version. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

53
                /** @scrutinizer ignore-deprecated */ CascadeSoftDeletes::dispatchNow($this, 'delete', null) :

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
54
                CascadeSoftDeletes::dispatchSync($this, 'delete', null);
55
            // @codeCoverageIgnoreEnd
56
        }
57
    }
58
59
    /**
60
     * Restore the cascaded relations.
61
     */
62
    protected function restoreCascadedSoftDeleted() : void
63
    {
64
        if (config('cascaded-soft-deletes.queue_cascades_by_default') === true) {
65
            CascadeSoftDeletes::dispatch($this, 'restore', static::$instanceDeletedAt)->onQueue(config('cascaded-soft-deletes.queue_name'));
66
        } else {
67
            // @codeCoverageIgnoreStart
68
            Str::startsWith(app()->version(), '7') ?
69
                CascadeSoftDeletes::dispatchNow($this, 'restore', static::$instanceDeletedAt) :
0 ignored issues
show
Deprecated Code introduced by
The function RaziAlsayyed\LaravelCasc...tDeletes::dispatchNow() has been deprecated: Will be removed in a future Laravel version. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

69
                /** @scrutinizer ignore-deprecated */ CascadeSoftDeletes::dispatchNow($this, 'restore', static::$instanceDeletedAt) :

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
70
                CascadeSoftDeletes::dispatchSync($this, 'restore', static::$instanceDeletedAt);
71
            // @codeCoverageIgnoreEnd
72
        }
73
        // CascadeSoftDeletes::dispatch($this, 'restore', static::$instanceDeletedAt);
74
    }
75
76
    /**
77
     * Delete/Restore Cascaded Relationships.
78
     *
79
     * @param $action
80
     */
81
    public function cascadeSoftDeletes(string $action, ?\Carbon\Carbon $instanceDeletedAt = null) : void
82
    {
83
        if (method_exists($this, 'getCascadedSoftDeletes')) {
84
            $relations = collect($this->getCascadedSoftDeletes());
85
        } elseif (property_exists($this, 'cascadedSoftDeletes')) {
86
            $relations = collect($this->cascadedSoftDeletes);
87
        } else {
88
            throw new RuntimeException('neither getCascadedSoftDeletes function or cascaded_soft_deletes property exists!');
89
        }
90
91
        $relations->each(function ($item, $key) use ($action, $instanceDeletedAt) {
92
            $relation = $key;
93
            if (is_numeric($key)) {
94
                $relation = $item;
95
            }
96
97
            if (!is_callable($item) && !$this->relationUsesSoftDelete($relation)) {
98
                throw new LogicException('relationship ' . $relation . ' does not use SoftDeletes trait.');
99
            }
100
101
            if (is_callable($item)) {
102
                $query = $item();
103
            } else {
104
                $query = $this->{$relation}();
105
            }
106
107
            if ($action == 'delete') {
108
                $query->get()->each->delete();
109
            } else {
110
                $query
111
                    ->onlyTrashed()
112
                    ->where($this->getDeletedAtColumn(), '>=', $instanceDeletedAt->format('Y-m-d H:i:s.u'))
0 ignored issues
show
The method format() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

112
                    ->where($this->getDeletedAtColumn(), '>=', $instanceDeletedAt->/** @scrutinizer ignore-call */ format('Y-m-d H:i:s.u'))

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
It seems like getDeletedAtColumn() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

112
                    ->where($this->/** @scrutinizer ignore-call */ getDeletedAtColumn(), '>=', $instanceDeletedAt->format('Y-m-d H:i:s.u'))
Loading history...
113
                    ->get()
114
                    ->each
115
                    ->restore();
116
            }
117
118
            // else {
119
            //     $query = $query
120
            //         ->withTrashed()
121
            //         ->where($query->qualifyColumn($this->getDeletedAtColumn()), '>=', $instanceDeletedAt);
122
123
            //     dd($query->toSql(), $query->getBindings(), $query->pluck('deleted_at'));
124
125
            // }
126
        });
127
    }
128
129
    /**
130
     * Get whether user is intended to delete the model from database entirely.
131
     *
132
     * @return bool
133
     */
134
    protected function isHardDeleting() : bool
135
    {
136
        return !$this->instanceUsesSoftDelete() || $this->forceDeleting;
137
    }
138
139
    /**
140
     * Check if the instance uses SoftDeletes trait.
141
     *
142
     * @return bool
143
     */
144
    protected static function instanceUsesSoftDelete() : bool
145
    {
146
        static $softDelete;
147
148
        if (is_null($softDelete)) {
149
            $instance = new static;
150
151
            return $softDelete = method_exists($instance, 'bootSoftDeletes');
152
        }
153
154
        return $softDelete;
155
    }
156
157
    /**
158
     * Check if the relation uses SoftDeletes trait.
159
     *
160
     * @return bool
161
     */
162
    public static function relationUsesSoftDelete($relation) : bool
163
    {
164
        static $softDeletes;
165
166
        if (is_null($softDeletes)) {
167
            $softDeletes = collect([]);
0 ignored issues
show
array() of type array is incompatible with the type Illuminate\Contracts\Support\Arrayable expected by parameter $value of collect(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

167
            $softDeletes = collect(/** @scrutinizer ignore-type */ []);
Loading history...
168
        }
169
170
        return $softDeletes->get($relation, function () use ($relation, $softDeletes) {
171
            $instance = new static;
172
            $cls = $instance->{$relation}()->getRelated();
173
            $relationInstance = new $cls;
174
175
            return $softDeletes->put($relation, method_exists($relationInstance, 'bootSoftDeletes'))->get($relation);
176
        });
177
    }
178
}
179