Completed
Push — master ( bca2e7...1f8246 )
by Maxence
02:35 queued 11s
created

CoreQueryBuilder::limitToSanitizedName()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 3
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
1
<?php
2
3
declare(strict_types=1);
4
5
6
/**
7
 * Circles - Bring cloud-users closer together.
8
 *
9
 * This file is licensed under the Affero General Public License version 3 or
10
 * later. See the COPYING file.
11
 *
12
 * @author Maxence Lange <[email protected]>
13
 * @copyright 2021
14
 * @license GNU AGPL version 3 or any later version
15
 *
16
 * This program is free software: you can redistribute it and/or modify
17
 * it under the terms of the GNU Affero General Public License as
18
 * published by the Free Software Foundation, either version 3 of the
19
 * License, or (at your option) any later version.
20
 *
21
 * This program is distributed in the hope that it will be useful,
22
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24
 * GNU Affero General Public License for more details.
25
 *
26
 * You should have received a copy of the GNU Affero General Public License
27
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
28
 *
29
 */
30
31
32
namespace OCA\Circles\Db;
33
34
35
use daita\MySmallPhpTools\Db\Nextcloud\nc22\NC22ExtendedQueryBuilder;
36
use daita\MySmallPhpTools\Traits\TArrayTools;
37
use Doctrine\DBAL\Query\QueryBuilder;
38
use OC;
39
use OCA\Circles\Exceptions\RequestBuilderException;
40
use OCA\Circles\IFederatedModel;
41
use OCA\Circles\IFederatedUser;
42
use OCA\Circles\Model\Circle;
43
use OCA\Circles\Model\Federated\RemoteInstance;
44
use OCA\Circles\Model\FederatedUser;
45
use OCA\Circles\Model\Member;
46
use OCA\Circles\Service\ConfigService;
47
use OCP\DB\QueryBuilder\ICompositeExpression;
48
use OCP\DB\QueryBuilder\IQueryBuilder;
49
50
51
/**
52
 * Class CoreQueryBuilder
53
 *
54
 * @package OCA\Circles\Db
55
 */
