CanBeSuspended::getSuspensionModelType()   A
last analyzed

Complexity

Conditions 2
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 1
c 1
b 0
f 0
dl 0
loc 3
rs 10
cc 2
nc 1
nop 0
1
<?php
2
3
namespace Digikraaft\ModelSuspension;
4
5
use Carbon\Carbon;
6
use Digikraaft\ModelSuspension\Events\ModelSuspensionChanged;
7
use Digikraaft\ModelSuspension\Exceptions\InvalidDate;
8
use Illuminate\Database\Eloquent\Builder;
9
use Illuminate\Database\Eloquent\Relations\MorphMany;
10
use Illuminate\Database\Eloquent\Relations\Relation;
11
use Illuminate\Database\Query\Builder as QueryBuilder;
12
use Illuminate\Support\Facades\DB;
13
14
trait CanBeSuspended
15
{
16
    public function suspensions(): MorphMany
17
    {
18
        return $this->morphMany($this->getSuspensionModelClassName(), 'model', 'model_type', $this->getModelKeyColumnName())
0 ignored issues
show
Bug introduced by
It seems like morphMany() 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

18
        return $this->/** @scrutinizer ignore-call */ morphMany($this->getSuspensionModelClassName(), 'model', 'model_type', $this->getModelKeyColumnName())
Loading history...
19
            ->latest('id');
20
    }
21
22
    public function suspension()
23
    {
24
        return $this->latestSuspension();
25
    }
26
27
    private function latestSuspension()
28
    {
29
        return $this->suspensions()->first();
30
    }
31
32
    public function suspend(?int $days = 0, ?string $reason = null): self
33
    {
34
        $suspended_until = null;
35
36
        if ($days > 0) {
37
            $suspended_until = now()->addDays($days);
38
        }
39
40
        return $this->createSuspension($suspended_until, $reason);
41
    }
42
43
    public function isSuspended(): bool
44
    {
45
        if ($this->suspension()->is_suspended === null && $this->suspension()->suspended_until === null) {
46
            return false;
47
        }
48
49
        if (Carbon::parse($this->suspension()->suspended_until)->lessThan(now()->toDateString())) {
50
            return false;
51
        }
52
53
        if ($this->suspension()->is_suspended != true) {
54
            return false;
55
        }
56
57
        return true;
58
    }
59
60
    public function unsuspend(): self
61
    {
62
        return $this->deleteSuspension();
63
    }
64
65
    /**
66
     *
67
     * @return bool
68
     */
69
    public function hasEverBeenSuspended(): bool
70
    {
71
        $suspensions = $this->relationLoaded('suspensions') ? $this->suspensions : $this->suspensions();
0 ignored issues
show
Bug introduced by
It seems like relationLoaded() 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

71
        $suspensions = $this->/** @scrutinizer ignore-call */ relationLoaded('suspensions') ? $this->suspensions : $this->suspensions();
Loading history...
72
73
        return $suspensions->count() > 0;
74
    }
75
76
    public function createSuspension($suspended_until = null, ?string $reason = null)
77
    {
78
        $this->suspensions()->create([
79
            'is_suspended' => true,
80
            'suspended_until' => $suspended_until,
81
            'reason' => $reason,
82
        ]);
83
84
        event(new ModelSuspensionChanged($this, $this->suspension()));
0 ignored issues
show
Bug introduced by
$this of type Digikraaft\ModelSuspension\CanBeSuspended is incompatible with the type Illuminate\Database\Eloquent\Model expected by parameter $model of Digikraaft\ModelSuspensi...nChanged::__construct(). ( Ignorable by Annotation )

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

84
        event(new ModelSuspensionChanged(/** @scrutinizer ignore-type */ $this, $this->suspension()));
Loading history...
85
86
        return $this;
87
    }
88
89
    private function deleteSuspension(): self
90
    {
91
        $this->suspension()->update([
92
            'is_suspended' => false,
93
            'deleted_at' => now(),
94
        ]);
95
96
        event(new ModelSuspensionChanged($this, $this->suspension()));
0 ignored issues
show
Bug introduced by
$this of type Digikraaft\ModelSuspension\CanBeSuspended is incompatible with the type Illuminate\Database\Eloquent\Model expected by parameter $model of Digikraaft\ModelSuspensi...nChanged::__construct(). ( Ignorable by Annotation )

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

96
        event(new ModelSuspensionChanged(/** @scrutinizer ignore-type */ $this, $this->suspension()));
Loading history...
97
98
        return $this;
99
    }
100
101
    public function numberOfTimesSuspended(?Carbon $from = null, ?Carbon $to = null): int
102
    {
103
        if ($from && $to) {
104
            if ($from->greaterThan($to)) {
105
                throw InvalidDate::from();
106
            }
107
108
            return $this->suspensions()
109
                    ->whereBetween(
110
                        'created_at',
111
                        [$from->toDateTimeString(), $to->toDateTimeString()]
112
                    )->count();
113
        }
114
115
        return $this->suspensions()->count();
116
    }
117
118
    protected function getSuspensionTableName(): string
119
    {
120
        $modelClass = $this->getSuspensionModelClassName();
121
122
        return (new $modelClass)->getTable();
123
    }
124
125
    protected function getModelKeyColumnName(): string
126
    {
127
        return config('model-suspension.model_primary_key_attribute') ?? 'model_id';
128
    }
129
130
    protected function getSuspensionModelClassName(): string
131
    {
132
        return config('model-suspension.suspension_model');
133
    }
134
135
    protected function getSuspensionModelType(): string
136
    {
137
        return array_search(static::class, Relation::morphMap()) ?: static::class;
138
    }
139
140
    public function scopeActiveSuspensions(Builder $builder)
141
    {
142
        $builder
143
            ->whereHas(
144
                'suspensions',
145
                function (Builder $query) {
146
                    $query
147
                        ->whereIn(
148
                            'id',
149
                            function (QueryBuilder $query) {
150
                                $query
151
                                    ->select(DB::raw('max(id)'))
152
                                    ->from($this->getSuspensionTableName())
153
                                    ->where('model_type', $this->getSuspensionModelType())
154
                                    ->whereColumn($this->getModelKeyColumnName(), $this->getQualifiedKeyName());
0 ignored issues
show
Bug introduced by
It seems like getQualifiedKeyName() 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

154
                                    ->whereColumn($this->getModelKeyColumnName(), $this->/** @scrutinizer ignore-call */ getQualifiedKeyName());
Loading history...
155
                            }
156
                        );
157
                }
158
            );
159
    }
160
161
    public function scopeSuspensions(Builder $builder)
162
    {
163
        $builder
164
            ->whereHas(
165
                'suspensions',
166
                function (Builder $query) {
167
                    $query
168
                        ->whereIn(
169
                            'id',
170
                            function (QueryBuilder $query) {
171
                                $query
172
                                    ->select(DB::raw('max(id)'))
173
                                    ->from($this->getSuspensionTableName())
174
                                    ->where('model_type', $this->getSuspensionModelType())
175
                                    ->whereColumn($this->getModelKeyColumnName(), $this->getQualifiedKeyName());
176
                            }
177
                        );
178
                }
179
            );
180
    }
181
}
182