Passed
Push — master ( 9b30f8...eb1dca )
by Anton
03:21
created

Reactable::scopeWhereNotReactedBy()   A

Complexity

Conditions 2
Paths 1

Size

Total Lines 9
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 4
c 0
b 0
f 0
dl 0
loc 9
rs 10
cc 2
nc 1
nop 3
1
<?php
2
3
/*
4
 * This file is part of Laravel Love.
5
 *
6
 * (c) Anton Komarev <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
declare(strict_types=1);
13
14
namespace Cog\Laravel\Love\Reactable\Models\Traits;
15
16
use Cog\Contracts\Love\Reactable\Exceptions\AlreadyRegisteredAsLoveReactant;
17
use Cog\Contracts\Love\Reactant\Facades\Reactant as ReactantFacadeContract;
18
use Cog\Contracts\Love\Reactant\Models\Reactant as ReactantContract;
19
use Cog\Contracts\Love\Reacterable\Models\Reacterable as ReacterableContract;
20
use Cog\Laravel\Love\Reactable\Observers\ReactableObserver;
21
use Cog\Laravel\Love\Reactant\Facades\Reactant as ReactantFacade;
22
use Cog\Laravel\Love\Reactant\Models\NullReactant;
23
use Cog\Laravel\Love\Reactant\Models\Reactant;
24
use Cog\Laravel\Love\Reactant\ReactionCounter\Models\ReactionCounter;
25
use Cog\Laravel\Love\Reactant\ReactionTotal\Models\ReactionTotal;
26
use Cog\Laravel\Love\ReactionType\Models\ReactionType;
27
use Illuminate\Database\Eloquent\Builder;
28
use Illuminate\Database\Eloquent\Relations\BelongsTo;
29
use Illuminate\Database\Query\JoinClause;
30
use Illuminate\Support\Facades\DB;
31
use Illuminate\Support\Str;
32
33
/**
34
 * @mixin \Cog\Contracts\Love\Reactable\Models\Reactable
35
 */
