MemberService::getQuery()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 7
c 1
b 0
f 0
nc 1
nop 3
dl 0
loc 9
rs 10
1
<?php
2
3
namespace Siak\Tontine\Service\Planning;
4
5
use Illuminate\Database\Eloquent\Builder;
6
use Illuminate\Database\Eloquent\Relations\Relation;
7
use Illuminate\Support\Collection;
8
use Illuminate\Support\Facades\DB;
9
use Lagdo\Facades\Logger;
10
use Siak\Tontine\Exception\MessageException;
11
use Siak\Tontine\Model\MemberDef;
12
use Siak\Tontine\Model\Round;
13
use Siak\Tontine\Service\TenantService;
14
use Siak\Tontine\Service\Traits\WithTrait;
15
use Siak\Tontine\Validation\SearchSanitizer;
16
use Exception;
17
18
use function trans;
19
20
class MemberService
21
{
22
    use WithTrait;
23
24
    /**
25
     * @param TenantService $tenantService
26
     * @param BillSyncService $billSyncService
27
     * @param SearchSanitizer $searchSanitizer
28
     */
29
    public function __construct(private TenantService $tenantService,
30
        private BillSyncService $billSyncService, private SearchSanitizer $searchSanitizer)
31
    {}
32
33
    /**
34
     * @param Round $round
35
     * @param string $search
36
     * @param bool $filter|null
37
     *
38
     * @return Relation
39
     */
40
    private function getQuery(Round $round, string $search, ?bool $filter): Relation
41
    {
42
        $onRoundFilter = fn(Builder $q) => $q->where('round_id', $round->id);
43
        return $round->guild->members()
44
            ->search($this->searchSanitizer->sanitize($search))
45
            ->when($filter === true, fn(Builder $query) => $query
46
                ->whereHas('members', $onRoundFilter))
47
            ->when($filter === false, fn(Builder $query) => $query
48
                ->whereDoesntHave('members', $onRoundFilter));
49
    }
50
51
    /**
52
     * Get a paginated list of members.
53
     *
54
     * @param Round $round
55
     * @param string $search
56
     * @param bool $filter|null
57
     * @param int $page
58
     *
59
     * @return Collection
60
     */
61
    public function getMemberDefs(Round $round, string $search, ?bool $filter, int $page = 0): Collection
62
    {
63
        return $this->getQuery($round, $search, $filter)
64
            ->withCount([
65
                'members' => fn(Builder $q) => $q->where('round_id', $round->id),
66
            ])
67
            ->page($page, $this->tenantService->getLimit())
68
            ->orderBy('name', 'asc')
69
            ->get();
70
    }
71
72
    /**
73
     * Get the number of members.
74
     *
75
     * @param Round $round
76
     * @param string $search
77
     * @param bool $filter|null
78
     *
79
     * @return int
80
     */
81
    public function getMemberDefCount(Round $round, string $search, ?bool $filter): int
82
    {
83
        return $this->getQuery($round, $search, $filter)->count();
84
    }
85
86
    /**
87
     * Get a single member.
88
     *
89
     * @param Round $round
90
     * @param int $memberId
91
     *
92
     * @return MemberDef|null
93
     */
94
    public function getMemberDef(Round $round, int $memberId): ?MemberDef
95
    {
96
        return $this->getQuery($round, '', null)
97
            // It's important to fetch the relations and filter on the round here.
98
            ->with([
99
                'members' => fn(Relation $q) => $q->where('round_id', $round->id),
100
            ])
101
            ->find($memberId);
102
    }
103
104
    /**
105
     * Add a new member.
106
     *
107
     * @param Round $round
108
     * @param int $defId
109
     *
110
     * @return void
111
     */
112
    public function enableMember(Round $round, int $defId): void
113
    {
114
        $def = $this->getMemberDef($round, $defId);
115
        if(!$def || $def->members->count() > 0)
116
        {
117
            return;
118
        }
119
120
        DB::transaction(function() use($round, $def) {
121
            $member = $def->members()->create(['round_id' => $round->id]);
122
123
            $this->billSyncService->memberEnabled($round, $member);
124
        });
125
    }
126
127
    /**
128
     * Delete a member.
129
     *
130
     * @param Round $round
131
     * @param int $defId
132
     *
133
     * @return void
134
     */
135
    public function disableMember(Round $round, int $defId): void
136
    {
137
        $def = $this->getMemberDef($round, $defId);
138
        if(!$def || $def->members->count() === 0)
139
        {
140
            return;
141
        }
142
143
        $member = $def->members->first();
144
        try
145
        {
146
            DB::transaction(function() use($round, $member) {
147
                $this->billSyncService->memberRemoved($round, $member);
148
149
                $member->delete();
150
            });
151
        }
152
        catch(Exception $e)
153
        {
154
            Logger::error('Error while removing a member.', [
155
                'message' => $e->getMessage(),
156
            ]);
157
            throw new MessageException(trans('tontine.member.errors.cannot_remove'));
158
        }
159
    }
160
161
    /**
162
     * Get the number of active members in the round.
163
     *
164
     * @param Round $round
165
     *
166
     * @return int
167
     */
168
    public function getMemberCount(Round $round): int
169
    {
170
        return $round->members()->count();
171
    }
172
}
173