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

src/Reactable/Models/Traits/Reactable.php (1 issue)

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');
45
    }
46
47
    public function getLoveReactant(): ReactantContract
48
    {
49
        return $this->getAttribute('loveReactant') ?? new NullReactant($this);
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'));
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(),
76
        ]);
77
78
        $this->setAttribute('love_reactant_id', $reactant->getId());
79
        $this->save();
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
        ?string $alias = null
99
    ): Builder {
100
        $alias = is_null($alias) ? strtolower($reactionType->getName()) : $alias;
101
102
        $select = $query->getQuery()->columns ?? ["{$this->getTable()}.*"];
103
        $select[] = DB::raw("COALESCE({$alias}.count, 0) as {$alias}_count");
104
        $select[] = DB::raw("COALESCE({$alias}.weight, 0) as {$alias}_weight");
105
106
        return $query
107
            ->leftJoin((new ReactionCounter())->getTable() . ' as '. $alias, function (JoinClause $join) use ($reactionType, $alias) {
108
                $join->on("{$alias}.reactant_id", '=', "{$this->getTable()}.love_reactant_id");
109
                $join->where("{$alias}.reaction_type_id", $reactionType->getId());
110
            })
111
            ->select($select);
112
    }
113
114
    public function scopeJoinReactionTotal(
115
        Builder $query
116
    ): Builder {
117
        $select = $query->getQuery()->columns ?? ["{$this->getTable()}.*"];
118
        $select[] = DB::raw('COALESCE(lrrt.count, 0) as reactions_total_count');
119
        $select[] = DB::raw('COALESCE(lrrt.weight, 0) as reactions_total_weight');
120
121
        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...
122
            ->leftJoin((new ReactionTotal())->getTable() . ' as lrrt', 'lrrt.reactant_id', '=', "{$this->getTable()}.love_reactant_id")
123
            ->select($select);
124
    }
125
}
126