Completed
Push — master ( f08741...7d0aeb )
by Anton
09:22
created

findOrCreateReactionTotal()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 5
dl 0
loc 10
rs 10
c 1
b 0
f 0
cc 2
nc 2
nop 0
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\Reactant\Jobs;
15
16
use Cog\Contracts\Love\Reactant\Models\Reactant as ReactantContract;
17
use Cog\Contracts\Love\Reactant\ReactionCounter\Models\ReactionCounter as ReactionCounterContract;
18
use Cog\Contracts\Love\Reactant\ReactionTotal\Models\ReactionTotal as ReactionTotalContract;
19
use Cog\Contracts\Love\ReactionType\Models\ReactionType as ReactionTypeContract;
20
use Cog\Laravel\Love\Reactant\ReactionCounter\Models\ReactionCounter;
21
use Cog\Laravel\Love\Reactant\ReactionCounter\Services\ReactionCounterService;
22
use Cog\Laravel\Love\Reactant\ReactionTotal\Models\NullReactionTotal;
23
use Cog\Laravel\Love\Reactant\ReactionTotal\Models\ReactionTotal;
24
use Illuminate\Bus\Queueable;
25
use Illuminate\Contracts\Queue\ShouldQueue;
26
use Illuminate\Foundation\Bus\Dispatchable;
27
28
final class RebuildReactionAggregatesJob implements
29
    ShouldQueue
30
{
31
    use Dispatchable;
32
    use Queueable;
33
34
    /**
35
     * @var \Cog\Contracts\Love\Reactant\Models\Reactant
36
     */
37
    private $reactant;
38
39
    /**
40
     * @var \Cog\Contracts\Love\ReactionType\Models\ReactionType|null
41
     */
42
    private $reactionType;
43
44
    public function __construct(
45
        ReactantContract $reactant,
46
        ?ReactionTypeContract $reactionType = null
47
    ) {
48
        $this->reactant = $reactant;
49
        $this->reactionType = $reactionType;
50
    }
51
52
    public function handle(
53
    ): void {
54
        $this->recountReactionCounters();
55
        $this->recountReactionTotal();
56
    }
57
58
    private function recountReactionCounters(
59
    ): void {
60
        $this->resetCountersValues();
61
62
        $service = new ReactionCounterService($this->reactant);
63
64
        $reactions = $this->collectReactions();
65
        foreach ($reactions as $reaction) {
66
            $service->addReaction($reaction);
67
        }
68
    }
69
70
    private function recountReactionTotal(
71
    ): void {
72
        $counters = $this->reactant->getReactionCounters();
73
74
        if (count($counters) === 0) {
75
            return;
76
        }
77
78
        $totalCount = ReactionTotal::COUNT_DEFAULT;
79
        $totalWeight = ReactionTotal::WEIGHT_DEFAULT;
80
81
        foreach ($counters as $counter) {
82
            $totalCount += $counter->getCount();
83
            $totalWeight += $counter->getWeight();
84
        }
85
86
        $reactionTotal = $this->findOrCreateReactionTotal();
87
88
        /** @var \Cog\Laravel\Love\Reactant\ReactionTotal\Models\ReactionTotal $reactionTotal */
89
        $reactionTotal->update([
90
            'count' => $totalCount,
91
            'weight' => $totalWeight,
92
        ]);
93
    }
94
95
    private function findOrCreateReactionTotal(
96
    ): ReactionTotalContract {
97
        $reactionTotal = $this->reactant->getReactionTotal();
98
99
        if ($reactionTotal instanceof NullReactionTotal) {
100
            $this->reactant->createReactionTotal();
101
            $reactionTotal = $this->reactant->getReactionTotal();
102
        }
103
104
        return $reactionTotal;
105
    }
106
107
    private function resetCountersValues(
108
    ): void {
109
        $counters = $this->reactant->getReactionCounters();
110
111
        foreach ($counters as $counter) {
112
            if ($this->shouldNotAffectCounter($counter)) {
113
                continue;
114
            }
115
116
            /** @var \Cog\Laravel\Love\Reactant\ReactionCounter\Models\ReactionCounter $counter */
117
            $counter->update([
118
                'count' => ReactionCounter::COUNT_DEFAULT,
119
                'weight' => ReactionCounter::WEIGHT_DEFAULT,
120
            ]);
121
        }
122
    }
123
124
    /**
125
     * @return \Illuminate\Database\Eloquent\Builder[]|\Illuminate\Database\Eloquent\Collection
126
     */
127
    private function collectReactions(
128
    ): iterable {
129
        /** @var \Illuminate\Database\Eloquent\Builder $query */
130
        $query = $this->reactant->reactions();
0 ignored issues
show
Bug introduced by
The method reactions() does not exist on Cog\Contracts\Love\Reactant\Models\Reactant. It seems like you code against a sub-type of Cog\Contracts\Love\Reactant\Models\Reactant such as Cog\Laravel\Love\Reactant\Models\Reactant. ( Ignorable by Annotation )

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

130
        /** @scrutinizer ignore-call */ 
131
        $query = $this->reactant->reactions();
Loading history...
131
132
        if ($this->reactionType !== null) {
133
            $query->where('reaction_type_id', $this->reactionType->getId());
134
        }
135
136
        return $query->get();
137
    }
138
139
    /**
140
     * Determine if counter should not be rebuilt.
141
     *
142
     * @param ReactionCounterContract $counter
143
     * @return bool
144
     */
145
    private function shouldNotAffectCounter(
146
        ReactionCounterContract $counter
147
    ): bool {
148
        return $this->reactionType !== null
149
            && $counter->isNotReactionOfType($this->reactionType);
150
    }
151
}
152