|
1
|
|
|
<?php |
|
2
|
|
|
|
|
3
|
|
|
declare(strict_types=1); |
|
4
|
|
|
|
|
5
|
|
|
/** |
|
6
|
|
|
* balloon |
|
7
|
|
|
* |
|
8
|
|
|
* @copyright Copryright (c) 2012-2018 gyselroth GmbH (https://gyselroth.com) |
|
9
|
|
|
* @license GPL-3.0 https://opensource.org/licenses/GPL-3.0 |
|
10
|
|
|
*/ |
|
11
|
|
|
|
|
12
|
|
|
namespace Balloon; |
|
13
|
|
|
|
|
14
|
|
|
use Balloon\Filesystem\Acl; |
|
15
|
|
|
use Balloon\Filesystem\Acl\Exception\Forbidden as ForbiddenException; |
|
16
|
|
|
use Balloon\Filesystem\Delta; |
|
17
|
|
|
use Balloon\Filesystem\Node\Collection; |
|
18
|
|
|
use Balloon\Filesystem\Node\File; |
|
19
|
|
|
use Balloon\Filesystem\Node\NodeInterface; |
|
20
|
|
|
use Balloon\Filesystem\Storage; |
|
21
|
|
|
use Balloon\Server\User; |
|
22
|
|
|
use Generator; |
|
23
|
|
|
use MongoDB\BSON\ObjectId; |
|
24
|
|
|
use MongoDB\BSON\UTCDateTime; |
|
25
|
|
|
use MongoDB\Database; |
|
26
|
|
|
use Psr\Log\LoggerInterface; |
|
27
|
|
|
|
|
28
|
|
|
class Filesystem |
|
29
|
|
|
{ |
|
30
|
|
|
/** |
|
31
|
|
|
* Database. |
|
32
|
|
|
* |
|
33
|
|
|
* @var Database |
|
34
|
|
|
*/ |
|
35
|
|
|
protected $db; |
|
36
|
|
|
|
|
37
|
|
|
/** |
|
38
|
|
|
* LoggerInterface. |
|
39
|
|
|
* |
|
40
|
|
|
* @var LoggerInterface |
|
41
|
|
|
*/ |
|
42
|
|
|
protected $logger; |
|
43
|
|
|
|
|
44
|
|
|
/** |
|
45
|
|
|
* Hook. |
|
46
|
|
|
* |
|
47
|
|
|
* @var Hook |
|
48
|
|
|
*/ |
|
49
|
|
|
protected $hook; |
|
50
|
|
|
|
|
51
|
|
|
/** |
|
52
|
|
|
* Server. |
|
53
|
|
|
* |
|
54
|
|
|
* @var Server |
|
55
|
|
|
*/ |
|
56
|
|
|
protected $server; |
|
57
|
|
|
|
|
58
|
|
|
/** |
|
59
|
|
|
* Root collection. |
|
60
|
|
|
* |
|
61
|
|
|
* @var Collection |
|
62
|
|
|
*/ |
|
63
|
|
|
protected $root; |
|
64
|
|
|
|
|
65
|
|
|
/** |
|
66
|
|
|
* User. |
|
67
|
|
|
* |
|
68
|
|
|
* @var Delta |
|
69
|
|
|
*/ |
|
70
|
|
|
protected $delta; |
|
71
|
|
|
|
|
72
|
|
|
/** |
|
73
|
|
|
* Get user. |
|
74
|
|
|
* |
|
75
|
|
|
* @var User |
|
76
|
|
|
*/ |
|
77
|
|
|
protected $user; |
|
78
|
|
|
|
|
79
|
|
|
/** |
|
80
|
|
|
* Storage. |
|
81
|
|
|
* |
|
82
|
|
|
* @var Storage |
|
83
|
|
|
*/ |
|
84
|
|
|
protected $storage; |
|
85
|
|
|
|
|
86
|
|
|
/** |
|
87
|
|
|
* Acl. |
|
88
|
|
|
* |
|
89
|
|
|
* @var Acl |
|
90
|
|
|
*/ |
|
91
|
|
|
protected $acl; |
|
92
|
|
|
|
|
93
|
|
|
/** |
|
94
|
|
|
* Node storage cache. |
|
95
|
|
|
* |
|
96
|
|
|
* @var array |
|
97
|
|
|
*/ |
|
98
|
|
|
protected $cache = []; |
|
99
|
|
|
|
|
100
|
|
|
/** |
|
101
|
|
|
* Initialize. |
|
102
|
|
|
* |
|
103
|
|
|
* @param Server $server |
|
104
|
|
|
* @param LoggerInterface $logger |
|
105
|
|
|
* @param User $user |
|
106
|
|
|
*/ |
|
107
|
|
|
public function __construct(Server $server, Database $db, Hook $hook, LoggerInterface $logger, Storage $storage, Acl $acl, ?User $user = null) |
|
108
|
|
|
{ |
|
109
|
|
|
$this->user = $user; |
|
110
|
|
|
$this->server = $server; |
|
111
|
|
|
$this->db = $db; |
|
112
|
|
|
$this->logger = $logger; |
|
113
|
|
|
$this->hook = $hook; |
|
114
|
|
|
$this->storage = $storage; |
|
115
|
|
|
$this->acl = $acl; |
|
116
|
|
|
} |
|
117
|
|
|
|
|
118
|
|
|
/** |
|
119
|
|
|
* Get user. |
|
120
|
|
|
* |
|
121
|
|
|
* @return User |
|
122
|
|
|
*/ |
|
123
|
|
|
public function getUser(): ?User |
|
124
|
|
|
{ |
|
125
|
|
|
return $this->user; |
|
126
|
|
|
} |
|
127
|
|
|
|
|
128
|
|
|
/** |
|
129
|
|
|
* Get server. |
|
130
|
|
|
* |
|
131
|
|
|
* @return Server |
|
132
|
|
|
*/ |
|
133
|
|
|
public function getServer(): Server |
|
134
|
|
|
{ |
|
135
|
|
|
return $this->server; |
|
136
|
|
|
} |
|
137
|
|
|
|
|
138
|
|
|
/** |
|
139
|
|
|
* Get database. |
|
140
|
|
|
* |
|
141
|
|
|
* @return Database |
|
142
|
|
|
*/ |
|
143
|
|
|
public function getDatabase(): Database |
|
144
|
|
|
{ |
|
145
|
|
|
return $this->db; |
|
146
|
|
|
} |
|
147
|
|
|
|
|
148
|
|
|
/** |
|
149
|
|
|
* Get root. |
|
150
|
|
|
* |
|
151
|
|
|
* @return Collection |
|
152
|
|
|
*/ |
|
153
|
|
|
public function getRoot(): Collection |
|
154
|
|
|
{ |
|
155
|
|
|
if ($this->root instanceof Collection) { |
|
156
|
|
|
return $this->root; |
|
157
|
|
|
} |
|
158
|
|
|
|
|
159
|
|
|
return $this->root = $this->initNode([ |
|
160
|
|
|
'directory' => true, |
|
161
|
|
|
'_id' => null, |
|
162
|
|
|
'owner' => $this->user ? $this->user->getId() : null, |
|
163
|
|
|
]); |
|
164
|
|
|
} |
|
165
|
|
|
|
|
166
|
|
|
/** |
|
167
|
|
|
* Get delta. |
|
168
|
|
|
* |
|
169
|
|
|
* @return Delta |
|
170
|
|
|
*/ |
|
171
|
|
|
public function getDelta(): Delta |
|
172
|
|
|
{ |
|
173
|
|
|
if ($this->delta instanceof Delta) { |
|
174
|
|
|
return $this->delta; |
|
175
|
|
|
} |
|
176
|
|
|
|
|
177
|
|
|
return $this->delta = new Delta($this, $this->db); |
|
178
|
|
|
} |
|
179
|
|
|
|
|
180
|
|
|
/** |
|
181
|
|
|
* Find raw node. |
|
182
|
|
|
* |
|
183
|
|
|
* @param ObjectId $id |
|
184
|
|
|
* |
|
185
|
|
|
* @return array |
|
186
|
|
|
*/ |
|
187
|
|
|
public function findRawNode(ObjectId $id): array |
|
188
|
|
|
{ |
|
189
|
|
|
if (isset($this->cache[(string) $id])) { |
|
190
|
|
|
return $this->cache[(string) $id]->getRawAttributes(); |
|
191
|
|
|
} |
|
192
|
|
|
|
|
193
|
|
|
$node = $this->db->storage->findOne(['_id' => $id]); |
|
194
|
|
|
if (null === $node) { |
|
195
|
|
|
throw new Exception\NotFound( |
|
196
|
|
|
'node '.$id.' not found', |
|
197
|
|
|
Exception\NotFound::NODE_NOT_FOUND |
|
198
|
|
|
); |
|
199
|
|
|
} |
|
200
|
|
|
|
|
201
|
|
|
return $node; |
|
202
|
|
|
} |
|
203
|
|
|
|
|
204
|
|
|
/** |
|
205
|
|
|
* Factory loader. |
|
206
|
|
|
* |
|
207
|
|
|
* @param ObjectId|string $id |
|
208
|
|
|
* @param string $class Fore check node type |
|
209
|
|
|
* @param int $deleted |
|
210
|
|
|
* |
|
211
|
|
|
* @return NodeInterface |
|
212
|
|
|
*/ |
|
213
|
|
|
public function findNodeById($id, ?string $class = null, int $deleted = NodeInterface::DELETED_INCLUDE): NodeInterface |
|
214
|
|
|
{ |
|
215
|
|
|
if (isset($this->cache[(string) $id])) { |
|
216
|
|
|
return $this->cache[(string) $id]; |
|
217
|
|
|
} |
|
218
|
|
|
|
|
219
|
|
|
if (!is_string($id) && !($id instanceof ObjectId)) { |
|
|
|
|
|
|
220
|
|
|
throw new Exception\InvalidArgument($id.' node id has to be a string or instance of \MongoDB\BSON\ObjectId'); |
|
221
|
|
|
} |
|
222
|
|
|
|
|
223
|
|
|
try { |
|
224
|
|
|
if (is_string($id)) { |
|
225
|
|
|
$id = new ObjectId($id); |
|
226
|
|
|
} |
|
227
|
|
|
} catch (\Exception $e) { |
|
228
|
|
|
throw new Exception\InvalidArgument('invalid node id specified'); |
|
229
|
|
|
} |
|
230
|
|
|
|
|
231
|
|
|
$filter = [ |
|
232
|
|
|
'_id' => $id, |
|
233
|
|
|
]; |
|
234
|
|
|
|
|
235
|
|
|
switch ($deleted) { |
|
236
|
|
|
case NodeInterface::DELETED_INCLUDE: |
|
237
|
|
|
break; |
|
238
|
|
|
case NodeInterface::DELETED_EXCLUDE: |
|
239
|
|
|
$filter['deleted'] = false; |
|
240
|
|
|
|
|
241
|
|
|
break; |
|
242
|
|
|
case NodeInterface::DELETED_ONLY: |
|
243
|
|
|
$filter['deleted'] = ['$type' => 9]; |
|
244
|
|
|
|
|
245
|
|
|
break; |
|
246
|
|
|
} |
|
247
|
|
|
|
|
248
|
|
|
$node = $this->db->storage->findOne($filter); |
|
249
|
|
|
|
|
250
|
|
|
if (null === $node) { |
|
251
|
|
|
throw new Exception\NotFound( |
|
252
|
|
|
'node ['.$id.'] not found', |
|
253
|
|
|
Exception\NotFound::NODE_NOT_FOUND |
|
254
|
|
|
); |
|
255
|
|
|
} |
|
256
|
|
|
|
|
257
|
|
|
$return = $this->initNode($node); |
|
258
|
|
|
|
|
259
|
|
|
if (null !== $class && !($return instanceof $class)) { |
|
260
|
|
|
throw new Exception('node '.get_class($return).' is not instance of '.$class); |
|
261
|
|
|
} |
|
262
|
|
|
|
|
263
|
|
|
return $return; |
|
264
|
|
|
} |
|
265
|
|
|
|
|
266
|
|
|
/** |
|
267
|
|
|
* Load node with path. |
|
268
|
|
|
* |
|
269
|
|
|
* @param string $path |
|
270
|
|
|
* @param string $class Fore check node type |
|
271
|
|
|
* |
|
272
|
|
|
* @return NodeInterface |
|
273
|
|
|
*/ |
|
274
|
|
|
public function findNodeByPath(string $path = '', ?string $class = null): NodeInterface |
|
275
|
|
|
{ |
|
276
|
|
|
if (empty($path) || '/' !== $path[0]) { |
|
277
|
|
|
$path = '/'.$path; |
|
278
|
|
|
} |
|
279
|
|
|
|
|
280
|
|
|
$last = strlen($path) - 1; |
|
281
|
|
|
if ('/' === $path[$last]) { |
|
282
|
|
|
$path = substr($path, 0, -1); |
|
283
|
|
|
} |
|
284
|
|
|
|
|
285
|
|
|
$parts = explode('/', $path); |
|
286
|
|
|
$parent = $this->getRoot(); |
|
287
|
|
|
array_shift($parts); |
|
288
|
|
|
foreach ($parts as $node) { |
|
289
|
|
|
$parent = $parent->getChild($node, NodeInterface::DELETED_EXCLUDE); |
|
290
|
|
|
} |
|
291
|
|
|
|
|
292
|
|
|
if (null !== $class && !($parent instanceof $class)) { |
|
293
|
|
|
throw new Exception('node is not instance of '.$class); |
|
294
|
|
|
} |
|
295
|
|
|
|
|
296
|
|
|
return $parent; |
|
297
|
|
|
} |
|
298
|
|
|
|
|
299
|
|
|
/** |
|
300
|
|
|
* Load nodes by id. |
|
301
|
|
|
* |
|
302
|
|
|
* @param array $id |
|
303
|
|
|
* @param string $class Force check node type |
|
304
|
|
|
* @param bool $deleted |
|
305
|
|
|
* |
|
306
|
|
|
* @return Generator |
|
307
|
|
|
*/ |
|
308
|
|
|
public function findNodesById(array $id = [], ?string $class = null, int $deleted = NodeInterface::DELETED_INCLUDE): Generator |
|
309
|
|
|
{ |
|
310
|
|
|
$find = []; |
|
311
|
|
|
foreach ($id as $i) { |
|
312
|
|
|
$find[] = new ObjectId($i); |
|
313
|
|
|
} |
|
314
|
|
|
|
|
315
|
|
|
$filter = [ |
|
316
|
|
|
'_id' => ['$in' => $find], |
|
317
|
|
|
]; |
|
318
|
|
|
|
|
319
|
|
|
switch ($deleted) { |
|
320
|
|
|
case NodeInterface::DELETED_INCLUDE: |
|
321
|
|
|
break; |
|
322
|
|
|
case NodeInterface::DELETED_EXCLUDE: |
|
323
|
|
|
$filter['deleted'] = false; |
|
324
|
|
|
|
|
325
|
|
|
break; |
|
326
|
|
|
case NodeInterface::DELETED_ONLY: |
|
327
|
|
|
$filter['deleted'] = ['$type' => 9]; |
|
328
|
|
|
|
|
329
|
|
|
break; |
|
330
|
|
|
} |
|
331
|
|
|
|
|
332
|
|
|
$result = $this->db->storage->find($filter); |
|
333
|
|
|
|
|
334
|
|
|
$nodes = []; |
|
|
|
|
|
|
335
|
|
|
foreach ($result as $node) { |
|
336
|
|
|
$return = $this->initNode($node); |
|
337
|
|
|
|
|
338
|
|
|
if (null !== $class && !($return instanceof $class)) { |
|
339
|
|
|
throw new Exception('node is not an instance of '.$class); |
|
340
|
|
|
} |
|
341
|
|
|
|
|
342
|
|
|
yield $return; |
|
343
|
|
|
} |
|
344
|
|
|
} |
|
345
|
|
|
|
|
346
|
|
|
/** |
|
347
|
|
|
* Load nodes by id. |
|
348
|
|
|
* |
|
349
|
|
|
* @param array $path |
|
350
|
|
|
* @param string $class Force check node type |
|
351
|
|
|
* |
|
352
|
|
|
* @return Generator |
|
353
|
|
|
*/ |
|
354
|
|
|
public function findNodesByPath(array $path = [], ?string $class = null): Generator |
|
355
|
|
|
{ |
|
356
|
|
|
$find = []; |
|
|
|
|
|
|
357
|
|
|
foreach ($path as $p) { |
|
|
|
|
|
|
358
|
|
|
if (empty($path) || '/' !== $path[0]) { |
|
359
|
|
|
$path = '/'.$path; |
|
360
|
|
|
} |
|
361
|
|
|
|
|
362
|
|
|
$last = strlen($path) - 1; |
|
363
|
|
|
if ('/' === $path[$last]) { |
|
364
|
|
|
$path = substr($path, 0, -1); |
|
365
|
|
|
} |
|
366
|
|
|
|
|
367
|
|
|
$parts = explode('/', $path); |
|
368
|
|
|
$parent = $this->getRoot(); |
|
369
|
|
|
array_shift($parts); |
|
370
|
|
|
foreach ($parts as $node) { |
|
371
|
|
|
$parent = $parent->getChild($node, NodeInterface::DELETED_EXCLUDE); |
|
372
|
|
|
} |
|
373
|
|
|
|
|
374
|
|
|
if (null !== $class && !($parent instanceof $class)) { |
|
375
|
|
|
throw new Exception('node is not an instance of '.$class); |
|
376
|
|
|
} |
|
377
|
|
|
|
|
378
|
|
|
yield $parent; |
|
379
|
|
|
} |
|
380
|
|
|
} |
|
381
|
|
|
|
|
382
|
|
|
/** |
|
383
|
|
|
* Load nodes by id. |
|
384
|
|
|
* |
|
385
|
|
|
* @param array $id |
|
386
|
|
|
* @param array $path |
|
387
|
|
|
* @param string $class Force set node type |
|
388
|
|
|
* @param int $deleted |
|
389
|
|
|
* |
|
390
|
|
|
* @return Generator |
|
391
|
|
|
*/ |
|
392
|
|
|
public function getNodes(?array $id = null, ?array $path = null, $class = null, int $deleted = NodeInterface::DELETED_EXCLUDE): Generator |
|
393
|
|
|
{ |
|
394
|
|
|
if (null === $id && null === $path) { |
|
395
|
|
|
throw new Exception\InvalidArgument('neither parameter id nor p (path) was given'); |
|
396
|
|
|
} |
|
397
|
|
|
if (null !== $id && null !== $path) { |
|
398
|
|
|
throw new Exception\InvalidArgument('parameter id and p (path) can not be used at the same time'); |
|
399
|
|
|
} |
|
400
|
|
|
if (null !== $id) { |
|
401
|
|
|
if (null === $deleted) { |
|
402
|
|
|
$deleted = NodeInterface::DELETED_INCLUDE; |
|
403
|
|
|
} |
|
404
|
|
|
|
|
405
|
|
|
return $this->findNodesById($id, $class, $deleted); |
|
406
|
|
|
} |
|
407
|
|
|
if (null !== $path) { |
|
408
|
|
|
if (null === $deleted) { |
|
409
|
|
|
$deleted = NodeInterface::DELETED_EXCLUDE; |
|
|
|
|
|
|
410
|
|
|
} |
|
411
|
|
|
|
|
412
|
|
|
return $this->findNodesByPath($path, $class); |
|
413
|
|
|
} |
|
414
|
|
|
} |
|
415
|
|
|
|
|
416
|
|
|
/** |
|
417
|
|
|
* Load node. |
|
418
|
|
|
* |
|
419
|
|
|
* @param string $id |
|
420
|
|
|
* @param string $path |
|
421
|
|
|
* @param string $class Force set node type |
|
422
|
|
|
* @param bool $multiple Allow $id to be an array |
|
423
|
|
|
* @param bool $allow_root Allow instance of root collection |
|
424
|
|
|
* @param bool $deleted How to handle deleted node |
|
425
|
|
|
* |
|
426
|
|
|
* @return NodeInterface |
|
427
|
|
|
*/ |
|
428
|
|
|
public function getNode($id = null, $path = null, $class = null, bool $multiple = false, bool $allow_root = false, int $deleted = NodeInterface::DELETED_EXCLUDE): NodeInterface |
|
429
|
|
|
{ |
|
430
|
|
|
if (empty($id) && empty($path)) { |
|
431
|
|
|
if (true === $allow_root) { |
|
432
|
|
|
return $this->getRoot(); |
|
433
|
|
|
} |
|
434
|
|
|
|
|
435
|
|
|
throw new Exception\InvalidArgument('neither parameter id nor p (path) was given'); |
|
436
|
|
|
} |
|
437
|
|
|
if (null !== $id && null !== $path) { |
|
438
|
|
|
throw new Exception\InvalidArgument('parameter id and p (path) can not be used at the same time'); |
|
439
|
|
|
} |
|
440
|
|
|
if (null !== $id) { |
|
441
|
|
|
if (null === $deleted) { |
|
442
|
|
|
$deleted = NodeInterface::DELETED_INCLUDE; |
|
443
|
|
|
} |
|
444
|
|
|
|
|
445
|
|
|
if (true === $multiple && is_array($id)) { |
|
446
|
|
|
return $this->findNodesById($id, $class, $deleted); |
|
447
|
|
|
} |
|
448
|
|
|
|
|
449
|
|
|
return $this->findNodeById($id, $class, $deleted); |
|
450
|
|
|
} |
|
451
|
|
|
if (null !== $path) { |
|
452
|
|
|
if (null === $deleted) { |
|
453
|
|
|
$deleted = NodeInterface::DELETED_EXCLUDE; |
|
|
|
|
|
|
454
|
|
|
} |
|
455
|
|
|
|
|
456
|
|
|
return $this->findNodeByPath($path, $class); |
|
457
|
|
|
} |
|
458
|
|
|
} |
|
459
|
|
|
|
|
460
|
|
|
/** |
|
461
|
|
|
* Find node with custom filter. |
|
462
|
|
|
* |
|
463
|
|
|
* @param array $filter |
|
464
|
|
|
* |
|
465
|
|
|
* @return NodeInterface |
|
466
|
|
|
*/ |
|
467
|
|
|
public function findNodeByFilter(array $filter): NodeInterface |
|
468
|
|
|
{ |
|
469
|
|
|
$result = $this->db->storage->findOne($filter); |
|
470
|
|
|
if (null === $result) { |
|
471
|
|
|
throw new Exception\NotFound( |
|
472
|
|
|
'node with custom filter was not found', |
|
473
|
|
|
Exception\NotFound::NODE_NOT_FOUND |
|
474
|
|
|
); |
|
475
|
|
|
} |
|
476
|
|
|
|
|
477
|
|
|
return $this->initNode($result); |
|
478
|
|
|
} |
|
479
|
|
|
|
|
480
|
|
|
/** |
|
481
|
|
|
* Find nodes with custom filters. |
|
482
|
|
|
* |
|
483
|
|
|
* @param array $filter |
|
484
|
|
|
* |
|
485
|
|
|
* @return Generator |
|
486
|
|
|
*/ |
|
487
|
|
|
public function findNodesByFilter(array $filter): Generator |
|
488
|
|
|
{ |
|
489
|
|
|
$result = $this->db->storage->find($filter); |
|
490
|
|
|
$list = []; |
|
|
|
|
|
|
491
|
|
|
|
|
492
|
|
|
foreach ($result as $node) { |
|
493
|
|
|
try { |
|
494
|
|
|
yield $this->initNode($node); |
|
495
|
|
|
} catch (\Exception $e) { |
|
496
|
|
|
$this->logger->info('remove node from result list, failed load node', [ |
|
497
|
|
|
'category' => get_class($this), |
|
498
|
|
|
'exception' => $e, |
|
499
|
|
|
]); |
|
500
|
|
|
} |
|
501
|
|
|
} |
|
502
|
|
|
} |
|
503
|
|
|
|
|
504
|
|
|
/** |
|
505
|
|
|
* Get custom filtered children. |
|
506
|
|
|
* |
|
507
|
|
|
* @param int $deleted |
|
508
|
|
|
* @param array $filter |
|
509
|
|
|
* |
|
510
|
|
|
* @return Generator |
|
511
|
|
|
*/ |
|
512
|
|
|
public function findNodesByFilterUser(int $deleted, array $filter): Generator |
|
513
|
|
|
{ |
|
514
|
|
|
$shares = $this->user->getShares(); |
|
515
|
|
|
$stored_filter = ['$and' => [ |
|
516
|
|
|
[], |
|
517
|
|
|
['$or' => [ |
|
518
|
|
|
['owner' => $this->user->getId()], |
|
519
|
|
|
['shared' => ['$in' => $shares]], |
|
520
|
|
|
]], |
|
521
|
|
|
]]; |
|
522
|
|
|
|
|
523
|
|
|
if (NodeInterface::DELETED_EXCLUDE === $deleted) { |
|
524
|
|
|
$stored_filter['$and'][0]['deleted'] = false; |
|
525
|
|
|
} elseif (NodeInterface::DELETED_ONLY === $deleted) { |
|
526
|
|
|
$stored_filter['$and'][0]['deleted'] = ['$type' => 9]; |
|
527
|
|
|
} |
|
528
|
|
|
|
|
529
|
|
|
$stored_filter['$and'][0] = array_merge($filter, $stored_filter['$and'][0]); |
|
530
|
|
|
$result = $this->db->storage->find($stored_filter); |
|
531
|
|
|
|
|
532
|
|
|
foreach ($result as $node) { |
|
533
|
|
|
try { |
|
534
|
|
|
yield $this->initNode($node); |
|
535
|
|
|
} catch (\Exception $e) { |
|
536
|
|
|
$this->logger->info('remove node from result list, failed load node', [ |
|
537
|
|
|
'category' => get_class($this), |
|
538
|
|
|
'exception' => $e, |
|
539
|
|
|
]); |
|
540
|
|
|
} |
|
541
|
|
|
} |
|
542
|
|
|
} |
|
543
|
|
|
|
|
544
|
|
|
/** |
|
545
|
|
|
* Init node. |
|
546
|
|
|
* |
|
547
|
|
|
* @param array $node |
|
548
|
|
|
* |
|
549
|
|
|
* @return NodeInterface |
|
550
|
|
|
*/ |
|
551
|
|
|
public function initNode(array $node): NodeInterface |
|
552
|
|
|
{ |
|
553
|
|
|
if (isset($node['shared']) && true === $node['shared'] && null !== $this->user && $node['owner'] != $this->user->getId()) { |
|
554
|
|
|
$node = $this->findReferenceNode($node); |
|
555
|
|
|
} |
|
556
|
|
|
|
|
557
|
|
|
//this would result in a recursiv call until the top level node |
|
558
|
|
|
/*if (isset($node['parent'])) { |
|
|
|
|
|
|
559
|
|
|
try { |
|
560
|
|
|
$this->findNodeById($node['parent']); |
|
561
|
|
|
} catch (Exception\InvalidArgument $e) { |
|
562
|
|
|
throw new Exception\InvalidArgument('invalid parent node specified: '.$e->getMessage()); |
|
563
|
|
|
} catch (Exception\NotFound $e) { |
|
564
|
|
|
throw new Exception\InvalidArgument('invalid parent node specified: '.$e->getMessage()); |
|
565
|
|
|
} |
|
566
|
|
|
}*/ |
|
567
|
|
|
|
|
568
|
|
|
if (!array_key_exists('directory', $node)) { |
|
569
|
|
|
throw new Exception('invalid node ['.$node['_id'].'] found, directory attribute does not exists'); |
|
570
|
|
|
} |
|
571
|
|
|
if (true === $node['directory']) { |
|
572
|
|
|
$instance = new Collection($node, $this, $this->logger, $this->hook, $this->acl); |
|
573
|
|
|
} else { |
|
574
|
|
|
$instance = new File($node, $this, $this->logger, $this->hook, $this->acl, $this->storage); |
|
575
|
|
|
} |
|
576
|
|
|
|
|
577
|
|
|
if (!$this->acl->isAllowed($instance, 'r')) { |
|
578
|
|
|
if ($instance->isReference()) { |
|
579
|
|
|
$instance->delete(true); |
|
580
|
|
|
} |
|
581
|
|
|
|
|
582
|
|
|
throw new ForbiddenException( |
|
583
|
|
|
'not allowed to access node', |
|
584
|
|
|
ForbiddenException::NOT_ALLOWED_TO_ACCESS |
|
585
|
|
|
); |
|
586
|
|
|
} |
|
587
|
|
|
|
|
588
|
|
|
if (isset($node['destroy']) && $node['destroy'] instanceof UTCDateTime && $node['destroy']->toDateTime()->format('U') <= time()) { |
|
|
|
|
|
|
589
|
|
|
$this->logger->info('node ['.$node['_id'].'] is not accessible anmyore, destroy node cause of expired destroy flag', [ |
|
590
|
|
|
'category' => get_class($this), |
|
591
|
|
|
]); |
|
592
|
|
|
|
|
593
|
|
|
$instance->delete(true); |
|
594
|
|
|
|
|
595
|
|
|
throw new Exception\Conflict('node is not available anymore'); |
|
596
|
|
|
} |
|
597
|
|
|
|
|
598
|
|
|
$this->cache[(string) $node['_id']] = $instance; |
|
599
|
|
|
|
|
600
|
|
|
return $instance; |
|
601
|
|
|
} |
|
602
|
|
|
|
|
603
|
|
|
/** |
|
604
|
|
|
* Resolve shared node to reference or share depending who requested. |
|
605
|
|
|
* |
|
606
|
|
|
* @param array $node |
|
607
|
|
|
* |
|
608
|
|
|
* @return array |
|
609
|
|
|
*/ |
|
610
|
|
|
protected function findReferenceNode(array $node): array |
|
611
|
|
|
{ |
|
612
|
|
|
if (isset($node['reference']) && ($node['reference'] instanceof ObjectId)) { |
|
|
|
|
|
|
613
|
|
|
$this->logger->debug('reference node ['.$node['_id'].'] requested from share owner, trying to find the shared node', [ |
|
614
|
|
|
'category' => get_class($this), |
|
615
|
|
|
]); |
|
616
|
|
|
|
|
617
|
|
|
$node = $this->db->storage->findOne([ |
|
618
|
|
|
'owner' => $this->user->getId(), |
|
619
|
|
|
'shared' => true, |
|
620
|
|
|
'_id' => $node['reference'], |
|
621
|
|
|
]); |
|
622
|
|
|
|
|
623
|
|
|
if (null === $node) { |
|
624
|
|
|
throw new Exception\NotFound( |
|
625
|
|
|
'no share node for reference node '.$node['reference'].' found', |
|
626
|
|
|
Exception\NotFound::SHARE_NOT_FOUND |
|
627
|
|
|
); |
|
628
|
|
|
} |
|
629
|
|
|
} else { |
|
630
|
|
|
$this->logger->debug('share node ['.$node['_id'].'] requested from member, trying to find the reference node', [ |
|
631
|
|
|
'category' => get_class($this), |
|
632
|
|
|
]); |
|
633
|
|
|
|
|
634
|
|
|
$node = $this->db->storage->findOne([ |
|
635
|
|
|
'owner' => $this->user->getId(), |
|
636
|
|
|
'shared' => true, |
|
637
|
|
|
'reference' => $node['_id'], |
|
638
|
|
|
]); |
|
639
|
|
|
|
|
640
|
|
|
if (null === $node) { |
|
641
|
|
|
throw new Exception\NotFound( |
|
642
|
|
|
'no share reference for node '.$node['_id'].' found', |
|
643
|
|
|
Exception\NotFound::REFERENCE_NOT_FOUND |
|
644
|
|
|
); |
|
645
|
|
|
} |
|
646
|
|
|
} |
|
647
|
|
|
|
|
648
|
|
|
return $node; |
|
649
|
|
|
} |
|
650
|
|
|
} |
|
651
|
|
|
|
This error could be the result of:
1. Missing dependencies
PHP Analyzer uses your
composer.jsonfile (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects thecomposer.jsonto be in the root folder of your repository.Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the
requireorrequire-devsection?2. Missing use statement
PHP does not complain about undefined classes in
ìnstanceofchecks. For example, the following PHP code will work perfectly fine:If you have not tested against this specific condition, such errors might go unnoticed.