|
1
|
|
|
<?php declare(strict_types=1); |
|
2
|
|
|
/** |
|
3
|
|
|
* ownCloud |
|
4
|
|
|
* |
|
5
|
|
|
* This file is licensed under the Affero General Public License version 3 or |
|
6
|
|
|
* later. See the COPYING file. |
|
7
|
|
|
* |
|
8
|
|
|
* @author Alessandro Cosentino <[email protected]> |
|
9
|
|
|
* @author Bernhard Posselt <[email protected]> |
|
10
|
|
|
* @author Pauli Järvinen <[email protected]> |
|
11
|
|
|
* @copyright Alessandro Cosentino 2012 |
|
12
|
|
|
* @copyright Bernhard Posselt 2012, 2014 |
|
13
|
|
|
* @copyright Pauli Järvinen 2017 - 2023 |
|
14
|
|
|
*/ |
|
15
|
|
|
|
|
16
|
|
|
namespace OCA\Music\AppFramework\BusinessLayer; |
|
17
|
|
|
|
|
18
|
|
|
use OCA\Music\Db\BaseMapper; |
|
19
|
|
|
use OCA\Music\Db\Entity; |
|
20
|
|
|
use OCA\Music\Db\MatchMode; |
|
21
|
|
|
use OCA\Music\Db\SortBy; |
|
22
|
|
|
use OCA\Music\Utility\Util; |
|
23
|
|
|
|
|
24
|
|
|
use OCP\AppFramework\Db\DoesNotExistException; |
|
25
|
|
|
use OCP\AppFramework\Db\MultipleObjectsReturnedException; |
|
26
|
|
|
|
|
27
|
|
|
/** |
|
28
|
|
|
* @phpstan-template EntityType of Entity |
|
29
|
|
|
*/ |
|
30
|
|
|
abstract class BusinessLayer { |
|
31
|
|
|
protected $mapper; |
|
32
|
|
|
|
|
33
|
|
|
/** |
|
34
|
|
|
* @phpstan-param BaseMapper<EntityType> $mapper |
|
35
|
|
|
*/ |
|
36
|
|
|
public function __construct(BaseMapper $mapper) { |
|
37
|
|
|
$this->mapper = $mapper; |
|
38
|
|
|
} |
|
39
|
|
|
|
|
40
|
|
|
/** |
|
41
|
|
|
* Update an entity in the database |
|
42
|
|
|
* @phpstan-param EntityType $entity |
|
43
|
|
|
* @phpstan-return EntityType |
|
44
|
|
|
*/ |
|
45
|
|
|
public function update(Entity $entity) : Entity { |
|
46
|
|
|
return $this->mapper->update($entity); |
|
47
|
|
|
} |
|
48
|
|
|
|
|
49
|
|
|
/** |
|
50
|
|
|
* Delete an entity |
|
51
|
|
|
* @param int $id the id of the entity |
|
52
|
|
|
* @param string $userId the name of the user for security reasons |
|
53
|
|
|
* @throws BusinessLayerException if the entity does not exist or more than one entity exists |
|
54
|
|
|
* @phpstan-return EntityType |
|
55
|
|
|
*/ |
|
56
|
|
|
public function delete(int $id, string $userId) : Entity { |
|
57
|
|
|
$entity = $this->find($id, $userId); |
|
58
|
|
|
return $this->mapper->delete($entity); |
|
|
|
|
|
|
59
|
|
|
} |
|
60
|
|
|
|
|
61
|
|
|
/** |
|
62
|
|
|
* Deletes entities without specifying the owning user. |
|
63
|
|
|
* This should never be called directly from the HTML API, but only in case |
|
64
|
|
|
* we can actually trust the passed IDs (e.g. file deleted hook). |
|
65
|
|
|
* @param array $ids the ids of the entities which should be deleted |
|
66
|
|
|
*/ |
|
67
|
|
|
public function deleteById(array $ids) : void { |
|
68
|
|
|
if (\count($ids) > 0) { |
|
69
|
|
|
$this->mapper->deleteById($ids); |
|
70
|
|
|
} |
|
71
|
|
|
} |
|
72
|
|
|
|
|
73
|
|
|
/** |
|
74
|
|
|
* Delete all entities of the given user |
|
75
|
|
|
*/ |
|
76
|
|
|
public function deleteAll(string $userId) : void { |
|
77
|
|
|
$this->mapper->deleteAll($userId); |
|
78
|
|
|
} |
|
79
|
|
|
|
|
80
|
|
|
/** |
|
81
|
|
|
* Finds an entity by id |
|
82
|
|
|
* @param int $id the id of the entity |
|
83
|
|
|
* @param string $userId the name of the user for security reasons |
|
84
|
|
|
* @throws BusinessLayerException if the entity does not exist or more than one entity exists |
|
85
|
|
|
* @phpstan-return EntityType |
|
86
|
|
|
*/ |
|
87
|
|
|
public function find(int $id, string $userId) : Entity { |
|
88
|
|
|
try { |
|
89
|
|
|
return $this->mapper->find($id, $userId); |
|
90
|
|
|
} catch (DoesNotExistException $ex) { |
|
91
|
|
|
throw new BusinessLayerException($ex->getMessage()); |
|
92
|
|
|
} catch (MultipleObjectsReturnedException $ex) { |
|
93
|
|
|
throw new BusinessLayerException($ex->getMessage()); |
|
94
|
|
|
} |
|
95
|
|
|
} |
|
96
|
|
|
|
|
97
|
|
|
/** |
|
98
|
|
|
* Finds an entity by id, or returns an empty entity instance if the requested one is not found |
|
99
|
|
|
* @param int $id the id of the entity |
|
100
|
|
|
* @param string $userId the name of the user for security reasons |
|
101
|
|
|
* @phpstan-return EntityType |
|
102
|
|
|
*/ |
|
103
|
|
|
public function findOrDefault(int $id, string $userId) : Entity { |
|
104
|
|
|
try { |
|
105
|
|
|
return $this->find($id, $userId); |
|
106
|
|
|
} catch (BusinessLayerException $ex) { |
|
107
|
|
|
return $this->mapper->createEntity(); |
|
108
|
|
|
} |
|
109
|
|
|
} |
|
110
|
|
|
|
|
111
|
|
|
/** |
|
112
|
|
|
* Find all entities matching the given IDs. |
|
113
|
|
|
* Specifying the user is optional; if omitted, the caller should make sure that |
|
114
|
|
|
* user's data is not leaked to unauthorized users. |
|
115
|
|
|
* @param integer[] $ids IDs of the entities to be found |
|
116
|
|
|
* @param string|null $userId |
|
117
|
|
|
* @param bool $preserveOrder If true, then the result will be in the same order as @a $ids |
|
118
|
|
|
* @return Entity[] |
|
119
|
|
|
* @phpstan-return EntityType[] |
|
120
|
|
|
*/ |
|
121
|
|
|
public function findById(array $ids, string $userId=null, bool $preserveOrder=false) : array { |
|
122
|
|
|
$entities = []; |
|
123
|
|
|
if (\count($ids) > 0) { |
|
124
|
|
|
// don't use more than 999 SQL args in one query since that may be a problem for SQLite |
|
125
|
|
|
$idChunks = \array_chunk($ids, 998); |
|
126
|
|
|
foreach ($idChunks as $idChunk) { |
|
127
|
|
|
$entities = \array_merge($entities, $this->mapper->findById($idChunk, $userId)); |
|
128
|
|
|
} |
|
129
|
|
|
} |
|
130
|
|
|
|
|
131
|
|
|
if ($preserveOrder) { |
|
132
|
|
|
$lut = Util::createIdLookupTable($entities); |
|
133
|
|
|
$result = []; |
|
134
|
|
|
foreach ($ids as $id) { |
|
135
|
|
|
$result[] = $lut[$id]; |
|
136
|
|
|
} |
|
137
|
|
|
} else { |
|
138
|
|
|
$result = $entities; |
|
139
|
|
|
} |
|
140
|
|
|
|
|
141
|
|
|
return $result; |
|
142
|
|
|
} |
|
143
|
|
|
|
|
144
|
|
|
/** |
|
145
|
|
|
* Finds all entities |
|
146
|
|
|
* @param string $userId the name of the user |
|
147
|
|
|
* @param integer $sortBy sort order of the result set |
|
148
|
|
|
* @param integer|null $limit |
|
149
|
|
|
* @param integer|null $offset |
|
150
|
|
|
* @param string|null $createdMin Optional minimum `created` timestamp. |
|
151
|
|
|
* @param string|null $createdMax Optional maximum `created` timestamp. |
|
152
|
|
|
* @param string|null $updatedMin Optional minimum `updated` timestamp. |
|
153
|
|
|
* @param string|null $updatedMax Optional maximum `updated` timestamp. |
|
154
|
|
|
* @return Entity[] |
|
155
|
|
|
* @phpstan-return EntityType[] |
|
156
|
|
|
*/ |
|
157
|
|
|
public function findAll( |
|
158
|
|
|
string $userId, int $sortBy=SortBy::None, ?int $limit=null, ?int $offset=null, |
|
159
|
|
|
?string $createdMin=null, ?string $createdMax=null, ?string $updatedMin=null, ?string $updatedMax=null) : array { |
|
160
|
|
|
return $this->mapper->findAll($userId, $sortBy, $limit, $offset, $createdMin, $createdMax, $updatedMin, $updatedMax); |
|
161
|
|
|
} |
|
162
|
|
|
|
|
163
|
|
|
/** |
|
164
|
|
|
* Return all entities with name matching the search criteria |
|
165
|
|
|
* @param string|null $createdMin Optional minimum `created` timestamp. |
|
166
|
|
|
* @param string|null $createdMax Optional maximum `created` timestamp. |
|
167
|
|
|
* @param string|null $updatedMin Optional minimum `updated` timestamp. |
|
168
|
|
|
* @param string|null $updatedMax Optional maximum `updated` timestamp. |
|
169
|
|
|
* @return Entity[] |
|
170
|
|
|
* @phpstan-return EntityType[] |
|
171
|
|
|
*/ |
|
172
|
|
|
public function findAllByName( |
|
173
|
|
|
?string $name, string $userId, int $matchMode=MatchMode::Exact, ?int $limit=null, ?int $offset=null, |
|
174
|
|
|
?string $createdMin=null, ?string $createdMax=null, ?string $updatedMin=null, ?string $updatedMax=null) : array { |
|
175
|
|
|
if ($name !== null) { |
|
176
|
|
|
$name = \trim($name); |
|
177
|
|
|
} |
|
178
|
|
|
return $this->mapper->findAllByName($name, $userId, $matchMode, $limit, $offset, $createdMin, $createdMax, $updatedMin, $updatedMax); |
|
179
|
|
|
} |
|
180
|
|
|
|
|
181
|
|
|
/** |
|
182
|
|
|
* Find all starred entities |
|
183
|
|
|
* @return Entity[] |
|
184
|
|
|
* @phpstan-return EntityType[] |
|
185
|
|
|
*/ |
|
186
|
|
|
public function findAllStarred(string $userId, ?int $limit=null, ?int $offset=null) : array { |
|
187
|
|
|
return $this->mapper->findAllStarred($userId, $limit, $offset); |
|
188
|
|
|
} |
|
189
|
|
|
|
|
190
|
|
|
/** |
|
191
|
|
|
* Find all entities with user-given rating 1-5 |
|
192
|
|
|
* @return Entity[] |
|
193
|
|
|
* @phpstan-return EntityType[] |
|
194
|
|
|
*/ |
|
195
|
|
|
public function findAllRated(string $userId, ?int $limit=null, ?int $offset=null) : array { |
|
196
|
|
|
return $this->mapper->findAllRated($userId, $limit, $offset); |
|
197
|
|
|
} |
|
198
|
|
|
|
|
199
|
|
|
/** |
|
200
|
|
|
* Find all entities matching multiple criteria, as needed for the Ampache API method `advanced_search` |
|
201
|
|
|
* @param string $conjunction Operator to use between the rules, either 'and' or 'or' |
|
202
|
|
|
* @param array $rules Array of arrays: [['rule' => string, 'operator' => string, 'input' => string], ...] |
|
203
|
|
|
* Here, 'rule' has dozens of possible values depending on the business layer in question, |
|
204
|
|
|
* (see https://ampache.org/api/api-advanced-search#available-search-rules, alias names not supported here), |
|
205
|
|
|
* 'operator' is one of |
|
206
|
|
|
* ['contain', 'notcontain', 'start', 'end', 'is', 'isnot', '>=', '<=', '=', '!=', '>', '<', 'true', 'false', 'equal', 'ne', 'limit'], |
|
207
|
|
|
* 'input' is the right side value of the 'operator' (disregarded for the operators 'true' and 'false') |
|
208
|
|
|
* @return Entity[] |
|
209
|
|
|
* @phpstan-return EntityType[] |
|
210
|
|
|
*/ |
|
211
|
|
|
public function findAllAdvanced(string $conjunction, array $rules, string $userId, ?int $limit=null, ?int $offset=null) : array { |
|
212
|
|
|
if ($conjunction !== 'and' && $conjunction !== 'or') { |
|
213
|
|
|
throw new BusinessLayerException("Bad conjunction '$conjunction'"); |
|
214
|
|
|
} |
|
215
|
|
|
try { |
|
216
|
|
|
return $this->mapper->findAllAdvanced($conjunction, $rules, $userId, $limit, $offset); |
|
217
|
|
|
} catch (\Exception $e) { |
|
218
|
|
|
// catch everything as many kinds of DB exceptions are possible on various cloud versions |
|
219
|
|
|
throw new BusinessLayerException($e->getMessage()); |
|
220
|
|
|
} |
|
221
|
|
|
} |
|
222
|
|
|
|
|
223
|
|
|
/** |
|
224
|
|
|
* Find IDs of all user's entities of this kind |
|
225
|
|
|
* @return int[] |
|
226
|
|
|
*/ |
|
227
|
|
|
public function findAllIds(string $userId) : array { |
|
228
|
|
|
return $this->mapper->findAllIds($userId); |
|
229
|
|
|
} |
|
230
|
|
|
|
|
231
|
|
|
/** |
|
232
|
|
|
* Find IDs of all users owning any entities of this business layer |
|
233
|
|
|
* @return string[] |
|
234
|
|
|
*/ |
|
235
|
|
|
public function findAllUsers() : array { |
|
236
|
|
|
return $this->mapper->findAllUsers(); |
|
237
|
|
|
} |
|
238
|
|
|
|
|
239
|
|
|
/** |
|
240
|
|
|
* Set the given entities as "starred" on this date |
|
241
|
|
|
* @param int[] $ids |
|
242
|
|
|
* @param string $userId |
|
243
|
|
|
* @return int number of modified entities |
|
244
|
|
|
*/ |
|
245
|
|
|
public function setStarred(array $ids, string $userId) : int { |
|
246
|
|
|
if (\count($ids) > 0) { |
|
247
|
|
|
return $this->mapper->setStarredDate(new \DateTime(), $ids, $userId); |
|
248
|
|
|
} else { |
|
249
|
|
|
return 0; |
|
250
|
|
|
} |
|
251
|
|
|
} |
|
252
|
|
|
|
|
253
|
|
|
/** |
|
254
|
|
|
* Remove the "starred" status of the given entities |
|
255
|
|
|
* @param integer[] $ids |
|
256
|
|
|
* @param string $userId |
|
257
|
|
|
* @return int number of modified entities |
|
258
|
|
|
*/ |
|
259
|
|
|
public function unsetStarred(array $ids, string $userId) : int { |
|
260
|
|
|
if (\count($ids) > 0) { |
|
261
|
|
|
return $this->mapper->setStarredDate(null, $ids, $userId); |
|
262
|
|
|
} else { |
|
263
|
|
|
return 0; |
|
264
|
|
|
} |
|
265
|
|
|
} |
|
266
|
|
|
|
|
267
|
|
|
/** |
|
268
|
|
|
* Tests if entity with given ID and user ID exists in the database |
|
269
|
|
|
* @param int $id |
|
270
|
|
|
* @param string $userId |
|
271
|
|
|
* @return bool |
|
272
|
|
|
*/ |
|
273
|
|
|
public function exists(int $id, string $userId) : bool { |
|
274
|
|
|
return $this->mapper->exists($id, $userId); |
|
275
|
|
|
} |
|
276
|
|
|
|
|
277
|
|
|
/** |
|
278
|
|
|
* Get the number of entities |
|
279
|
|
|
* @param string $userId |
|
280
|
|
|
*/ |
|
281
|
|
|
public function count(string $userId) : int { |
|
282
|
|
|
return $this->mapper->count($userId); |
|
283
|
|
|
} |
|
284
|
|
|
|
|
285
|
|
|
/** |
|
286
|
|
|
* Get the timestamp of the latest insert operation on the entity type in question |
|
287
|
|
|
*/ |
|
288
|
|
|
public function latestInsertTime(string $userId) : \DateTime { |
|
289
|
|
|
return $this->mapper->latestInsertTime($userId) ?? new \DateTime('1970-01-01'); |
|
290
|
|
|
} |
|
291
|
|
|
|
|
292
|
|
|
/** |
|
293
|
|
|
* Get the timestamp of the latest update operation on the entity type in question |
|
294
|
|
|
*/ |
|
295
|
|
|
public function latestUpdateTime(string $userId) : \DateTime { |
|
296
|
|
|
return $this->mapper->latestUpdateTime($userId) ?? new \DateTime('1970-01-01'); |
|
297
|
|
|
} |
|
298
|
|
|
} |
|
299
|
|
|
|
This function has been deprecated. The supplier of the function has supplied an explanatory message.
The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.