Passed
Pull Request — main (#55)
by Thierry
05:38
created

MemberService::getFakeMembers()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Siak\Tontine\Service\Tontine;
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 Siak\Tontine\Model\Member;
10
use Siak\Tontine\Service\TenantService;
11
use Siak\Tontine\Service\Traits\EventTrait;
12
use Siak\Tontine\Service\Traits\WithTrait;
13
14
use function count;
15
use function strtolower;
16
use function tap;
17
18
class MemberService
19
{
20
    use EventTrait;
0 ignored issues
show
introduced by
The trait Siak\Tontine\Service\Traits\EventTrait requires some properties which are not provided by Siak\Tontine\Service\Tontine\MemberService: $name, $lendable, $tontine_bills, $amount, $round_bills, $id, $session_bills, $round, $period_once
Loading history...
21
    use WithTrait;
22
23
    /**
24
     * @var bool
25
     */
26
    private bool $filterActive = false;
27
28
    /**
29
     * @param TenantService $tenantService
30
     */
31
    public function __construct(protected TenantService $tenantService)
32
    {}
33
34
    /**
35
     * @param bool $filter
36
     *
37
     * @return self
38
     */
39
    public function active(bool $filter = true): self
40
    {
41
        $this->filterActive = $filter;
42
        return $this;
43
    }
44
45
    /**
46
     * @param string $search
47
     *
48
     * @return Builder|Relation
49
     */
50
    private function getQuery(string $search = ''): Builder|Relation
51
    {
52
        return $this->tenantService->tontine()->members()
53
            ->when($this->filterActive, fn(Builder $query) => $query->active())
54
            ->when($search !== '', function(Builder $query) use($search) {
55
                $search = '%' . strtolower($search) . '%';
56
                return $query->where(DB::raw('lower(name)'), 'like', $search);
57
            });
58
    }
59
60
    /**
61
     * Get a paginated list of members.
62
     *
63
     * @param string $search
64
     * @param int $page
65
     *
66
     * @return Collection
67
     */
68
    public function getMembers(string $search, int $page = 0): Collection
69
    {
70
        return tap($this->getQuery($search), fn($query) => $this->addWith($query))
71
            ->page($page, $this->tenantService->getLimit())
72
            ->orderBy('name', 'asc')
73
            ->get();
74
    }
75
76
    /**
77
     * Get the number of members.
78
     *
79
     * @param string $search
80
     *
81
     * @return int
82
     */
83
    public function getMemberCount(string $search): int
84
    {
85
        return $this->getQuery($search)->count();
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->getQuery($search)->count() could return the type Illuminate\Database\Eloq...uent\Relations\Relation which is incompatible with the type-hinted return integer. Consider adding an additional type-check to rule them out.
Loading history...
86
    }
87
88
    /**
89
     * Get a single member.
90
     *
91
     * @param int $id       The member id
92
     *
93
     * @return Member|null
94
     */
95
    public function getMember(int $id): ?Member
96
    {
97
        return tap($this->getQuery(), fn($query) => $this->addWith($query))
98
            ->find($id);
99
    }
100
101
    /**
102
     * Get a list of members for dropdown.
103
     *
104
     * @return Collection
105
     */
106
    public function getMemberList(): Collection
107
    {
108
        return $this->tenantService->tontine()->members()->active()
109
            ->orderBy('name', 'asc')->pluck('name', 'id');
110
    }
111
112
    /**
113
     * Save active members ids for the round
114
     *
115
     * @return void
116
     */
117
    private function saveActiveMembers()
118
    {
119
        if(!($tontine = $this->tenantService->tontine()) ||
120
            !($round = $this->tenantService->round()))
121
        {
122
            return;
123
        }
124
        $properties = $round->properties;
0 ignored issues
show
Bug introduced by
The property properties does not seem to exist on Siak\Tontine\Model\Round. Are you sure there is no database migration missing?

Checks if undeclared accessed properties appear in database migrations and if the creating migration is correct.

Loading history...
125
        $properties['members'] = $tontine->members()->active()->pluck('id')->all();
126
        $round->saveProperties($properties);
127
    }
128
129
    /**
130
     * Get the number of active members for the current round
131
     *
132
     * @return int
133
     */
134
    public function countActiveMembers(): int
135
    {
136
        // The number of active members is saved in the round, so its current
137
        // value can be retrieved forever, even when the membership will change.
138
        $round = $this->tenantService->round();
139
        if(!isset($round->properties['members']))
0 ignored issues
show
Bug introduced by
The property properties does not seem to exist on Siak\Tontine\Model\Round. Are you sure there is no database migration missing?

Checks if undeclared accessed properties appear in database migrations and if the creating migration is correct.

Loading history...
140
        {
141
            // Create and save the property with the content
142
            $this->saveActiveMembers();
143
            $round->refresh();
144
        }
145
146
        return count($round->properties['members']);
147
    }
148
149
    /**
150
     * Add a new member.
151
     *
152
     * @param array $values
153
     *
154
     * @return bool
155
     */
156
    public function createMember(array $values): bool
157
    {
158
        DB::transaction(function() use($values) {
159
            $tontine = $this->tenantService->tontine();
160
            $member = $tontine->members()->create($values);
161
            // Create members bills
162
            $this->memberCreated($tontine, $member);
0 ignored issues
show
Bug introduced by
It seems like $tontine can also be of type null; however, parameter $tontine of Siak\Tontine\Service\Ton...ervice::memberCreated() does only seem to accept Siak\Tontine\Model\Tontine, maybe add an additional type check? ( Ignorable by Annotation )

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

162
            $this->memberCreated(/** @scrutinizer ignore-type */ $tontine, $member);
Loading history...
163
            $this->saveActiveMembers();
164
        });
165
166
        return true;
167
    }
168
169
    /**
170
     * Add new members.
171
     *
172
     * @param array $values
173
     *
174
     * @return bool
175
     */
176
    public function createMembers(array $values): bool
177
    {
178
        DB::transaction(function() use($values) {
179
            $tontine = $this->tenantService->tontine();
180
            $members = $tontine->members()->createMany($values);
181
            // Create members bills
182
            foreach($members as $member)
183
            {
184
                $this->memberCreated($tontine, $member);
0 ignored issues
show
Bug introduced by
It seems like $tontine can also be of type null; however, parameter $tontine of Siak\Tontine\Service\Ton...ervice::memberCreated() does only seem to accept Siak\Tontine\Model\Tontine, maybe add an additional type check? ( Ignorable by Annotation )

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

184
                $this->memberCreated(/** @scrutinizer ignore-type */ $tontine, $member);
Loading history...
185
            }
186
            $this->saveActiveMembers();
187
        });
188
189
        return true;
190
    }
191
192
    /**
193
     * Update a member.
194
     *
195
     * @param Member $member
196
     * @param array $values    The member data
197
     *
198
     * @return bool
199
     */
200
    public function updateMember(Member $member, array $values): bool
201
    {
202
        return $member->update($values);
203
    }
204
205
    /**
206
     * Toggle a member.
207
     *
208
     * @param Member $member
209
     *
210
     * @return void
211
     */
212
    public function toggleMember(Member $member)
213
    {
214
        $member->update(['active' => !$member->active]);
215
        $this->saveActiveMembers();
216
    }
217
218
    /**
219
     * Delete a member.
220
     *
221
     * @param Member $member
222
     *
223
     * @return void
224
     */
225
    public function deleteMember(Member $member)
226
    {
227
        // Will fail if any bill is already paid.
228
        $billIds = $member->tontine_bills()->pluck('bill_id')
229
            ->concat($member->round_bills()->pluck('bill_id'))
230
            ->concat($member->session_bills()->pluck('bill_id'))
231
            ->concat($member->libre_bills()->pluck('bill_id'));
232
        DB::transaction(function() use($member, $billIds) {
233
            $member->tontine_bills()->delete();
234
            $member->round_bills()->delete();
235
            $member->session_bills()->delete();
236
            $member->libre_bills()->delete();
237
            DB::table('bills')->whereIn('id', $billIds)->delete();
238
            $member->delete();
239
            $this->saveActiveMembers();
240
        });
241
    }
242
243
    /**
244
     * @param int $count
245
     *
246
     * @return Collection
247
     */
248
    public function getFakeMembers(int $count): Collection
249
    {
250
        return Member::factory()->count($count)->make([
251
            'tontine_id' => $this->tenantService->tontine(),
252
        ]);
253
    }
254
}
255