Passed
Push — master ( 0cf9a8...478c1f )
by Anton
03:37
created

src/Reactable/Models/Traits/Reactable.php (10 issues)

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\Reacter\Models\Reacter as ReacterContract;
20
use Cog\Contracts\Love\ReactionType\Models\ReactionType as ReactionTypeContract;
21
use Cog\Laravel\Love\Reactable\Observers\ReactableObserver;
22
use Cog\Laravel\Love\Reactant\Facades\Reactant as ReactantFacade;
23
use Cog\Laravel\Love\Reactant\Models\NullReactant;
24
use Cog\Laravel\Love\Reactant\Models\Reactant;
25
use Cog\Laravel\Love\Reactant\ReactionCounter\Models\ReactionCounter;
26
use Cog\Laravel\Love\Reactant\ReactionTotal\Models\ReactionTotal;
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
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
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...
$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
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
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
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
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
        ReacterContract $reacter,
85
        ?ReactionTypeContract $reactionType = null
86
    ): Builder {
87
        return $query->whereHas('loveReactant.reactions', function (Builder $reactionsQuery) use ($reacter, $reactionType) {
88
            $reactionsQuery->where('reacter_id', $reacter->getId());
89
            if (!is_null($reactionType)) {
90
                $reactionsQuery->where('reaction_type_id', $reactionType->getId());
91
            }
92
        });
93
    }
94
95
    public function scopeJoinReactionCounterOfType(
96
        Builder $query,
97
        ReactionTypeContract $reactionType
98
    ): Builder {
99
        $select = $query->getQuery()->columns ?? ["{$this->getTable()}.*"];
0 ignored issues
show
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

99
        $select = $query->getQuery()->columns ?? ["{$this->/** @scrutinizer ignore-call */ getTable()}.*"];
Loading history...
100
        $select[] = DB::raw('COALESCE(lrrc.count, 0) as reactions_count');
101
        $select[] = DB::raw('COALESCE(lrrc.weight, 0) as reactions_weight');
102
103
        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...
104
            ->leftJoin((new ReactionCounter())->getTable() . ' as lrrc', function (JoinClause $join) use ($reactionType) {
105
                $join->on('lrrc.reactant_id', '=', "{$this->getTable()}.love_reactant_id");
106
                $join->where('lrrc.reaction_type_id', $reactionType->getId());
107
            })
108
            ->select($select);
109
    }
110
111
    public function scopeJoinReactionTotal(
112
        Builder $query
113
    ): Builder {
114
        $select = $query->getQuery()->columns ?? ["{$this->getTable()}.*"];
115
        $select[] = DB::raw('COALESCE(lrrt.count, 0) as reactions_total_count');
116
        $select[] = DB::raw('COALESCE(lrrt.weight, 0) as reactions_total_weight');
117
118
        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...
119
            ->leftJoin((new ReactionTotal())->getTable() . ' as lrrt', 'lrrt.reactant_id', '=', "{$this->getTable()}.love_reactant_id")
120
            ->select($select);
121
    }
122
}
123