Passed
Pull Request — master (#148)
by Anton
08:29
created

RebuildAggregatesJob::recountTotal()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 23
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
eloc 12
c 3
b 0
f 0
dl 0
loc 23
rs 9.8666
cc 3
nc 3
nop 1
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 RebuildAggregatesJob 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($this->reactant);
55
        $this->recountReactionTotal($this->reactant);
56
    }
57
58
    private function recountReactionCounters(
59
        ReactantContract $reactant
60
    ): void {
61
        $this->resetCountersValues();
62
63
        $service = new ReactionCounterService($reactant);
64
65
        $reactions = $this->collectReactions();
66
        foreach ($reactions as $reaction) {
67
            $service->addReaction($reaction);
68
        }
69
    }
70
71
    private function recountReactionTotal(
72
        ReactantContract $reactant
73
    ): void {
74
        $counters = $reactant->getReactionCounters();
75
76
        if (count($counters) === 0) {
77
            return;
78
        }
79
80
        $totalCount = ReactionTotal::COUNT_DEFAULT;
81
        $totalWeight = ReactionTotal::WEIGHT_DEFAULT;
82
83
        foreach ($counters as $counter) {
84
            $totalCount += $counter->getCount();
85
            $totalWeight += $counter->getWeight();
86
        }
87
88
        $reactionTotal = $this->findOrCreateReactionTotal($reactant);
89
90
        /** @var \Cog\Laravel\Love\Reactant\ReactionTotal\Models\ReactionTotal $reactionTotal */
91
        $reactionTotal->update([
92
            'count' => $totalCount,
93
            'weight' => $totalWeight,
94
        ]);
95
    }
96
97
    private function findOrCreateReactionTotal(
98
        ReactantContract $reactant
99
    ): ReactionTotalContract {
100
        $reactionTotal = $reactant->getReactionTotal();
101
102
        if ($reactionTotal instanceof NullReactionTotal) {
103
            $reactant->createReactionTotal();
104
            $reactionTotal = $reactant->getReactionTotal();
105
        }
106
107
        return $reactionTotal;
108
    }
109
110
    private function resetCountersValues(
111
    ): void {
112
        $counters = $this->reactant->getReactionCounters();
113
114
        foreach ($counters as $counter) {
115
            if ($this->shouldNotAffectCounter($counter)) {
116
                continue;
117
            }
118
119
            /** @var \Cog\Laravel\Love\Reactant\ReactionCounter\Models\ReactionCounter $counter */
120
            $counter->update([
121
                'count' => ReactionCounter::COUNT_DEFAULT,
122
                'weight' => ReactionCounter::WEIGHT_DEFAULT,
123
            ]);
124
        }
125
    }
126
127
    /**
128
     * @return \Illuminate\Database\Eloquent\Builder[]|\Illuminate\Database\Eloquent\Collection
129
     */
130
    private function collectReactions(
131
    ): iterable {
132
        /** @var \Illuminate\Database\Eloquent\Builder $query */
133
        $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

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