Passed
Pull Request — master (#102)
by Anton
03:08
created

Reactable   A

Complexity

Total Complexity 16

Size/Duplication

Total Lines 105
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 16
eloc 38
c 1
b 0
f 0
dl 0
loc 105
rs 10

11 Methods

Rating   Name   Duplication   Size   Complexity  
A viaLoveReactant() 0 3 1
A registerAsLoveReactant() 0 13 2
A isRegisteredAsLoveReactant() 0 3 1
A getLoveReactant() 0 3 1
A loveReactant() 0 3 1
A isNotRegisteredAsLoveReactant() 0 3 1
A bootReactable() 0 3 1
A scopeWhereReactedBy() 0 9 2
A scopeJoinReactionTotal() 0 12 2
A scopeWhereNotReactedBy() 0 9 2
A scopeJoinReactionCounterOfType() 0 18 2
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
32
/**
33
 * @mixin \Cog\Contracts\Love\Reactable\Models\Reactable
34
 */
35
trait Reactable
36
{
37
    protected static function bootReactable(): void
38
    {
39
        static::observe(ReactableObserver::class);
40
    }
41
42
    public function loveReactant(): BelongsTo
43
    {
44
        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

44
        return $this->/** @scrutinizer ignore-call */ belongsTo(Reactant::class, 'love_reactant_id');
Loading history...
45
    }
46
47
    public function getLoveReactant(): ReactantContract
48
    {
49
        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

49
        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

49
        return $this->getAttribute('loveReactant') ?? new NullReactant(/** @scrutinizer ignore-type */ $this);
Loading history...
50
    }
51
52
    public function viaLoveReactant(): ReactantFacadeContract
53
    {
54
        return new ReactantFacade($this->getLoveReactant());
55
    }
56
57
    public function isRegisteredAsLoveReactant(): bool
58
    {
59
        return !$this->isNotRegisteredAsLoveReactant();
60
    }
61
62
    public function isNotRegisteredAsLoveReactant(): bool
63
    {
64
        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

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

75
            'type' => $this->/** @scrutinizer ignore-call */ getMorphClass(),
Loading history...
76
        ]);
77
78
        $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

78
        $this->/** @scrutinizer ignore-call */ 
79
               setAttribute('love_reactant_id', $reactant->getId());
Loading history...
79
        $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

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

116
        $select = $query->getQuery()->columns ?? ["{$this->/** @scrutinizer ignore-call */ getTable()}.*"];
Loading history...
117
        $select[] = DB::raw("COALESCE({$alias}.count, 0) as {$alias}_count");
118
        $select[] = DB::raw("COALESCE({$alias}.weight, 0) as {$alias}_weight");
119
120
        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...
121
            ->leftJoin((new ReactionCounter())->getTable() . ' as '. $alias, function (JoinClause $join) use ($reactionType, $alias) {
122
                $join->on("{$alias}.reactant_id", '=', "{$this->getTable()}.love_reactant_id");
123
                $join->where("{$alias}.reaction_type_id", $reactionType->getId());
124
            })
125
            ->select($select);
126
    }
127
128
    public function scopeJoinReactionTotal(
129
        Builder $query,
130
        ?string $alias = null
131
    ): Builder {
132
        $alias = is_null($alias) ? 'total_reactions' : $alias;
133
        $select = $query->getQuery()->columns ?? ["{$this->getTable()}.*"];
134
        $select[] = DB::raw("COALESCE({$alias}.count, 0) as {$alias}_count");
135
        $select[] = DB::raw("COALESCE({$alias}.weight, 0) as {$alias}_weight");
136
137
        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...
138
            ->leftJoin((new ReactionTotal())->getTable() . ' as ' . $alias, "{$alias}.reactant_id", '=', "{$this->getTable()}.love_reactant_id")
139
            ->select($select);
140
    }
141
}
142