36
trait Reactable
37
{
38
    protected static function bootReactable(): void
39
    {
40
        static::observe(ReactableObserver::class);
41
    }
42
43
    public function loveReactant(): BelongsTo
44
    {
45
        return $this->belongsTo(Reactant::class, 'love_reactant_id');
0 ignored issues
show
Bug introduced by
It seems like belongsTo() 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

45
        return $this->/** @scrutinizer ignore-call */ belongsTo(Reactant::class, 'love_reactant_id');
Loading history...
46
    }
47
48
    public function getLoveReactant(): ReactantContract
49
    {
50
        return $this->getAttribute('loveReactant') ?? new NullReactant($this);
0 ignored issues
show
Bug introduced by
It seems like getAttribute() 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

50
        return $this->/** @scrutinizer ignore-call */ getAttribute('loveReactant') ?? new NullReactant($this);
Loading history...
Bug introduced by
$this of type Cog\Laravel\Love\Reactable\Models\Traits\Reactable is incompatible with the type Cog\Contracts\Love\Reactable\Models\Reactable expected by parameter $reactable of Cog\Laravel\Love\Reactan...Reactant::__construct(). ( Ignorable by Annotation )

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

50
        return $this->getAttribute('loveReactant') ?? new NullReactant(/** @scrutinizer ignore-type */ $this);
Loading history...
51
    }
52
53
    public function viaLoveReactant(): ReactantFacadeContract
54
    {
55
        return new ReactantFacade($this->getLoveReactant());
56
    }
57
58
    public function isRegisteredAsLoveReactant(): bool
59
    {
60
        return !$this->isNotRegisteredAsLoveReactant();
61
    }
62
63
    public function isNotRegisteredAsLoveReactant(): bool
64
    {
65
        return is_null($this->getAttributeValue('love_reactant_id'));
0 ignored issues
show
Bug introduced by
It seems like getAttributeValue() 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

65
        return is_null($this->/** @scrutinizer ignore-call */ getAttributeValue('love_reactant_id'));
Loading history...
66
    }
67
68
    public function registerAsLoveReactant(): void
69
    {
70
        if ($this->isRegisteredAsLoveReactant()) {
71
            throw new AlreadyRegisteredAsLoveReactant();
72
        }
73
74
        /** @var \Cog\Contracts\Love\Reactant\Models\Reactant $reactant */
75
        $reactant = $this->loveReactant()->create([
76
            'type' => $this->getMorphClass(),
0 ignored issues
show
Bug introduced by
It seems like getMorphClass() 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

76
            'type' => $this->/** @scrutinizer ignore-call */ getMorphClass(),
Loading history...
77
        ]);
78
79
        $this->setAttribute('love_reactant_id', $reactant->getId());
0 ignored issues
show
Bug introduced by
It seems like setAttribute() 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

79
        $this->/** @scrutinizer ignore-call */ 
80
               setAttribute('love_reactant_id', $reactant->getId());
Loading history...
80
        $this->save();
0 ignored issues
show
Bug introduced by
It seems like save() 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

80
        $this->/** @scrutinizer ignore-call */ 
81
               save();
Loading history...
81
    }
82
83
    public function scopeWhereReactedBy(
84
        Builder $query,
85
        ReacterableContract $reacterable,
86
        ?string $reactionTypeName = null
87
    ): Builder {
88
        return $query->whereHas('loveReactant.reactions', function (Builder $reactionsQuery) use ($reacterable, $reactionTypeName) {
89
            $reactionsQuery->where('reacter_id', $reacterable->getLoveReacter()->getId());
90
            if (!is_null($reactionTypeName)) {
91
                $reactionsQuery->where('reaction_type_id', ReactionType::fromName($reactionTypeName)->getId());
92
            }
93
        });
94
    }
95
96
    public function scopeWhereNotReactedBy(
97
        Builder $query,
98
        ReacterableContract $reacterable,
99
        ?string $reactionTypeName = null
100
    ): Builder {
101
        return $query->whereDoesntHave('loveReactant.reactions', function (Builder $reactionsQuery) use ($reacterable, $reactionTypeName) {
102
            $reactionsQuery->where('reacter_id', $reacterable->getLoveReacter()->getId());
103
            if (!is_null($reactionTypeName)) {
104
                $reactionsQuery->where('reaction_type_id', ReactionType::fromName($reactionTypeName)->getId());
105
            }
106
        });
107
    }
108
109
    public function scopeJoinReactionCounterOfType(
110
        Builder $query,
111
        string $reactionTypeName,
112
        ?string $alias = null
113
    ): Builder {
114
        $reactionType = ReactionType::fromName($reactionTypeName);
115
        $alias = is_null($alias) ? 'reaction_' . Str::snake($reactionType->getName()) : $alias;
116
117
        $select = $query->getQuery()->columns ?? ["{$this->getTable()}.*"];
0 ignored issues
show
Bug introduced by
It seems like getTable() 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

117
        $select = $query->getQuery()->columns ?? ["{$this->/** @scrutinizer ignore-call */ getTable()}.*"];
Loading history...
118
        $select[] = DB::raw("COALESCE({$alias}.count, 0) as {$alias}_count");
119
        $select[] = DB::raw("COALESCE({$alias}.weight, 0) as {$alias}_weight");
120
121
        return $query
0 ignored issues
show
Bug Best Practice introduced by
The expression return $query->leftJoin(... */ })->select($select) could return the type Illuminate\Database\Query\Builder which is incompatible with the type-hinted return Illuminate\Database\Eloquent\Builder. Consider adding an additional type-check to rule them out.
Loading history...
122
            ->leftJoin((new ReactionCounter())->getTable() . ' as '. $alias, function (JoinClause $join) use ($reactionType, $alias) {
123
                $join->on("{$alias}.reactant_id", '=', "{$this->getTable()}.love_reactant_id");
124
                $join->where("{$alias}.reaction_type_id", $reactionType->getId());
125
            })
126
            ->select($select);
127
    }
128
129
    public function scopeJoinReactionTotal(
130
        Builder $query,
131
        ?string $alias = null
132
    ): Builder {
133
        $alias = is_null($alias) ? 'reaction_total' : $alias;
134
        $select = $query->getQuery()->columns ?? ["{$this->getTable()}.*"];
135
        $select[] = DB::raw("COALESCE({$alias}.count, 0) as {$alias}_count");
136
        $select[] = DB::raw("COALESCE({$alias}.weight, 0) as {$alias}_weight");
137
138
        return $query
0 ignored issues
show
Bug Best Practice introduced by
The expression return $query->leftJoin(...t_id')->select($select) could return the type Illuminate\Database\Query\Builder which is incompatible with the type-hinted return Illuminate\Database\Eloquent\Builder. Consider adding an additional type-check to rule them out.
Loading history...
139
            ->leftJoin((new ReactionTotal())->getTable() . ' as ' . $alias, "{$alias}.reactant_id", '=', "{$this->getTable()}.love_reactant_id")
140
            ->select($select);
141
    }
142
}
143