Passed
Push — master ( bc79f7...517d2b )
by Samuel
02:55
created

NoteFinderRepository::findMostRecentNotes()   A

Complexity

Conditions 2
Paths 1

Size

Total Lines 27
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 20
CRAP Score 2

Importance

Changes 0
Metric Value
eloc 15
c 0
b 0
f 0
dl 0
loc 27
ccs 20
cts 20
cp 1
rs 9.7666
cc 2
nc 1
nop 1
crap 2
1
<?php
2
3
namespace App\Domain\Note\Repository;
4
5
use App\Domain\Note\Data\NoteData;
6
use App\Domain\Note\Data\NoteResultData;
7
use App\Infrastructure\Factory\QueryFactory;
0 ignored issues
show
Bug introduced by
The type App\Infrastructure\Factory\QueryFactory was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
8
use App\Infrastructure\Utility\Hydrator;
9
10
class NoteFinderRepository
11
{
12
    /** Fields for queries that populate @see NoteResultData */
13
    public array $noteResultFields = [
14
        'id' => 'note.id',
15
        'client_id' => 'note.client_id',
16
        'message' => 'note.message',
17
        'hidden' => 'note.hidden',
18
        'updated_at' => 'note.updated_at',
19
        'created_at' => 'note.created_at',
20
        'deleted_at' => 'note.deleted_at',
21
        'user_id' => 'note.user_id',
22
    ];
23
24 83
    public function __construct(
25
        private readonly QueryFactory $queryFactory,
26
        private readonly Hydrator $hydrator
27
    ) {
28 83
    }
29
30
    /**
31
     * Return note with given id if it exists
32
     * otherwise null.
33
     *
34
     * @param string|int $id
35
     *
36
     * @return NoteData
37
     */
38 24
    public function findNoteById(string|int $id): NoteData
39
    {
40 24
        $query = $this->queryFactory->selectQuery()->select(['*'])->from('note')->where(
41 24
            ['deleted_at IS' => null, 'id' => $id]
42 24
        );
43 24
        $noteRow = $query->execute()->fetch('assoc') ?: [];
44
45 24
        return new NoteData($noteRow);
46
    }
47
48
    /**
49
     * Return all notes which are linked to the given user except the main note.
50
     *
51
     * @param int $userId
52
     *
53
     * @return NoteResultData[]
54
     */
55 1
    public function findAllNotesExceptMainByUserId(int $userId): array
56
    {
57 1
        $query = $this->queryFactory->selectQuery()->from('note');
58
59 1
        $concatName = $query->func()->concat(['user.first_name' => 'identifier', ' ', 'user.surname' => 'identifier']);
60
61 1
        $query->select(array_merge($this->noteResultFields, ['user_full_name' => $concatName]))
62 1
            ->join(['table' => 'user', 'conditions' => 'note.user_id = user.id'])
63 1
            ->andWhere([
64
                // Not unsafe as it's not an expression and thus escaped by querybuilder
65 1
                'note.user_id' => $userId,
66 1
                'note.is_main' => 0,
67 1
                'note.deleted_at IS' => null,
68 1
            ]);
69 1
        $resultRows = $query->execute()->fetchAll('assoc') ?: [];
70
71
        // Convert to list of Note objects with associated User info
72 1
        return $this->hydrator->hydrate($resultRows, NoteResultData::class);
73
    }
74
75
    /**
76
     * Return all notes which are linked to the given client
77
     * from most recent to oldest EXCEPT for the main note.
78
     *
79
     * @param int $clientId
80
     *
81
     * @return NoteResultData[]
82
     */
83 6
    public function findAllNotesExceptMainWithUserByClientId(int $clientId): array
84
    {
85 6
        $query = $this->queryFactory->selectQuery()->from('note');
86
87 6
        $concatName = $query->func()->concat([
88 6
            $query->func()->coalesce(['user.first_name' => 'identifier', '']),
89 6
            ' ',
90 6
            $query->func()->coalesce(['user.surname' => 'identifier', '']),
91 6
        ]);
92
93 6
        $query->select(array_merge($this->noteResultFields, ['user_full_name' => $concatName]))
94 6
            ->join(['user' => ['table' => 'user', 'type' => 'LEFT', 'conditions' => 'note.user_id = user.id']])
95 6
            ->join(['client' => ['table' => 'client', 'type' => 'LEFT', 'conditions' => 'note.client_id = client.id']])
96 6
            ->where(
97 6
                [
98
                    // Not unsafe as it's not an expression and thus escaped by querybuilder
99 6
                    'note.client_id' => $clientId,
100 6
                    'note.is_main' => 0,
101 6
                    'OR' => [
102 6
                        'note.deleted_at IS' => null,
103 6
                        'note.deleted_at' => $query->identifier('client.deleted_at'),
104 6
                    ],
105 6
                ]
106 6
            )->orderByDesc('note.created_at');
107 6
        $resultRows = $query->execute()->fetchAll('assoc') ?: [];
108
109
        // Convert to list of Note objects with associated User info
110 6
        return $this->hydrator->hydrate($resultRows, NoteResultData::class);
111
    }
112
113
    /**
114
     * Returns given amount of notes ordered by most recent.
115
     *
116
     * @param int $notesAmount
117
     *
118
     * @return NoteResultData[]
119
     */
120 1
    public function findMostRecentNotes(int $notesAmount): array
121
    {
122 1
        $query = $this->queryFactory->selectQuery()->from('note');
123
124 1
        $concatUserName = $query->func()->concat(
125
            // Not very sexy to put IFNULL function there but with "identifier", cake interprets the string literally
126 1
            ['IFNULL(user.first_name, "")' => 'identifier', ' ', 'IFNULL(user.surname, "")' => 'identifier']
127 1
        );
128 1
        $concatClientName = $query->func()->concat(
129 1
            ['IFNULL(client.first_name, "")' => 'identifier', ' ', 'IFNULL(client.last_name, "")' => 'identifier']
130 1
        );
131
132 1
        $query->select(
133 1
            array_merge($this->noteResultFields, [
134 1
                'user_full_name' => $concatUserName,
135 1
                'client_full_name' => $concatClientName,
136 1
            ])
137 1
        )
138 1
            ->join(['table' => 'user', 'conditions' => 'note.user_id = user.id'])
139 1
            ->leftJoin('client', ['note.client_id = client.id'])
140 1
            ->andWhere(['note.deleted_at IS' => null, 'note.is_main' => 0])
141 1
            ->orderByDesc('note.updated_at')->limit($notesAmount);
142
143 1
        $resultRows = $query->execute()->fetchAll('assoc') ?: [];
144
145
        // Convert to list of Note objects with associated User info
146 1
        return $this->hydrator->hydrate($resultRows, NoteResultData::class);
147
    }
148
149
    /**
150
     * Find the amount of notes without counting the main note.
151
     *
152
     * @param int $clientId
153
     *
154
     * @return int
155
     */
156 3
    public function findClientNotesAmount(int $clientId): int
157
    {
158 3
        $query = $this->queryFactory->selectQuery()->from('client');
159
160 3
        $query->select(['amount' => $query->func()->count('n.id')])
161 3
            ->join(['n' => ['table' => 'note', 'type' => 'LEFT', 'conditions' => 'n.client_id = client.id']])
162 3
            ->where(
163 3
                [
164 3
                    'client.id' => $clientId,
165
                    // The main note should not be counted in
166 3
                    'n.is_main' => 0,
167 3
                    'n.deleted_at IS' => null,
168 3
                ]
169 3
            );
170
171
        // Return amount of notes
172 3
        return (int)$query->execute()->fetch('assoc')['amount'];
173
    }
174
}
175