56
class CoreQueryBuilder extends NC22ExtendedQueryBuilder {
57
58
59
	use TArrayTools;
60
61
62
	const SINGLE = 'single';
63
	const CIRCLE = 'circle';
64
	const MEMBER = 'member';
65
	const OWNER = 'owner';
66
	const FEDERATED_EVENT = 'federatedevent';
67
	const REMOTE = 'remote';
68
	const BASED_ON = 'basedon';
69
	const INITIATOR = 'initiator';
70
	const MEMBERSHIPS = 'memberships';
71
	const UPSTREAM_MEMBERSHIPS = 'upstreammemberships';
72
	const INHERITANCE_FROM = 'inheritancefrom';
73
	const INHERITED_BY = 'inheritedby';
74
	const INVITED_BY = 'invitedby';
75
	const MOUNT = 'mount';
76
	const MOUNTPOINT = 'mountpoint';
77
	const SHARE = 'share';
78
	const FILE_CACHE = 'filecache';
79
	const STORAGES = 'storages';
80
	const OPTIONS = 'options';
81
	const HELPER = 'circleshelper';
82
83
84
	public static $SQL_PATH = [
85
		self::SINGLE => [
86
			self::MEMBER
87
		],
88
		self::CIRCLE => [
89
			self::OPTIONS   => [
90
				'getPersonalCircle' => true
91
			],
92
			self::MEMBER,
93
			self::OWNER     => [
94
				self::BASED_ON
95
			],
96
			self::MEMBERSHIPS,
97
			self::INITIATOR => [
98
				self::BASED_ON,
99
				self::INHERITED_BY => [
100
					self::MEMBERSHIPS
101
				]
102
			],
103
			self::REMOTE    => [
104
				self::MEMBER,
105
				self::CIRCLE => [
106
					self::OWNER
107
				]
108
			]
109
		],
110
		self::MEMBER => [
111
			self::MEMBERSHIPS,
112
			self::INHERITANCE_FROM,
113
			self::CIRCLE     => [
114
				self::OPTIONS   => [
115
					'getData' => true
116
				],
117
				self::OWNER,
118
				self::MEMBERSHIPS,
119
				self::INITIATOR => [
120
					self::OPTIONS      => [
121
						'mustBeMember' => true,
122
						'canBeVisitor' => false
123
					],
124
					self::BASED_ON,
125
					self::INHERITED_BY => [
126
						self::MEMBERSHIPS
127
					],
128
					self::INVITED_BY   => [
129
						self::OWNER,
130
						self::BASED_ON
131
					]
132
				]
133
			],
134
			self::BASED_ON   => [
135
				self::OWNER,
136
				self::MEMBERSHIPS,
137
				self::INITIATOR => [
138
					self::BASED_ON,
139
					self::INHERITED_BY => [
140
						self::MEMBERSHIPS
141
					]
142
				]
143
			],
144
			self::REMOTE     => [
145
				self::MEMBER,
146
				self::CIRCLE => [
147
					self::OWNER
148
				]
149
			],
150
			self::INVITED_BY => [
151
				self::OWNER,
152
				self::BASED_ON
153
			]
154
		],
155
		self::SHARE  => [
156
			self::SHARE,
157
			self::FILE_CACHE           => [
158
				self::STORAGES
159
			],
160
			self::UPSTREAM_MEMBERSHIPS => [
161
				self::MEMBERSHIPS,
162
				self::INHERITED_BY => [
163
					self::BASED_ON
164
				],
165
				self::SHARE,
166
			],
167
			self::MEMBERSHIPS,
168
			self::INHERITANCE_FROM,
169
			self::INHERITED_BY         => [
170
				self::BASED_ON
171
			],
172
			self::CIRCLE               => [
173
				self::OWNER
174
			],
175
			self::INITIATOR            => [
176
				self::BASED_ON,
177
				self::INHERITED_BY => [
178
					self::MEMBERSHIPS
179
				]
180
			]
181
		],
182
		self::REMOTE => [
183
			self::MEMBER
184
		],
185
		self::MOUNT  => [
186
			self::MEMBER    => [
187
				self::REMOTE
188
			],
189
			self::INITIATOR => [
190
				self::INHERITED_BY => [
191
					self::MEMBERSHIPS
192
				]
193
			],
194
			self::MOUNTPOINT,
195
			self::MEMBERSHIPS
196
		],
197
		self::HELPER => [
198
			self::MEMBERSHIPS,
199
			self::INITIATOR => [
200
				self::INHERITED_BY => [
201
					self::MEMBERSHIPS
202
				]
203
			],
204
			self::CIRCLE    => [
205
				self::OPTIONS => [
206
					'getPersonalCircle' => true
207
				],
208
				self::MEMBER,
209
				self::OWNER   => [
210
					self::BASED_ON
211
				]
212
			]
213
		]
214
	];
215
216
217
	/** @var ConfigService */
218
	private $configService;
219
220
221
	/** @var array */
222
	private $options = [];
223
224
225
	/**
226
	 * CoreQueryBuilder constructor.
227
	 */
228
	public function __construct() {
229
		parent::__construct();
230
231
		$this->configService = OC::$server->get(ConfigService::class);
232
	}
233
234
235
	/**
236
	 * @param IFederatedModel $federatedModel
237
	 *
238
	 * @return string
239
	 */
240
	public function getInstance(IFederatedModel $federatedModel): string {
241
		$instance = $federatedModel->getInstance();
242
243
		return ($this->configService->isLocalInstance($instance)) ? '' : $instance;
244
	}
245
246
247
	/**
248
	 * @param string $id
249
	 */
250
	public function limitToCircleId(string $id): void {
251
		$this->limitToDBField('circle_id', $id, true);
0 ignored issues
show
Deprecated Code introduced by
The method daita\MySmallPhpTools\Db...ilder::limitToDBField() has been deprecated with message: - use limit();

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
252
	}
253
254
	/**
255
	 * @param string $name
256
	 */
257
	public function limitToName(string $name): void {
258
		$this->limit('name', $name);
259
	}
260
261
	/**
262
	 * @param string $name
263
	 */
264
	public function limitToDisplayName(string $name): void {
265
		$this->limit('display_name', $name, '', false);
266
	}
267
268
	/**
269
	 * @param string $name
270
	 */
271
	public function limitToSanitizedName(string $name): void {
272
		$this->limit('sanitized_name', $name, '', false);
273
	}
274
275
	/**
276
	 * @param int $config
277
	 */
278
	public function limitToConfig(int $config): void {
279
		$this->limitToDBFieldInt('config', $config);
0 ignored issues
show
Deprecated Code introduced by
The method daita\MySmallPhpTools\Db...er::limitToDBFieldInt() has been deprecated with message: - use limitInt()

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
280
	}
281
282
	/**
283
	 * @param int $source
284
	 */
285
	public function limitToSource(int $source): void {
286
		$this->limitToDBFieldInt('source', $source);
0 ignored issues
show
Deprecated Code introduced by
The method daita\MySmallPhpTools\Db...er::limitToDBFieldInt() has been deprecated with message: - use limitInt()

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
287
	}
288
289
	/**
290
	 * @param int $config
291
	 * @param string $alias
292
	 */
293
	public function limitToConfigFlag(int $config, string $alias = ''): void {
294
		$this->limitBitwise('config', $config, $alias);
295
	}
296
297
298
	/**
299
	 * @param string $singleId
300
	 */
301
	public function limitToSingleId(string $singleId): void {
302
		$this->limitToDBField('single_id', $singleId, true);
0 ignored issues
show
Deprecated Code introduced by
The method daita\MySmallPhpTools\Db...ilder::limitToDBField() has been deprecated with message: - use limit();

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
303
	}
304
305
306
	/**
307
	 * @param string $itemId
308
	 */
309
	public function limitToItemId(string $itemId): void {
310
		$this->limitToDBField('item_id', $itemId, true);
0 ignored issues
show
Deprecated Code introduced by
The method daita\MySmallPhpTools\Db...ilder::limitToDBField() has been deprecated with message: - use limit();

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
311
	}
312
313
314
	/**
315
	 * @param string $host
316
	 */
317
	public function limitToInstance(string $host): void {
318
		$this->limitToDBField('instance', $host, false);
0 ignored issues
show
Deprecated Code introduced by
The method daita\MySmallPhpTools\Db...ilder::limitToDBField() has been deprecated with message: - use limit();

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
319
	}
320
321
322
	/**
323
	 * @param int $userType
324
	 */
325
	public function limitToUserType(int $userType): void {
326
		$this->limitToDBFieldInt('user_type', $userType);
0 ignored issues
show
Deprecated Code introduced by
The method daita\MySmallPhpTools\Db...er::limitToDBFieldInt() has been deprecated with message: - use limitInt()

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
327
	}
328
329
330
	/**
331
	 * @param int $shareType
332
	 */
333
	public function limitToShareType(int $shareType): void {
334
		$this->limitToDBFieldInt('share_type', $shareType);
0 ignored issues
show
Deprecated Code introduced by
The method daita\MySmallPhpTools\Db...er::limitToDBFieldInt() has been deprecated with message: - use limitInt()

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
335
	}
336
337
338
	/**
339
	 * @param string $shareWith
340
	 */
341
	public function limitToShareWith(string $shareWith): void {
342
		$this->limitToDBField('share_with', $shareWith);
0 ignored issues
show
Deprecated Code introduced by
The method daita\MySmallPhpTools\Db...ilder::limitToDBField() has been deprecated with message: - use limit();

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
343
	}
344
345
346
	/**
347
	 * @param int $nodeId
348
	 */
349
	public function limitToFileSource(int $nodeId): void {
350
		$this->limitToDBFieldInt('file_source', $nodeId);
0 ignored issues
show
Deprecated Code introduced by
The method daita\MySmallPhpTools\Db...er::limitToDBFieldInt() has been deprecated with message: - use limitInt()

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
351
	}
352
353
	/**
354
	 * @param array $files
355
	 */
356
	public function limitToFileSourceArray(array $files): void {
357
		$this->limitToDBFieldInArray('file_source', $files);
0 ignored issues
show
Deprecated Code introduced by
The method daita\MySmallPhpTools\Db...limitToDBFieldInArray() has been deprecated with message: - use limitInArray()

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
358
	}
359
360
361
	/**
362
	 * @param int $shareId
363
	 */
364
	public function limitToShareParent(int $shareId): void {
365
		$this->limitToDBFieldInt('parent', $shareId);
0 ignored issues
show
Deprecated Code introduced by
The method daita\MySmallPhpTools\Db...er::limitToDBFieldInt() has been deprecated with message: - use limitInt()

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
366
	}
367
368
369
	/**
370
	 * @param Circle $circle
371
	 */
372
	public function filterCircle(Circle $circle): void {
373
		if ($this->getType() !== QueryBuilder::SELECT) {
374
			return;
375
		}
376
377
		if ($circle->getDisplayName() !== '') {
378
			$this->searchInDBField('display_name', '%' . $circle->getDisplayName() . '%');
379
		}
380
	}
381
382
383
	/**
384
	 * left join RemoteInstance based on a Member
385
	 */
386
	public function leftJoinRemoteInstance(string $alias): void {
387
		$expr = $this->expr();
388
389
		try {
390
			$aliasRemoteInstance = $this->generateAlias($alias, self::REMOTE);
391
			$this->generateRemoteInstanceSelectAlias($aliasRemoteInstance)
392
				 ->leftJoin(
393
					 $alias, CoreRequestBuilder::TABLE_REMOTE, $aliasRemoteInstance,
394
					 $expr->eq($alias . '.instance', $aliasRemoteInstance . '.instance')
395
				 );
396
		} catch (RequestBuilderException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
397
		}
398
	}
399
400
401
	/**
402
	 * @param string $alias
403
	 * @param RemoteInstance $remoteInstance
404
	 * @param bool $filterSensitiveData
405
	 * @param string $aliasCircle
406
	 *
407
	 * @throws RequestBuilderException
408
	 */
409
	public function limitToRemoteInstance(
410
		string $alias,
411
		RemoteInstance $remoteInstance,
412
		bool $filterSensitiveData = true,
413
		string $aliasCircle = ''
414
	): void {
415
416
		if ($aliasCircle === '') {
417
			$aliasCircle = $alias;
418
		}
419
420
		$this->leftJoinRemoteInstanceIncomingRequest($alias, $remoteInstance);
421
		$this->leftJoinMemberFromInstance($alias, $remoteInstance, $aliasCircle);
422
		$this->leftJoinMemberFromRemoteCircle($alias, $remoteInstance, $aliasCircle);
423
		$this->limitRemoteVisibility($alias, $filterSensitiveData, $aliasCircle);
424
	}
425
426
427
	/**
428
	 * Left join RemoteInstance based on an incoming request
429
	 *
430
	 * @param string $alias
431
	 * @param RemoteInstance $remoteInstance
432
	 *
433
	 * @throws RequestBuilderException
434
	 */
435
	public function leftJoinRemoteInstanceIncomingRequest(
436
		string $alias,
437
		RemoteInstance $remoteInstance
438
	): void {
439
		if ($this->getType() !== QueryBuilder::SELECT) {
440
			return;
441
		}
442
443
		$aliasRemote = $this->generateAlias($alias, self::REMOTE);
444
		$expr = $this->expr();
445
		$this->leftJoin(
446
			$this->getDefaultSelectAlias(), CoreRequestBuilder::TABLE_REMOTE, $aliasRemote,
447
			$expr->eq($aliasRemote . '.instance', $this->createNamedParameter($remoteInstance->getInstance()))
448
		);
449
	}
450
451
452
	/**
453
	 * left join members to check memberships of someone from instance
454
	 *
455
	 * @param string $alias
456
	 * @param RemoteInstance $remoteInstance
457
	 * @param string $aliasCircle
458
	 *
459
	 * @throws RequestBuilderException
460
	 */
461
	private function leftJoinMemberFromInstance(
462
		string $alias, RemoteInstance $remoteInstance, string $aliasCircle
463
	) {
464
		if ($this->getType() !== QueryBuilder::SELECT) {
465
			return;
466
		}
467
468
		$aliasRemote = $this->generateAlias($alias, self::REMOTE);
469
		$aliasRemoteMember = $this->generateAlias($aliasRemote, self::MEMBER);
470
471
		$expr = $this->expr();
472
		$this->leftJoin(
473
			$this->getDefaultSelectAlias(), CoreRequestBuilder::TABLE_MEMBER, $aliasRemoteMember,
474
			$expr->andX(
475
				$expr->eq($aliasRemoteMember . '.circle_id', $aliasCircle . '.unique_id'),
476
				$expr->eq(
477
					$aliasRemoteMember . '.instance',
478
					$this->createNamedParameter($remoteInstance->getInstance())
479
				),
480
				$expr->gte($aliasRemoteMember . '.level', $this->createNamedParameter(Member::LEVEL_MEMBER))
481
			)
482
		);
483
	}
484
485
486
	/**
487
	 * left join circle is member of a circle from remote instance
488
	 *
489
	 * @param string $alias
490
	 * @param RemoteInstance $remoteInstance
491
	 * @param string $aliasCircle
492
	 *
493
	 * @throws RequestBuilderException
494
	 */
495
	private function leftJoinMemberFromRemoteCircle(
496
		string $alias,
497
		RemoteInstance $remoteInstance,
498
		string $aliasCircle
499
	) {
500
		if ($this->getType() !== QueryBuilder::SELECT) {
501
			return;
502
		}
503
504
		$aliasRemote = $this->generateAlias($alias, self::REMOTE);
505
		$aliasRemoteCircle = $this->generateAlias($aliasRemote, self::CIRCLE);
506
		$aliasRemoteCircleOwner = $this->generateAlias($aliasRemoteCircle, self::OWNER);
507
508
		$expr = $this->expr();
509
		$this->leftJoin(
510
			$this->getDefaultSelectAlias(), CoreRequestBuilder::TABLE_MEMBER, $aliasRemoteCircle,
511
			$expr->andX(
512
				$expr->eq($aliasRemoteCircle . '.single_id', $aliasCircle . '.unique_id'),
513
				$expr->emptyString($aliasRemoteCircle . '.instance'),
514
				$expr->gte($aliasRemoteCircle . '.level', $this->createNamedParameter(Member::LEVEL_MEMBER))
515
			)
516
		);
517
		$this->leftJoin(
518
			$this->getDefaultSelectAlias(), CoreRequestBuilder::TABLE_MEMBER, $aliasRemoteCircleOwner,
519
			$expr->andX(
520
				$expr->eq($aliasRemoteCircle . '.circle_id', $aliasRemoteCircleOwner . '.circle_id'),
521
				$expr->eq(
522
					$aliasRemoteCircleOwner . '.instance',
523
					$this->createNamedParameter($remoteInstance->getInstance())
524
				),
525
				$expr->eq(
526
					$aliasRemoteCircleOwner . '.level', $this->createNamedParameter(Member::LEVEL_OWNER)
527
				)
528
			)
529
		);
530
	}
531
532
533
	/**
534
	 * - global_scale: visibility on all Circles
535
	 * - trusted: visibility on all FEDERATED Circle if owner is local
536
	 * - external: visibility on all FEDERATED Circle if owner is local and:
537
	 *    - with if Circle contains at least one member from the remote instance
538
	 *    - one circle from the remote instance contains the local circle as member, and confirmed (using
539
	 *      sync locally)
540
	 * - passive: like external, but the members list will only contains member from the local instance and
541
	 * from the remote instance.
542
	 *
543
	 * @param string $alias
544
	 * @param bool $sensitive
545
	 * @param string $aliasCircle
546
	 *
547
	 * @throws RequestBuilderException
548
	 */
549
	protected function limitRemoteVisibility(string $alias, bool $sensitive, string $aliasCircle) {
550
		$aliasRemote = $this->generateAlias($alias, self::REMOTE);
551
		$aliasOwner = $this->generateAlias($aliasCircle, self::OWNER);
552
		$aliasRemoteMember = $this->generateAlias($aliasRemote, self::MEMBER);
553
		$aliasRemoteCircle = $this->generateAlias($aliasRemote, self::CIRCLE);
554
		$aliasRemoteCircleOwner = $this->generateAlias($aliasRemoteCircle, self::OWNER);
555
556
		$expr = $this->expr();
557
		$orX = $expr->orX();
558
		$orX->add(
559
			$expr->eq($aliasRemote . '.type', $this->createNamedParameter(RemoteInstance::TYPE_GLOBALSCALE))
560
		);
561
562
		$orExtOrPassive = $expr->orX();
563
		$orExtOrPassive->add(
564
			$expr->eq($aliasRemote . '.type', $this->createNamedParameter(RemoteInstance::TYPE_EXTERNAL))
565
		);
566
		if (!$sensitive) {
567
			$orExtOrPassive->add(
568
				$expr->eq($aliasRemote . '.type', $this->createNamedParameter(RemoteInstance::TYPE_PASSIVE))
569
			);
570
		} else {
571
			if ($this->getDefaultSelectAlias() === CoreQueryBuilder::MEMBER) {
572
				$orExtOrPassive->add($this->limitRemoteVisibility_Sensitive_Members($aliasRemote));
573
			}
574
		}
575
576
		$orInstance = $expr->orX();
577
		$orInstance->add($expr->isNotNull($aliasRemoteMember . '.instance'));
578
		$orInstance->add($expr->isNotNull($aliasRemoteCircleOwner . '.instance'));
579
580
		$andExternal = $expr->andX();
581
		$andExternal->add($orExtOrPassive);
582
		$andExternal->add($orInstance);
583
584
		$orExtOrTrusted = $expr->orX();
585
		$orExtOrTrusted->add($andExternal);
586
		$orExtOrTrusted->add(
587
			$expr->eq($aliasRemote . '.type', $this->createNamedParameter(RemoteInstance::TYPE_TRUSTED))
588
		);
589
590
		$andTrusted = $expr->andX();
591
		$andTrusted->add($orExtOrTrusted);
592
		$andTrusted->add($this->exprLimitBitwise('config', Circle::CFG_FEDERATED, $aliasCircle));
593
		$andTrusted->add($expr->emptyString($aliasOwner . '.instance'));
594
		$orX->add($andTrusted);
595
596
		$this->andWhere($orX);
597
	}
598
599
600
	/**
601
	 * @param string $alias
602
	 * @param Member $member
603
	 *
604
	 * @throws RequestBuilderException
605
	 */
606
	public function limitToDirectMembership(string $alias, Member $member): void {
607
		if ($this->getType() !== QueryBuilder::SELECT) {
608
			return;
609
		}
610
611
		$aliasMember = $this->generateAlias($alias, self::MEMBER, $options);
612
		$getData = $this->getBool('getData', $options, false);
613
614
		$expr = $this->expr();
615
		if ($getData) {
616
			$this->generateMemberSelectAlias($aliasMember);
617
		}
618
		$this->leftJoin(
619
			$this->getDefaultSelectAlias(), CoreRequestBuilder::TABLE_MEMBER, $aliasMember,
620
			$expr->eq($aliasMember . '.circle_id', $alias . '.unique_id')
621
		);
622
623
		$this->filterDirectMembership($aliasMember, $member);
624
	}
625
626
627
	/**
628
	 * @param string $aliasMember
629
	 * @param Member $member
630
	 */
631
	public function filterDirectMembership(string $aliasMember, Member $member): void {
632
		if ($this->getType() !== QueryBuilder::SELECT) {
633
			return;
634
		}
635
636
		$expr = $this->expr();
637
		$andX = $expr->andX();
638
639
		if ($member->getUserId() !== '') {
640
			$andX->add(
641
				$expr->eq($aliasMember . '.user_id', $this->createNamedParameter($member->getUserId()))
642
			);
643
		}
644
645
		if ($member->getSingleId() !== '') {
646
			$andX->add(
647
				$expr->eq($aliasMember . '.single_id', $this->createNamedParameter($member->getSingleId()))
648
			);
649
		}
650
651
		if ($member->getUserType() > 0) {
652
			$andX->add(
653
				$expr->eq($aliasMember . '.user_type', $this->createNamedParameter($member->getUserType()))
654
			);
655
		}
656
657
		$andX->add(
658
			$expr->eq($aliasMember . '.instance', $this->createNamedParameter($this->getInstance($member)))
659
		);
660
661
		if ($member->getLevel() > 0) {
662
			$andX->add(
663
				$expr->gte(
664
					$aliasMember . '.level',
665
					$this->createNamedParameter($member->getLevel(), IQueryBuilder::PARAM_INT)
666
				)
667
			);
668
		}
669
670
		$this->andWhere($andX);
671
	}
672
673
674
	/**
675
	 * @param string $alias
676
	 * @param IFederatedUser|null $initiator
677
	 * @param string $field
678
	 * @param string $helpedAlias
0 ignored issues
show
Documentation introduced by
There is no parameter named $helpedAlias. Did you maybe mean $helperAlias?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.

Consider the following example. The parameter $ireland is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $ireland
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was changed, but the annotation was not.

Loading history...
679
	 *
680
	 * @throws RequestBuilderException
681
	 */
682
	public function leftJoinCircle(
683
		string $alias,
684
		?IFederatedUser $initiator = null,
685
		string $field = 'circle_id',
686
		string $helperAlias = ''
687
	): void {
688
		if ($this->getType() !== QueryBuilder::SELECT) {
689
			return;
690
		}
691
692
		$helperAlias = ($helperAlias !== '') ? $helperAlias : $alias;
693
		$aliasCircle = $this->generateAlias($alias, self::CIRCLE, $options);
694
		$getData = $this->getBool('getData', $options, false);
695
		$expr = $this->expr();
696
697
		if ($getData) {
698
			$this->generateCircleSelectAlias($aliasCircle);
699
		}
700
701
		$this->leftJoin(
702
			$helperAlias,
703
			CoreRequestBuilder::TABLE_CIRCLE,
704
			$aliasCircle,
705
			$expr->eq($aliasCircle . '.unique_id', $helperAlias . '.' . $field)
706
		);
707
708
		if (!is_null($initiator)) {
709
			$this->limitToInitiator($aliasCircle, $initiator);
710
		}
711
712
		$this->leftJoinOwner($aliasCircle);
713
	}
714
715
716
	/**
717
	 * @param string $aliasMember
718
	 *
719
	 * @throws RequestBuilderException
720
	 */
721
	public function leftJoinInvitedBy(string $aliasMember): void {
722
		if ($this->getType() !== QueryBuilder::SELECT) {
723
			return;
724
		}
725
726
		try {
727
			$aliasInvitedBy = $this->generateAlias($aliasMember, self::INVITED_BY);
728
		} catch (RequestBuilderException $e) {
729
			return;
730
		}
731
732
		$expr = $this->expr();
733
		$this->generateCircleSelectAlias($aliasInvitedBy)
734
			 ->leftJoin(
735
				 $aliasMember, CoreRequestBuilder::TABLE_CIRCLE, $aliasInvitedBy,
736
				 $expr->eq($aliasMember . '.invited_by', $aliasInvitedBy . '.unique_id')
737
			 );
738
739
		$this->leftJoinOwner($aliasInvitedBy);
740
	}
741
742
743
	/**
744
	 * @param string $aliasMember
745
	 * @param IFederatedUser|null $initiator
746
	 *
747
	 * @throws RequestBuilderException
748
	 */
749
	public function leftJoinBasedOn(
750
		string $aliasMember,
751
		?IFederatedUser $initiator = null
752
	): void {
753
		if ($this->getType() !== QueryBuilder::SELECT) {
754
			return;
755
		}
756
757
		try {
758
			$aliasBasedOn = $this->generateAlias($aliasMember, self::BASED_ON, $options);
759
		} catch (RequestBuilderException $e) {
760
			return;
761
		}
762
763
		$expr = $this->expr();
764
		$this->generateCircleSelectAlias($aliasBasedOn)
765
			 ->leftJoin(
766
				 $aliasMember, CoreRequestBuilder::TABLE_CIRCLE, $aliasBasedOn,
767
				 $expr->eq($aliasBasedOn . '.unique_id', $aliasMember . '.single_id')
768
			 );
769
770
		if (!is_null($initiator)) {
771
			$this->leftJoinInitiator($aliasBasedOn, $initiator);
772
			$this->leftJoinOwner($aliasBasedOn);
773
		}
774
	}
775
776
777
	/**
778
	 * @param string $alias
779
	 * @param string $field
780
	 *
781
	 * @throws RequestBuilderException
782
	 */
783
	public function leftJoinOwner(string $alias, string $field = 'unique_id'): void {
784
		if ($this->getType() !== QueryBuilder::SELECT) {
785
			return;
786
		}
787
788
		try {
789
			$aliasMember = $this->generateAlias($alias, self::OWNER, $options);
790
			$getData = $this->getBool('getData', $options, false);
0 ignored issues
show
Unused Code introduced by
$getData is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
791
		} catch (RequestBuilderException $e) {
792
			return;
793
		}
794
795
		$expr = $this->expr();
796
		$this->generateMemberSelectAlias($aliasMember)
797
			 ->leftJoin(
798
				 $alias, CoreRequestBuilder::TABLE_MEMBER, $aliasMember,
799
				 $expr->andX(
800
					 $expr->eq($aliasMember . '.circle_id', $alias . '.' . $field),
801
					 $expr->eq(
802
						 $aliasMember . '.level',
803
						 $this->createNamedParameter(Member::LEVEL_OWNER, self::PARAM_INT)
804
					 )
805
				 )
806
			 );
807
808
		$this->leftJoinBasedOn($aliasMember);
809
	}
810
811
812
	/**
813
	 * @param string $alias
814
	 * @param string $fieldCircleId
815
	 * @param string $fieldSingleId
816
	 *
817
	 * @throws RequestBuilderException
818
	 */
819
	public function leftJoinMember(
820
		string $alias,
821
		string $fieldCircleId = 'circle_id',
822
		string $fieldSingleId = 'single_id'
823
	): void {
824
		if ($this->getType() !== QueryBuilder::SELECT) {
825
			return;
826
		}
827
828
		try {
829
			$aliasMember = $this->generateAlias($alias, self::MEMBER, $options);
830
			$getData = $this->getBool('getData', $options, false);
0 ignored issues
show
Unused Code introduced by
$getData is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
831
		} catch (RequestBuilderException $e) {
832
			return;
833
		}
834
835
		$expr = $this->expr();
836
		$this->generateMemberSelectAlias($aliasMember)
837
			 ->leftJoin(
838
				 $alias, CoreRequestBuilder::TABLE_MEMBER, $aliasMember,
839
				 $expr->andX(
840
					 $expr->eq($aliasMember . '.circle_id', $alias . '.' . $fieldCircleId),
841
					 $expr->eq($aliasMember . '.single_id', $alias . '.' . $fieldSingleId),
842
					 $expr->gte(
843
						 $aliasMember . '.level',
844
						 $this->createNamedParameter(Member::LEVEL_MEMBER, self::PARAM_INT)
845
					 )
846
				 )
847
			 );
848
849
		$this->leftJoinRemoteInstance($aliasMember);
850
		$this->leftJoinBasedOn($aliasMember);
851
	}
852
853
854
	/**
855
	 * if 'getData' is true, will returns 'inheritanceBy': the Member at the end of a sub-chain of
856
	 * memberships (based on $field for Top Circle's singleId)
857
	 *
858
	 * @param string $alias
859
	 * @param string $field
860
	 * @param string $aliasInheritedBy
861
	 *
862
	 * @throws RequestBuilderException
863
	 */
864
	public function leftJoinInheritedMembers(
865
		string $alias,
866
		string $field = '',
867
		string $aliasInheritedBy = ''
868
	): void {
869
		$expr = $this->expr();
870
871
		$field = ($field === '') ? 'circle_id' : $field;
872
		$aliasMembership = $this->generateAlias($alias, self::MEMBERSHIPS, $options);
873
874
		$this->leftJoin(
875
			$alias, CoreRequestBuilder::TABLE_MEMBERSHIP, $aliasMembership,
876
			$expr->eq($aliasMembership . '.circle_id', $alias . '.' . $field)
877
		);
878
879
//		if (!$this->getBool('getData', $options, false)) {
880
//			return;
881
//		}
882
883
		if ($aliasInheritedBy === '') {
884
			$aliasInheritedBy = $this->generateAlias($alias, self::INHERITED_BY);
885
		}
886
		$this->generateMemberSelectAlias($aliasInheritedBy)
887
			 ->leftJoin(
888
				 $alias, CoreRequestBuilder::TABLE_MEMBER, $aliasInheritedBy,
889
				 $expr->andX(
890
					 $expr->eq($aliasMembership . '.inheritance_last', $aliasInheritedBy . '.circle_id'),
891
					 $expr->eq($aliasMembership . '.single_id', $aliasInheritedBy . '.single_id')
892
				 )
893
			 );
894
895
		$this->leftJoinBasedOn($aliasInheritedBy);
896
	}
897
898
899
	/**
900
	 * @throws RequestBuilderException
901
	 */
902
	public function limitToInheritedMemberships(string $alias, string $singleId, string $field = ''): void {
903
		$expr = $this->expr();
904
		$field = ($field === '') ? 'circle_id' : $field;
905
		$aliasUpstreamMembership = $this->generateAlias($alias, self::UPSTREAM_MEMBERSHIPS, $options);
906
		$this->leftJoin(
907
			$alias, CoreRequestBuilder::TABLE_MEMBERSHIP, $aliasUpstreamMembership,
908
			$expr->eq($aliasUpstreamMembership . '.single_id', $this->createNamedParameter($singleId))
909
		);
910
911
		$orX = $expr->orX(
912
			$expr->eq($aliasUpstreamMembership . '.circle_id', $alias . '.' . $field),
913
			$expr->eq($alias . '.' . $field, $this->createNamedParameter($singleId))
914
		);
915
916
		$this->andWhere($orX);
917
	}
918
919
920
	/**
921
	 * limit the request to Members and Sub Members of a Circle.
922
	 *
923
	 * @param string $alias
924
	 * @param string $singleId
925
	 *
926
	 * @throws RequestBuilderException
927
	 */
928
	public function limitToMembersByInheritance(string $alias, string $singleId): void {
929
		$this->leftJoinMembersByInheritance($alias);
930
931
		$expr = $this->expr();
932
		$aliasMembership = $this->generateAlias($alias, self::MEMBERSHIPS);
933
		$this->andWhere($expr->eq($aliasMembership . '.circle_id', $this->createNamedParameter($singleId)));
934
	}
935
936
937
	/**
938
	 * if 'getData' is true, will returns 'inheritanceFrom': the Circle-As-Member of the Top Circle
939
	 * that explain the membership of a Member (based on $field for singleId) to a specific Circle
940
	 *
941
	 * // TODO: returns the link/path ?
942
	 *
943
	 * @param string $alias
944
	 * @param string $field
945
	 *
946
	 * @throws RequestBuilderException
947
	 */
948
	public function leftJoinMembersByInheritance(string $alias, string $field = ''): void {
949
		$expr = $this->expr();
950
951
		$field = ($field === '') ? 'circle_id' : $field;
952
		$aliasMembership = $this->generateAlias($alias, self::MEMBERSHIPS, $options);
953
954
		$this->leftJoin(
955
			$alias, CoreRequestBuilder::TABLE_MEMBERSHIP, $aliasMembership,
956
//			$expr->andX(
957
			$expr->eq($aliasMembership . '.inheritance_last', $alias . '.' . $field)
958
//				$expr->eq($aliasMembership . '.single_id', $alias . '.single_id')
959
//			)
960
		);
961
962
		if (!$this->getBool('getData', $options, false)) {
963
			return;
964
		}
965
966
		$aliasInheritanceFrom = $this->generateAlias($alias, self::INHERITANCE_FROM);
967
		$this->generateMemberSelectAlias($aliasInheritanceFrom)
968
			 ->leftJoin(
969
				 $aliasMembership, CoreRequestBuilder::TABLE_MEMBER, $aliasInheritanceFrom,
970
				 $expr->andX(
971
					 $expr->eq($aliasMembership . '.circle_id', $aliasInheritanceFrom . '.circle_id'),
972
					 $expr->eq($aliasMembership . '.inheritance_first', $aliasInheritanceFrom . '.single_id')
973
				 )
974
			 );
975
	}
976
977
978
	/**
979
	 * limit the result to the point of view of a FederatedUser
980
	 *
981
	 * @param string $alias
982
	 * @param IFederatedUser $user
983
	 * @param string $field
984
	 * @param string $helperAlias
985
	 *
986
	 * @return ICompositeExpression
987
	 * @throws RequestBuilderException
988
	 */
989
	public function limitToInitiator(
990
		string $alias,
991
		IFederatedUser $user,
992
		string $field = '',
993
		string $helperAlias = ''
994
	): ICompositeExpression {
995
		$this->leftJoinInitiator($alias, $user, $field, $helperAlias);
996
		$where = $this->limitInitiatorVisibility($alias);
997
998
		$aliasInitiator = $this->generateAlias($alias, self::INITIATOR, $options);
999
		if ($this->getBool('getData', $options, false)) {
1000
			$this->leftJoinBasedOn($aliasInitiator);
1001
		}
1002
1003
		return $where;
1004
	}
1005
1006
1007
	/**
1008
	 * Left join members to filter userId as initiator.
1009
	 *
1010
	 * @param string $alias
1011
	 * @param IFederatedUser $initiator
1012
	 * @param string $field
1013
	 * @param string $helperAlias
1014
	 *
1015
	 * @throws RequestBuilderException
1016
	 */
1017
	public function leftJoinInitiator(
1018
		string $alias,
1019
		IFederatedUser $initiator,
1020
		string $field = '',
1021
		string $helperAlias = ''
1022
	): void {
1023
		if ($this->getType() !== QueryBuilder::SELECT) {
1024
			return;
1025
		}
1026
1027
		$expr = $this->expr();
1028
		$field = ($field === '') ? 'unique_id' : $field;
1029
		$helperAlias = ($helperAlias !== '') ? $helperAlias : $alias;
1030
		$aliasMembership = $this->generateAlias($alias, self::MEMBERSHIPS, $options);
1031
1032
		$this->leftJoin(
1033
			$helperAlias,
1034
			CoreRequestBuilder::TABLE_MEMBERSHIP,
1035
			$aliasMembership,
1036
			$expr->andX(
1037
				$this->exprLimit('single_id', $initiator->getSingleId(), $aliasMembership),
1038
				$expr->eq($aliasMembership . '.circle_id', $helperAlias . '.' . $field)
1039
			)
1040
		);
1041
1042
		if (!$this->getBool('getData', $options, false)) {
1043
			return;
1044
		}
1045
1046
		try {
1047
			$aliasInitiator = $this->generateAlias($alias, self::INITIATOR, $options);
1048
			$this->leftJoin(
1049
				$aliasMembership, CoreRequestBuilder::TABLE_MEMBER, $aliasInitiator,
1050
				$expr->andX(
1051
					$expr->eq($aliasMembership . '.inheritance_first', $aliasInitiator . '.single_id'),
1052
					$expr->eq($aliasMembership . '.circle_id', $aliasInitiator . '.circle_id')
1053
				)
1054
			);
1055
1056
			$aliasInheritedBy = $this->generateAlias($aliasInitiator, self::INHERITED_BY);
1057
			$this->leftJoin(
1058
				$aliasInitiator, CoreRequestBuilder::TABLE_MEMBER, $aliasInheritedBy,
1059
				$expr->andX(
1060
					$expr->eq($aliasMembership . '.single_id', $aliasInheritedBy . '.single_id'),
1061
					$expr->eq($aliasMembership . '.inheritance_last', $aliasInheritedBy . '.circle_id')
1062
				)
1063
			);
1064
1065
			$default = [];
1066
			if ($this->getBool('canBeVisitor', $options, false)) {
1067
				$default = [
1068
					'user_id'   => $initiator->getUserId(),
1069
					'single_id' => $initiator->getSingleId(),
1070
					'user_type' => $initiator->getUserType(),
1071
					'instance'  => $initiator->getInstance()
1072
				];
1073
			}
1074
			$this->generateMemberSelectAlias($aliasInitiator, $default);
1075
1076
			$this->generateMemberSelectAlias($aliasInheritedBy);
1077
			$aliasInheritedByMembership = $this->generateAlias($aliasInheritedBy, self::MEMBERSHIPS);
1078
			$this->generateMembershipSelectAlias($aliasMembership, $aliasInheritedByMembership);
1079
		} catch (RequestBuilderException $e) {
1080
			\OC::$server->getLogger()->log(3, '-- ' . $e->getMessage());
1081
		}
1082
	}
1083
1084
1085
	/**
1086
	 * @param string $alias
1087
	 *
1088
	 * @return ICompositeExpression
1089
	 * @throws RequestBuilderException
1090
	 */
1091
	protected function limitInitiatorVisibility(string $alias): ICompositeExpression {
1092
		$aliasMembership = $this->generateAlias($alias, self::MEMBERSHIPS, $options);
1093
		$getPersonalCircle = $this->getBool('getPersonalCircle', $options, false);
1094
1095
		$expr = $this->expr();
1096
1097
		// Visibility to non-member is
1098
		// - 0 (default), if initiator is member
1099
		// - 2 (Personal), if initiator is owner)
1100
		// - 4 (Visible to everyone)
1101
		$orX = $expr->orX();
1102
		$orX->add(
1103
			$expr->andX(
1104
				$expr->gte($aliasMembership . '.level', $this->createNamedParameter(Member::LEVEL_MEMBER))
1105
			)
1106
		);
1107
1108
		if ($getPersonalCircle) {
1109
			$orX->add(
1110
				$expr->andX(
1111
					$this->exprLimitBitwise('config', Circle::CFG_PERSONAL, $alias),
1112
					$expr->eq($aliasMembership . '.level', $this->createNamedParameter(Member::LEVEL_OWNER))
1113
				)
1114
			);
1115
		}
1116
		if (!$this->getBool('mustBeMember', $options, true)) {
1117
			$orX->add($this->exprLimitBitwise('config', Circle::CFG_VISIBLE, $alias));
1118
		}
1119
		if ($this->getBool('canBeVisitor', $options, false)) {
1120
			// TODO: should find a better way, also filter on remote initiator on non-federated ?
1121
			$orX->add($expr->gte($alias . '.config', $this->createNamedParameter(0)));
1122
		}
1123
		if ($this->getBool('canBeVisitorOnOpen', $options, false)) {
1124
			$andOpen = $expr->andX();
1125
			$andOpen->add($this->exprLimitBitwise('config', Circle::CFG_OPEN, $alias));
1126
			$andOpen->add($this->exprFilterBitwise('config', Circle::CFG_REQUEST, $alias));
1127
			$orX->add($andOpen);
1128
		}
1129
1130
		$this->andWhere($orX);
1131
1132
		return $orX;
1133
//		$orTypes = $this->generateLimit($qb, $circleUniqueId, $userId, $type, $name, $forceAll);
1134
//		if (sizeof($orTypes) === 0) {
1135
//			throw new ConfigNoCircleAvailableException(
1136
//				$this->l10n->t(
1137
//					'You cannot use the Circles Application until your administrator has allowed at least one type of circles'
1138
//				)
1139
//			);
1140
//		}
1141
1142
//		$orXTypes = $this->expr()
1143
//						 ->orX();
1144
//		foreach ($orTypes as $orType) {
1145
//			$orXTypes->add($orType);
1146
//		}
1147
//
1148
//		$qb->andWhere($orXTypes);
1149
	}
1150
1151
1152
	/**
1153
	 * CFG_SINGLE, CFG_HIDDEN and CFG_BACKEND means hidden from listing.
1154
	 *
1155
	 * @param string $aliasCircle
1156
	 * @param int $flag
1157
	 */
1158
	public function filterCircles(
1159
		string $aliasCircle,
1160
		int $flag = Circle::CFG_SINGLE | Circle::CFG_HIDDEN | Circle::CFG_BACKEND
1161
	): void {
1162
		if ($flag === 0) {
1163
			return;
1164
		}
1165
1166
		$expr = $this->expr();
1167
		$hide = $expr->andX();
1168
		foreach (Circle::$DEF_CFG as $cfg => $v) {
1169
			if ($flag & $cfg) {
1170
				$hide->add($this->exprFilterBitwise('config', $cfg, $aliasCircle));
1171
			}
1172
		}
1173
1174
		$this->andWhere($hide);
1175
	}
1176
1177
1178
	/**
1179
	 * Limit visibility on Sensitive information when search for members.
1180
	 *
1181
	 * @param string $alias
1182
	 *
1183
	 * @return ICompositeExpression
1184
	 */
1185
	private function limitRemoteVisibility_Sensitive_Members(string $alias): ICompositeExpression {
1186
		$expr = $this->expr();
1187
		$andPassive = $expr->andX();
1188
		$andPassive->add(
1189
			$expr->eq($alias . '.type', $this->createNamedParameter(RemoteInstance::TYPE_PASSIVE))
1190
		);
1191
1192
		$orMemberOrLevel = $expr->orX();
1193
		$orMemberOrLevel->add(
1194
			$expr->eq($this->getDefaultSelectAlias() . '.instance', $alias . '.instance')
1195
		);
1196
		// TODO: do we need this ? (display members from the local instance)
1197
		$orMemberOrLevel->add(
1198
			$expr->emptyString($this->getDefaultSelectAlias() . '.instance')
1199
		);
1200
1201
		$orMemberOrLevel->add(
1202
			$expr->eq(
1203
				$this->getDefaultSelectAlias() . '.level',
1204
				$this->createNamedParameter(Member::LEVEL_OWNER)
1205
			)
1206
		);
1207
		$andPassive->add($orMemberOrLevel);
1208
1209
		return $andPassive;
1210
	}
1211
1212
1213
	/**
1214
	 * Link to storage/filecache
1215
	 *
1216
	 * @param string $aliasShare
1217
	 *
1218
	 * @throws RequestBuilderException
1219
	 */
1220
	public function leftJoinFileCache(string $aliasShare) {
1221
		$expr = $this->expr();
1222
1223
		$aliasFileCache = $this->generateAlias($aliasShare, self::FILE_CACHE);
1224
		$aliasStorages = $this->generateAlias($aliasFileCache, self::STORAGES);
1225
1226
		$this->generateSelectAlias(
1227
			CoreRequestBuilder::$outsideTables[CoreRequestBuilder::TABLE_FILE_CACHE],
0 ignored issues
show
Bug introduced by
The property outsideTables cannot be accessed from this context as it is declared private in class OCA\Circles\Db\CoreRequestBuilder.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
1228
			$aliasFileCache,
1229
			$aliasFileCache,
1230
			[]
1231
		)
1232
			 ->generateSelectAlias(
1233
				 CoreRequestBuilder::$outsideTables[CoreRequestBuilder::TABLE_STORAGES],
0 ignored issues
show
Bug introduced by
The property outsideTables cannot be accessed from this context as it is declared private in class OCA\Circles\Db\CoreRequestBuilder.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
1234
				 $aliasStorages,
1235
				 $aliasStorages,
1236
				 []
1237
			 )
1238
			 ->leftJoin(
1239
				 $aliasShare, CoreRequestBuilder::TABLE_FILE_CACHE, $aliasFileCache,
1240
				 $expr->eq($aliasShare . '.file_source', $aliasFileCache . '.fileid')
1241
			 )
1242
			 ->leftJoin(
1243
				 $aliasFileCache, CoreRequestBuilder::TABLE_STORAGES, $aliasStorages,
1244
				 $expr->eq($aliasFileCache . '.storage', $aliasStorages . '.numeric_id')
1245
			 );
1246
	}
1247
1248
1249
	/**
1250
	 * @param string $aliasShare
1251
	 * @param string $aliasShareMemberships
1252
	 *
1253
	 * @throws RequestBuilderException
1254
	 */
1255
	public function leftJoinShareChild(string $aliasShare, string $aliasShareMemberships = '') {
1256
		$expr = $this->expr();
1257
1258
		$aliasShareChild = $this->generateAlias($aliasShare, self::SHARE);
1259
		if ($aliasShareMemberships === '') {
1260
			$aliasShareMemberships = $this->generateAlias($aliasShare, self::MEMBERSHIPS, $options);
1261
		}
1262
1263
		$this->leftJoin(
1264
			$aliasShareMemberships, CoreRequestBuilder::TABLE_SHARE, $aliasShareChild,
1265
			$expr->andX(
1266
				$expr->eq($aliasShareChild . '.parent', $aliasShare . '.id'),
1267
				$expr->eq($aliasShareChild . '.share_with', $aliasShareMemberships . '.single_id')
1268
			)
1269
		);
1270
1271
		$this->generateSelectAlias(
1272
			['id', 'file_target', 'permissions'],
1273
			$aliasShareChild,
1274
			'child_',
1275
			[]
1276
		);
1277
1278
//		$this->selectAlias($aliasShareParent . '.permissions', 'parent_perms');
1279
	}
1280
1281
1282
	/**
1283
	 * @param string $alias
1284
	 * @param FederatedUser $federatedUser
1285
	 * @param bool $reshares
1286
	 */
1287
	public function limitToShareOwner(string $alias, FederatedUser $federatedUser, bool $reshares): void {
1288
		$expr = $this->expr();
1289
1290
		$orX = $expr->orX($this->exprLimit('uid_initiator', $federatedUser->getUserId(), $alias));
1291
1292
		if ($reshares) {
1293
			$orX->add($this->exprLimit('uid_owner', $federatedUser->getUserId(), $alias));
1294
		}
1295
1296
		$this->andWhere($orX);
1297
	}
1298
1299
1300
	/**
1301
	 * @param string $aliasMount
1302
	 * @param string $aliasMountMemberships
1303
	 *
1304
	 * @throws RequestBuilderException
1305
	 */
1306
	public function leftJoinMountpoint(string $aliasMount, string $aliasMountMemberships = '') {
1307
		$expr = $this->expr();
1308
1309
		$aliasMountpoint = $this->generateAlias($aliasMount, self::MOUNTPOINT);
1310
		if ($aliasMountMemberships === '') {
1311
			$aliasMountMemberships = $this->generateAlias($aliasMount, self::MEMBERSHIPS, $options);
1312
		}
1313
1314
		$this->leftJoin(
1315
			$aliasMountMemberships, CoreRequestBuilder::TABLE_MOUNTPOINT, $aliasMountpoint,
1316
			$expr->andX(
1317
				$expr->eq($aliasMountpoint . '.mount_id', $aliasMount . '.mount_id'),
1318
				$expr->eq($aliasMountpoint . '.single_id', $aliasMountMemberships . '.single_id')
1319
			)
1320
		);
1321
1322
		$this->selectAlias($aliasMountpoint . '.mountpoint', $aliasMountpoint . '_mountpoint');
1323
		$this->selectAlias($aliasMountpoint . '.mountpoint_hash', $aliasMountpoint . '_mountpoint_hash');
1324
	}
1325
1326
1327
	/**
1328
	 * @param string $alias
1329
	 * @param array $default
1330
	 *
1331
	 * @return CoreQueryBuilder
1332
	 */
1333
	private function generateCircleSelectAlias(string $alias, array $default = []): self {
1334
		$this->generateSelectAlias(
1335
			CoreRequestBuilder::$tables[CoreRequestBuilder::TABLE_CIRCLE],
0 ignored issues
show
Bug introduced by
The property tables cannot be accessed from this context as it is declared private in class OCA\Circles\Db\CoreRequestBuilder.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
1336
			$alias,
1337
			$alias,
1338
			$default
1339
		);
1340
1341
		return $this;
1342
	}
1343
1344
	/**
1345
	 * @param string $alias
1346
	 * @param array $default
1347
	 *
1348
	 * @return $this
1349
	 */
1350
	private function generateMemberSelectAlias(string $alias, array $default = []): self {
1351
		$this->generateSelectAlias(
1352
			CoreRequestBuilder::$tables[CoreRequestBuilder::TABLE_MEMBER],
0 ignored issues
show
Bug introduced by
The property tables cannot be accessed from this context as it is declared private in class OCA\Circles\Db\CoreRequestBuilder.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
1353
			$alias,
1354
			$alias,
1355
			$default
1356
		);
1357
1358
		return $this;
1359
	}
1360
1361
1362
	/**
1363
	 * @param string $alias
1364
	 * @param array $default
1365
	 * @param string $prefix
1366
	 *
1367
	 * @return $this
1368
	 */
1369
	private function generateMembershipSelectAlias(
1370
		string $alias,
1371
		string $prefix = '',
1372
		array $default = []
1373
	): self {
1374
		$this->generateSelectAlias(
1375
			CoreRequestBuilder::$tables[CoreRequestBuilder::TABLE_MEMBERSHIP],
0 ignored issues
show
Bug introduced by
The property tables cannot be accessed from this context as it is declared private in class OCA\Circles\Db\CoreRequestBuilder.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
1376
			$alias,
1377
			($prefix === '') ? $alias : $prefix,
1378
			$default
1379
		);
1380
1381
		return $this;
1382
	}
1383
1384
1385
	/**
1386
	 * @param string $alias
1387
	 * @param array $default
1388
	 *
1389
	 * @return $this
1390
	 */
1391
	private function generateRemoteInstanceSelectAlias(string $alias, array $default = []): self {
1392
		$this->generateSelectAlias(
1393
			CoreRequestBuilder::$tables[CoreRequestBuilder::TABLE_REMOTE],
0 ignored issues
show
Bug introduced by
The property tables cannot be accessed from this context as it is declared private in class OCA\Circles\Db\CoreRequestBuilder.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
1394
			$alias,
1395
			$alias,
1396
			$default
1397
		);
1398
1399
		return $this;
1400
	}
1401
1402
1403
	/**
1404
	 * @param array $path
1405
	 * @param array $options
1406
	 */
1407
	public function setOptions(array $path, array $options): void {
1408
		$options = [self::OPTIONS => $options];
1409
		foreach (array_reverse($path) as $item) {
1410
			$options = [$item => $options];
1411
		}
1412
1413
		$this->options = $options;
1414
	}
1415
1416
1417
	/**
1418
	 * @param string $base
1419
	 * @param string $extension
1420
	 * @param array|null $options
1421
	 *
1422
	 * @return string
1423
	 * @throws RequestBuilderException
1424
	 */
1425
	public function generateAlias(string $base, string $extension, ?array &$options = []): string {
1426
		$search = str_replace('_', '.', $base);
1427
		$path = $search . '.' . $extension;
1428
		if (!$this->validKey($path, self::$SQL_PATH)
1429
			&& !in_array($extension, $this->getArray($search, self::$SQL_PATH))) {
1430
			throw new RequestBuilderException($extension . ' not found in ' . $search);
1431
		}
1432
1433
		if (!is_array($options)) {
1434
			$options = [];
1435
		}
1436
1437
		$optionPath = '';
1438
		foreach (explode('.', $path) as $p) {
1439
			$optionPath = trim($optionPath . '.' . $p, '.');
1440
			$options = array_merge(
1441
				$options,
1442
				$this->getArray($optionPath . '.' . self::OPTIONS, self::$SQL_PATH),
1443
				$this->getArray($optionPath . '.' . self::OPTIONS, $this->options)
1444
			);
1445
		}
1446
1447
		return $base . '_' . $extension;
1448
	}
1449
1450
1451
	/**
1452
	 * @param string $prefix
1453
	 *
1454
	 * @return array
1455
	 */
1456
	public function getAvailablePath(string $prefix): array {
1457
		$prefix = trim($prefix, '_');
1458
		$search = str_replace('_', '.', $prefix);
1459
1460
		$path = [];
1461
		foreach ($this->getArray($search, self::$SQL_PATH) as $arr => $item) {
1462
			if (is_numeric($arr)) {
1463
				$k = $item;
1464
			} else {
1465
				$k = $arr;
1466
			}
1467
			$path[$k] = $prefix . '_' . $k . '_';
1468
		}
1469
1470
		return $path;
1471
	}
1472
1473
}
1474
1475