Completed
Pull Request — master (#609)
by Maxence
02:33
created

CoreQueryBuilder::limitToInstance()   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
49
50
/**
51
 * Class CoreQueryBuilder
52
 *
53
 * @package OCA\Circles\Db
54
 */
55
class CoreQueryBuilder extends NC22ExtendedQueryBuilder {
56
57
58
	use TArrayTools;
59
60
61
	const SINGLE = 'single';
62
	const CIRCLE = 'circle';
63
	const MEMBER = 'member';
64
	const OWNER = 'owner';
65
	const FEDERATED_EVENT = 'federatedevent';
66
	const REMOTE = 'remote';
67
	const BASED_ON = 'basedon';
68
	const INITIATOR = 'initiator';
69
	const MEMBERSHIPS = 'memberships';
70
	const UPSTREAM_MEMBERSHIPS = 'upstreammemberships';
71
	const INHERITANCE_FROM = 'inheritancefrom';
72
	const INHERITED_BY = 'inheritedby';
73
	const INVITED_BY = 'invitedby';
74
	const MOUNT = 'mount';
75
	const MOUNTPOINT = 'mountpoint';
76
	const SHARE = 'share';
77
	const FILE_CACHE = 'filecache';
78
	const STORAGES = 'storages';
79
	const OPTIONS = 'options';
80
	const HELPER = 'circleshelper';
81
82
83
	public static $SQL_PATH = [
84
		self::SINGLE => [
85
			self::MEMBER
86
		],
87
		self::CIRCLE => [
88
			self::OPTIONS   => [
89
				'getPersonalCircle' => true
90
			],
91
			self::MEMBER,
92
			self::OWNER     => [
93
				self::BASED_ON
94
			],
95
			self::MEMBERSHIPS,
96
			self::INITIATOR => [
97
				self::BASED_ON,
98
				self::INHERITED_BY => [
99
					self::MEMBERSHIPS
100
				]
101
			],
102
			self::REMOTE    => [
103
				self::MEMBER,
104
				self::CIRCLE => [
105
					self::OWNER
106
				]
107
			]
108
		],
109
		self::MEMBER => [
110
			self::MEMBERSHIPS,
111
			self::INHERITANCE_FROM,
112
			self::CIRCLE     => [
113
				self::OPTIONS   => [
114
					'getData' => true
115
				],
116
				self::OWNER,
117
				self::MEMBERSHIPS,
118
				self::INITIATOR => [
119
					self::OPTIONS      => [
120
						'mustBeMember' => true,
121
						'canBeVisitor' => false
122
					],
123
					self::BASED_ON,
124
					self::INHERITED_BY => [
125
						self::MEMBERSHIPS
126
					],
127
					self::INVITED_BY => [
128
						self::OWNER,
129
						self::BASED_ON
130
					]
131
				]
132
			],
133
			self::BASED_ON   => [
134
				self::OWNER,
135
				self::MEMBERSHIPS,
136
				self::INITIATOR => [
137
					self::BASED_ON,
138
					self::INHERITED_BY => [
139
						self::MEMBERSHIPS
140
					]
141
				]
142
			],
143
			self::REMOTE     => [
144
				self::MEMBER,
145
				self::CIRCLE => [
146
					self::OWNER
147
				]
148
			],
149
			self::INVITED_BY => [
150
				self::OWNER,
151
				self::BASED_ON
152
			]
153
		],
154
		self::SHARE  => [
155
			self::SHARE,
156
			self::FILE_CACHE           => [
157
				self::STORAGES
158
			],
159
			self::UPSTREAM_MEMBERSHIPS => [
160
				self::MEMBERSHIPS,
161
				self::INHERITED_BY => [
162
					self::BASED_ON
163
				],
164
				self::SHARE,
165
			],
166
			self::MEMBERSHIPS,
167
			self::INHERITANCE_FROM,
168
			self::INHERITED_BY         => [
169
				self::BASED_ON
170
			],
171
			self::CIRCLE               => [
172
				self::OWNER
173
			],
174
			self::INITIATOR            => [
175
				self::BASED_ON,
176
				self::INHERITED_BY => [
177
					self::MEMBERSHIPS
178
				]
179
			]
180
		],
181
		self::REMOTE => [
182
			self::MEMBER
183
		],
184
		self::MOUNT  => [
185
			self::MEMBER    => [
186
				self::REMOTE
187
			],
188
			self::INITIATOR => [
189
				self::INHERITED_BY => [
190
					self::MEMBERSHIPS
191
				]
192
			],
193
			self::MOUNTPOINT,
194
			self::MEMBERSHIPS
195
		],
196
		self::HELPER => [
197
			self::MEMBERSHIPS,
198
			self::INITIATOR => [
199
				self::INHERITED_BY => [
200
					self::MEMBERSHIPS
201
				]
202
			],
203
			self::CIRCLE    => [
204
				self::OPTIONS => [
205
					'getPersonalCircle' => true
206
				],
207
				self::MEMBER,
208
				self::OWNER   => [
209
					self::BASED_ON
210
				]
211
			]
212
		]
213
	];
214
215
216
	/** @var ConfigService */
217
	private $configService;
218
219
220
	/** @var array */
221
	private $options = [];
222
223
224
	/**
225
	 * CoreQueryBuilder constructor.
226
	 */
227
	public function __construct() {
228
		parent::__construct();
229
230
		$this->configService = OC::$server->get(ConfigService::class);
231
	}
232
233
234
	/**
235
	 * @param IFederatedModel $federatedModel
236
	 *
237
	 * @return string
238
	 */
239
	public function getInstance(IFederatedModel $federatedModel): string {
240
		$instance = $federatedModel->getInstance();
241
242
		return ($this->configService->isLocalInstance($instance)) ? '' : $instance;
243
	}
244
245
246
	/**
247
	 * @param string $id
248
	 */
249
	public function limitToCircleId(string $id): void {
250
		$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...
251
	}
252
253
	/**
254
	 * @param string $name
255
	 */
256
	public function limitToName(string $name): void {
257
		$this->limitToDBField('name', $name);
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...
258
	}
259
260
	/**
261
	 * @param int $config
262
	 */
263
	public function limitToConfig(int $config): void {
264
		$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...
265
	}
266
267
	/**
268
	 * @param int $source
269
	 */
270
	public function limitToSource(int $source): void {
271
		$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...
272
	}
273
274
	/**
275
	 * @param int $config
276
	 */
277
	public function limitToConfigFlag(int $config): void {
278
		$this->andWhere($this->expr()->bitwiseAnd($this->getDefaultSelectAlias() . '.config', $config));
279
	}
280
281
282
	/**
283
	 * @param string $singleId
284
	 */
285
	public function limitToSingleId(string $singleId): void {
286
		$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...
287
	}
288
289
290
	/**
291
	 * @param string $itemId
292
	 */
293
	public function limitToItemId(string $itemId): void {
294
		$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...
295
	}
296
297
298
	/**
299
	 * @param string $host
300
	 */
301
	public function limitToInstance(string $host): void {
302
		$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...
303
	}
304
305
306
	/**
307
	 * @param int $userType
308
	 */
309
	public function limitToUserType(int $userType): void {
310
		$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...
311
	}
312
313
314
	/**
315
	 * @param int $shareType
316
	 */
317
	public function limitToShareType(int $shareType): void {
318
		$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...
319
	}
320
321
322
	/**
323
	 * @param string $shareWith
324
	 */
325
	public function limitToShareWith(string $shareWith): void {
326
		$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...
327
	}
328
329
330
	/**
331
	 * @param int $nodeId
332
	 */
333
	public function limitToFileSource(int $nodeId): void {
334
		$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...
335
	}
336
337
	/**
338
	 * @param array $files
339
	 */
340
	public function limitToFileSourceArray(array $files): void {
341
		$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...
342
	}
343
344
345
	/**
346
	 * @param int $shareId
347
	 */
348
	public function limitToShareParent(int $shareId): void {
349
		$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...
350
	}
351
352
353
	/**
354
	 * @param Circle $circle
355
	 */
356
	public function filterCircle(Circle $circle): void {
357
		if ($this->getType() !== QueryBuilder::SELECT) {
358
			return;
359
		}
360
361
		if ($circle->getDisplayName() !== '') {
362
			$this->searchInDBField('display_name', '%' . $circle->getDisplayName() . '%');
363
		}
364
	}
365
366
367
	/**
368
	 * left join RemoteInstance based on a Member
369
	 */
370
	public function leftJoinRemoteInstance(string $alias): void {
371
		$expr = $this->expr();
372
373
		try {
374
			$aliasRemoteInstance = $this->generateAlias($alias, self::REMOTE);
375
			$this->generateRemoteInstanceSelectAlias($aliasRemoteInstance)
376
				 ->leftJoin(
377
					 $alias, CoreRequestBuilder::TABLE_REMOTE, $aliasRemoteInstance,
378
					 $expr->eq($alias . '.instance', $aliasRemoteInstance . '.instance')
379
				 );
380
		} catch (RequestBuilderException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
381
		}
382
	}
383
384
385
	/**
386
	 * @param string $alias
387
	 * @param RemoteInstance $remoteInstance
388
	 * @param bool $filterSensitiveData
389
	 * @param string $aliasCircle
390
	 *
391
	 * @throws RequestBuilderException
392
	 */
393
	public function limitToRemoteInstance(
394
		string $alias,
395
		RemoteInstance $remoteInstance,
396
		bool $filterSensitiveData = true,
397
		string $aliasCircle = ''
398
	): void {
399
400
		if ($aliasCircle === '') {
401
			$aliasCircle = $alias;
402
		}
403
404
		$this->leftJoinRemoteInstanceIncomingRequest($alias, $remoteInstance);
405
		$this->leftJoinMemberFromInstance($alias, $remoteInstance, $aliasCircle);
406
		$this->leftJoinMemberFromRemoteCircle($alias, $remoteInstance, $aliasCircle);
407
		$this->limitRemoteVisibility($alias, $filterSensitiveData, $aliasCircle);
408
	}
409
410
411
	/**
412
	 * Left join RemoteInstance based on an incoming request
413
	 *
414
	 * @param string $alias
415
	 * @param RemoteInstance $remoteInstance
416
	 *
417
	 * @throws RequestBuilderException
418
	 */
419
	public function leftJoinRemoteInstanceIncomingRequest(
420
		string $alias,
421
		RemoteInstance $remoteInstance
422
	): void {
423
		if ($this->getType() !== QueryBuilder::SELECT) {
424
			return;
425
		}
426
427
		$aliasRemote = $this->generateAlias($alias, self::REMOTE);
428
		$expr = $this->expr();
429
		$this->leftJoin(
430
			$this->getDefaultSelectAlias(), CoreRequestBuilder::TABLE_REMOTE, $aliasRemote,
431
			$expr->eq($aliasRemote . '.instance', $this->createNamedParameter($remoteInstance->getInstance()))
432
		);
433
	}
434
435
436
	/**
437
	 * left join members to check memberships of someone from instance
438
	 *
439
	 * @param string $alias
440
	 * @param RemoteInstance $remoteInstance
441
	 * @param string $aliasCircle
442
	 *
443
	 * @throws RequestBuilderException
444
	 */
445
	private function leftJoinMemberFromInstance(
446
		string $alias, RemoteInstance $remoteInstance, string $aliasCircle
447
	) {
448
		if ($this->getType() !== QueryBuilder::SELECT) {
449
			return;
450
		}
451
452
		$aliasRemote = $this->generateAlias($alias, self::REMOTE);
453
		$aliasRemoteMember = $this->generateAlias($aliasRemote, self::MEMBER);
454
455
		$expr = $this->expr();
456
		$this->leftJoin(
457
			$this->getDefaultSelectAlias(), CoreRequestBuilder::TABLE_MEMBER, $aliasRemoteMember,
458
			$expr->andX(
459
				$expr->eq($aliasRemoteMember . '.circle_id', $aliasCircle . '.unique_id'),
460
				$expr->eq(
461
					$aliasRemoteMember . '.instance',
462
					$this->createNamedParameter($remoteInstance->getInstance())
463
				),
464
				$expr->gte($aliasRemoteMember . '.level', $this->createNamedParameter(Member::LEVEL_MEMBER))
465
			)
466
		);
467
	}
468
469
470
	/**
471
	 * left join circle is member of a circle from remote instance
472
	 *
473
	 * @param string $alias
474
	 * @param RemoteInstance $remoteInstance
475
	 * @param string $aliasCircle
476
	 *
477
	 * @throws RequestBuilderException
478
	 */
479
	private function leftJoinMemberFromRemoteCircle(
480
		string $alias,
481
		RemoteInstance $remoteInstance,
482
		string $aliasCircle
483
	) {
484
		if ($this->getType() !== QueryBuilder::SELECT) {
485
			return;
486
		}
487
488
		$aliasRemote = $this->generateAlias($alias, self::REMOTE);
489
		$aliasRemoteCircle = $this->generateAlias($aliasRemote, self::CIRCLE);
490
		$aliasRemoteCircleOwner = $this->generateAlias($aliasRemoteCircle, self::OWNER);
491
492
		$expr = $this->expr();
493
		$this->leftJoin(
494
			$this->getDefaultSelectAlias(), CoreRequestBuilder::TABLE_MEMBER, $aliasRemoteCircle,
495
			$expr->andX(
496
				$expr->eq($aliasRemoteCircle . '.single_id', $aliasCircle . '.unique_id'),
497
				$expr->emptyString($aliasRemoteCircle . '.instance'),
498
				$expr->gte($aliasRemoteCircle . '.level', $this->createNamedParameter(Member::LEVEL_MEMBER))
499
			)
500
		);
501
		$this->leftJoin(
502
			$this->getDefaultSelectAlias(), CoreRequestBuilder::TABLE_MEMBER, $aliasRemoteCircleOwner,
503
			$expr->andX(
504
				$expr->eq($aliasRemoteCircle . '.circle_id', $aliasRemoteCircleOwner . '.circle_id'),
505
				$expr->eq(
506
					$aliasRemoteCircleOwner . '.instance',
507
					$this->createNamedParameter($remoteInstance->getInstance())
508
				),
509
				$expr->eq(
510
					$aliasRemoteCircleOwner . '.level', $this->createNamedParameter(Member::LEVEL_OWNER)
511
				)
512
			)
513
		);
514
	}
515
516
517
	/**
518
	 * - global_scale: visibility on all Circles
519
	 * - trusted: visibility on all FEDERATED Circle if owner is local
520
	 * - external: visibility on all FEDERATED Circle if owner is local and:
521
	 *    - with if Circle contains at least one member from the remote instance
522
	 *    - one circle from the remote instance contains the local circle as member, and confirmed (using
523
	 *      sync locally)
524
	 * - passive: like external, but the members list will only contains member from the local instance and
525
	 * from the remote instance.
526
	 *
527
	 * @param string $alias
528
	 * @param bool $sensitive
529
	 * @param string $aliasCircle
530
	 *
531
	 * @throws RequestBuilderException
532
	 */
533
	protected function limitRemoteVisibility(string $alias, bool $sensitive, string $aliasCircle) {
534
		$aliasRemote = $this->generateAlias($alias, self::REMOTE);
535
		$aliasOwner = $this->generateAlias($aliasCircle, self::OWNER);
536
		$aliasRemoteMember = $this->generateAlias($aliasRemote, self::MEMBER);
537
		$aliasRemoteCircle = $this->generateAlias($aliasRemote, self::CIRCLE);
538
		$aliasRemoteCircleOwner = $this->generateAlias($aliasRemoteCircle, self::OWNER);
539
540
		$expr = $this->expr();
541
		$orX = $expr->orX();
542
		$orX->add(
543
			$expr->eq($aliasRemote . '.type', $this->createNamedParameter(RemoteInstance::TYPE_GLOBALSCALE))
544
		);
545
546
		$orExtOrPassive = $expr->orX();
547
		$orExtOrPassive->add(
548
			$expr->eq($aliasRemote . '.type', $this->createNamedParameter(RemoteInstance::TYPE_EXTERNAL))
549
		);
550
		if (!$sensitive) {
551
			$orExtOrPassive->add(
552
				$expr->eq($aliasRemote . '.type', $this->createNamedParameter(RemoteInstance::TYPE_PASSIVE))
553
			);
554
		} else {
555
			if ($this->getDefaultSelectAlias() === CoreQueryBuilder::MEMBER) {
556
				$orExtOrPassive->add($this->limitRemoteVisibility_Sensitive_Members($aliasRemote));
557
			}
558
		}
559
560
		$orInstance = $expr->orX();
561
		$orInstance->add($expr->isNotNull($aliasRemoteMember . '.instance'));
562
		$orInstance->add($expr->isNotNull($aliasRemoteCircleOwner . '.instance'));
563
564
		$andExternal = $expr->andX();
565
		$andExternal->add($orExtOrPassive);
566
		$andExternal->add($orInstance);
567
568
		$orExtOrTrusted = $expr->orX();
569
		$orExtOrTrusted->add($andExternal);
570
		$orExtOrTrusted->add(
571
			$expr->eq($aliasRemote . '.type', $this->createNamedParameter(RemoteInstance::TYPE_TRUSTED))
572
		);
573
574
		$andTrusted = $expr->andX();
575
		$andTrusted->add($orExtOrTrusted);
576
		$andTrusted->add($expr->bitwiseAnd($aliasCircle . '.config', Circle::CFG_FEDERATED));
577
		$andTrusted->add($expr->emptyString($aliasOwner . '.instance'));
578
		$orX->add($andTrusted);
579
580
		$this->andWhere($orX);
581
	}
582
583
584
	/**
585
	 * @param string $alias
586
	 * @param Member $member
587
	 *
588
	 * @throws RequestBuilderException
589
	 */
590
	public function limitToDirectMembership(string $alias, Member $member): void {
591
		if ($this->getType() !== QueryBuilder::SELECT) {
592
			return;
593
		}
594
595
		$aliasMember = $this->generateAlias($alias, self::MEMBER, $options);
596
		$getData = $this->getBool('getData', $options, false);
597
598
		$expr = $this->expr();
599
		if ($getData) {
600
			$this->generateMemberSelectAlias($aliasMember);
601
		}
602
		$this->leftJoin(
603
			$this->getDefaultSelectAlias(), CoreRequestBuilder::TABLE_MEMBER, $aliasMember,
604
			$expr->eq($aliasMember . '.circle_id', $alias . '.unique_id')
605
		);
606
607
		$this->filterDirectMembership($aliasMember, $member);
608
	}
609
610
611
	/**
612
	 * @param string $aliasMember
613
	 * @param Member $member
614
	 */
615
	public function filterDirectMembership(string $aliasMember, Member $member): void {
616
		if ($this->getType() !== QueryBuilder::SELECT) {
617
			return;
618
		}
619
620
		$expr = $this->expr();
621
		$andX = $expr->andX();
622
623
		if ($member->getUserId() !== '') {
624
			$andX->add(
625
				$expr->eq($aliasMember . '.user_id', $this->createNamedParameter($member->getUserId()))
626
			);
627
		}
628
629
		if ($member->getSingleId() !== '') {
630
			$andX->add(
631
				$expr->eq($aliasMember . '.single_id', $this->createNamedParameter($member->getSingleId()))
632
			);
633
		}
634
635
		if ($member->getUserType() > 0) {
636
			$andX->add(
637
				$expr->eq($aliasMember . '.user_type', $this->createNamedParameter($member->getUserType()))
638
			);
639
		}
640
641
		$andX->add(
642
			$expr->eq($aliasMember . '.instance', $this->createNamedParameter($this->getInstance($member)))
643
		);
644
645
		if ($member->getLevel() > 0) {
646
			$andX->add($expr->gte($aliasMember . '.level', $this->createNamedParameter($member->getLevel())));
647
		}
648
649
		$this->andWhere($andX);
650
	}
651
652
653
	/**
654
	 * @param string $alias
655
	 * @param IFederatedUser|null $initiator
656
	 * @param string $field
657
	 * @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...
658
	 *
659
	 * @throws RequestBuilderException
660
	 */
661
	public function leftJoinCircle(
662
		string $alias,
663
		?IFederatedUser $initiator = null,
664
		string $field = 'circle_id',
665
		string $helperAlias = ''
666
	): void {
667
		if ($this->getType() !== QueryBuilder::SELECT) {
668
			return;
669
		}
670
671
		$helperAlias = ($helperAlias !== '') ? $helperAlias : $alias;
672
		$aliasCircle = $this->generateAlias($alias, self::CIRCLE, $options);
673
		$getData = $this->getBool('getData', $options, false);
674
		$expr = $this->expr();
675
676
		if ($getData) {
677
			$this->generateCircleSelectAlias($aliasCircle);
678
		}
679
680
		$this->leftJoin(
681
			$helperAlias,
682
			CoreRequestBuilder::TABLE_CIRCLE,
683
			$aliasCircle,
684
			$expr->eq($aliasCircle . '.unique_id', $helperAlias . '.' . $field)
685
		);
686
687
		if (!is_null($initiator)) {
688
			$this->limitToInitiator($aliasCircle, $initiator);
689
		}
690
691
		$this->leftJoinOwner($aliasCircle);
692
	}
693
694
695
	/**
696
	 * @param string $aliasMember
697
	 *
698
	 * @throws RequestBuilderException
699
	 */
700
	public function leftJoinInvitedBy(string $aliasMember): void {
701
		if ($this->getType() !== QueryBuilder::SELECT) {
702
			return;
703
		}
704
705
		try {
706
			$aliasInvitedBy = $this->generateAlias($aliasMember, self::INVITED_BY);
707
		} catch (RequestBuilderException $e) {
708
			return;
709
		}
710
711
		$expr = $this->expr();
712
		$this->generateCircleSelectAlias($aliasInvitedBy)
713
			 ->leftJoin(
714
				 $aliasMember, CoreRequestBuilder::TABLE_CIRCLE, $aliasInvitedBy,
715
				 $expr->eq($aliasMember . '.invited_by', $aliasInvitedBy . '.unique_id')
716
			 );
717
718
		$this->leftJoinOwner($aliasInvitedBy);
719
	}
720
721
722
	/**
723
	 * @param string $aliasMember
724
	 * @param IFederatedUser|null $initiator
725
	 *
726
	 * @throws RequestBuilderException
727
	 */
728
	public function leftJoinBasedOn(
729
		string $aliasMember,
730
		?IFederatedUser $initiator = null
731
	): void {
732
		if ($this->getType() !== QueryBuilder::SELECT) {
733
			return;
734
		}
735
736
		try {
737
			$aliasBasedOn = $this->generateAlias($aliasMember, self::BASED_ON, $options);
738
		} catch (RequestBuilderException $e) {
739
			return;
740
		}
741
742
		$expr = $this->expr();
743
		$this->generateCircleSelectAlias($aliasBasedOn)
744
			 ->leftJoin(
745
				 $aliasMember, CoreRequestBuilder::TABLE_CIRCLE, $aliasBasedOn,
746
				 $expr->eq($aliasBasedOn . '.unique_id', $aliasMember . '.single_id')
747
			 );
748
749
		if (!is_null($initiator)) {
750
			$this->leftJoinInitiator($aliasBasedOn, $initiator);
751
			$this->leftJoinOwner($aliasBasedOn);
752
		}
753
	}
754
755
756
	/**
757
	 * @param string $alias
758
	 * @param string $field
759
	 *
760
	 * @throws RequestBuilderException
761
	 */
762
	public function leftJoinOwner(string $alias, string $field = 'unique_id'): void {
763
		if ($this->getType() !== QueryBuilder::SELECT) {
764
			return;
765
		}
766
767
		try {
768
			$aliasMember = $this->generateAlias($alias, self::OWNER, $options);
769
			$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...
770
		} catch (RequestBuilderException $e) {
771
			return;
772
		}
773
774
		$expr = $this->expr();
775
		$this->generateMemberSelectAlias($aliasMember)
776
			 ->leftJoin(
777
				 $alias, CoreRequestBuilder::TABLE_MEMBER, $aliasMember,
778
				 $expr->andX(
779
					 $expr->eq($aliasMember . '.circle_id', $alias . '.' . $field),
780
					 $expr->eq(
781
						 $aliasMember . '.level',
782
						 $this->createNamedParameter(Member::LEVEL_OWNER, self::PARAM_INT)
783
					 )
784
				 )
785
			 );
786
787
		$this->leftJoinBasedOn($aliasMember);
788
	}
789
790
791
	/**
792
	 * @param string $alias
793
	 * @param string $fieldCircleId
794
	 * @param string $fieldSingleId
795
	 *
796
	 * @throws RequestBuilderException
797
	 */
798
	public function leftJoinMember(
799
		string $alias,
800
		string $fieldCircleId = 'circle_id',
801
		string $fieldSingleId = 'single_id'
802
	): void {
803
		if ($this->getType() !== QueryBuilder::SELECT) {
804
			return;
805
		}
806
807
		try {
808
			$aliasMember = $this->generateAlias($alias, self::MEMBER, $options);
809
			$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...
810
		} catch (RequestBuilderException $e) {
811
			return;
812
		}
813
814
		$expr = $this->expr();
815
		$this->generateMemberSelectAlias($aliasMember)
816
			 ->leftJoin(
817
				 $alias, CoreRequestBuilder::TABLE_MEMBER, $aliasMember,
818
				 $expr->andX(
819
					 $expr->eq($aliasMember . '.circle_id', $alias . '.' . $fieldCircleId),
820
					 $expr->eq($aliasMember . '.single_id', $alias . '.' . $fieldSingleId),
821
					 $expr->gte(
822
						 $aliasMember . '.level',
823
						 $this->createNamedParameter(Member::LEVEL_MEMBER, self::PARAM_INT)
824
					 )
825
				 )
826
			 );
827
828
		$this->leftJoinRemoteInstance($aliasMember);
829
		$this->leftJoinBasedOn($aliasMember);
830
	}
831
832
833
	/**
834
	 * if 'getData' is true, will returns 'inheritanceBy': the Member at the end of a sub-chain of
835
	 * memberships (based on $field for Top Circle's singleId)
836
	 *
837
	 * @param string $alias
838
	 * @param string $field
839
	 * @param string $aliasInheritedBy
840
	 *
841
	 * @throws RequestBuilderException
842
	 */
843
	public function leftJoinInheritedMembers(
844
		string $alias,
845
		string $field = '',
846
		string $aliasInheritedBy = ''
847
	): void {
848
		$expr = $this->expr();
849
850
		$field = ($field === '') ? 'circle_id' : $field;
851
		$aliasMembership = $this->generateAlias($alias, self::MEMBERSHIPS, $options);
852
853
		$this->leftJoin(
854
			$alias, CoreRequestBuilder::TABLE_MEMBERSHIP, $aliasMembership,
855
			$expr->eq($aliasMembership . '.circle_id', $alias . '.' . $field)
856
		);
857
858
//		if (!$this->getBool('getData', $options, false)) {
859
//			return;
860
//		}
861
862
		if ($aliasInheritedBy === '') {
863
			$aliasInheritedBy = $this->generateAlias($alias, self::INHERITED_BY);
864
		}
865
		$this->generateMemberSelectAlias($aliasInheritedBy)
866
			 ->leftJoin(
867
				 $alias, CoreRequestBuilder::TABLE_MEMBER, $aliasInheritedBy,
868
				 $expr->andX(
869
					 $expr->eq($aliasMembership . '.inheritance_last', $aliasInheritedBy . '.circle_id'),
870
					 $expr->eq($aliasMembership . '.single_id', $aliasInheritedBy . '.single_id')
871
				 )
872
			 );
873
874
		$this->leftJoinBasedOn($aliasInheritedBy);
875
	}
876
877
878
	/**
879
	 * @throws RequestBuilderException
880
	 */
881
	public function limitToInheritedMemberships(string $alias, string $singleId, string $field = ''): void {
882
		$expr = $this->expr();
883
		$field = ($field === '') ? 'circle_id' : $field;
884
		$aliasUpstreamMembership = $this->generateAlias($alias, self::UPSTREAM_MEMBERSHIPS, $options);
885
		$this->leftJoin(
886
			$alias, CoreRequestBuilder::TABLE_MEMBERSHIP, $aliasUpstreamMembership,
887
			$expr->eq($aliasUpstreamMembership . '.single_id', $this->createNamedParameter($singleId))
888
		);
889
890
		$orX = $expr->orX(
891
			$expr->eq($aliasUpstreamMembership . '.circle_id', $alias . '.' . $field),
892
			$expr->eq($alias . '.' . $field, $this->createNamedParameter($singleId))
893
		);
894
895
		$this->andWhere($orX);
896
	}
897
898
899
	/**
900
	 * limit the request to Members and Sub Members of a Circle.
901
	 *
902
	 * @param string $alias
903
	 * @param string $singleId
904
	 *
905
	 * @throws RequestBuilderException
906
	 */
907
	public function limitToMembersByInheritance(string $alias, string $singleId): void {
908
		$this->leftJoinMembersByInheritance($alias);
909
910
		$expr = $this->expr();
911
		$aliasMembership = $this->generateAlias($alias, self::MEMBERSHIPS);
912
		$this->andWhere($expr->eq($aliasMembership . '.circle_id', $this->createNamedParameter($singleId)));
913
	}
914
915
916
	/**
917
	 * if 'getData' is true, will returns 'inheritanceFrom': the Circle-As-Member of the Top Circle
918
	 * that explain the membership of a Member (based on $field for singleId) to a specific Circle
919
	 *
920
	 * // TODO: returns the link/path ?
921
	 *
922
	 * @param string $alias
923
	 * @param string $field
924
	 *
925
	 * @throws RequestBuilderException
926
	 */
927
	public function leftJoinMembersByInheritance(string $alias, string $field = ''): void {
928
		$expr = $this->expr();
929
930
		$field = ($field === '') ? 'circle_id' : $field;
931
		$aliasMembership = $this->generateAlias($alias, self::MEMBERSHIPS, $options);
932
933
		$this->leftJoin(
934
			$alias, CoreRequestBuilder::TABLE_MEMBERSHIP, $aliasMembership,
935
//			$expr->andX(
936
			$expr->eq($aliasMembership . '.inheritance_last', $alias . '.' . $field)
937
//				$expr->eq($aliasMembership . '.single_id', $alias . '.single_id')
938
//			)
939
		);
940
941
		if (!$this->getBool('getData', $options, false)) {
942
			return;
943
		}
944
945
		$aliasInheritanceFrom = $this->generateAlias($alias, self::INHERITANCE_FROM);
946
		$this->generateMemberSelectAlias($aliasInheritanceFrom)
947
			 ->leftJoin(
948
				 $aliasMembership, CoreRequestBuilder::TABLE_MEMBER, $aliasInheritanceFrom,
949
				 $expr->andX(
950
					 $expr->eq($aliasMembership . '.circle_id', $aliasInheritanceFrom . '.circle_id'),
951
					 $expr->eq($aliasMembership . '.inheritance_first', $aliasInheritanceFrom . '.single_id')
952
				 )
953
			 );
954
	}
955
956
957
	/**
958
	 * limit the result to the point of view of a FederatedUser
959
	 *
960
	 * @param string $alias
961
	 * @param IFederatedUser $user
962
	 * @param string $field
963
	 * @param string $helperAlias
964
	 *
965
	 * @return ICompositeExpression
966
	 * @throws RequestBuilderException
967
	 */
968
	public function limitToInitiator(
969
		string $alias,
970
		IFederatedUser $user,
971
		string $field = '',
972
		string $helperAlias = ''
973
	): ICompositeExpression {
974
		$this->leftJoinInitiator($alias, $user, $field, $helperAlias);
975
		$where = $this->limitInitiatorVisibility($alias);
976
977
		$aliasInitiator = $this->generateAlias($alias, self::INITIATOR, $options);
978
		if ($this->getBool('getData', $options, false)) {
979
			$this->leftJoinBasedOn($aliasInitiator);
980
		}
981
982
		return $where;
983
	}
984
985
986
	/**
987
	 * Left join members to filter userId as initiator.
988
	 *
989
	 * @param string $alias
990
	 * @param IFederatedUser $initiator
991
	 * @param string $field
992
	 * @param string $helperAlias
993
	 *
994
	 * @throws RequestBuilderException
995
	 */
996
	public function leftJoinInitiator(
997
		string $alias,
998
		IFederatedUser $initiator,
999
		string $field = '',
1000
		string $helperAlias = ''
1001
	): void {
1002
		if ($this->getType() !== QueryBuilder::SELECT) {
1003
			return;
1004
		}
1005
1006
		$expr = $this->expr();
1007
		$field = ($field === '') ? 'unique_id' : $field;
1008
		$helperAlias = ($helperAlias !== '') ? $helperAlias : $alias;
1009
		$aliasMembership = $this->generateAlias($alias, self::MEMBERSHIPS, $options);
1010
1011
		$this->leftJoin(
1012
			$helperAlias,
1013
			CoreRequestBuilder::TABLE_MEMBERSHIP,
1014
			$aliasMembership,
1015
			$expr->andX(
1016
				$this->exprLimit('single_id', $initiator->getSingleId(), $aliasMembership),
1017
				$expr->eq($aliasMembership . '.circle_id', $helperAlias . '.' . $field)
1018
			)
1019
		);
1020
1021
		if (!$this->getBool('getData', $options, false)) {
1022
			return;
1023
		}
1024
1025
		try {
1026
			$aliasInitiator = $this->generateAlias($alias, self::INITIATOR, $options);
1027
			$this->leftJoin(
1028
				$aliasMembership, CoreRequestBuilder::TABLE_MEMBER, $aliasInitiator,
1029
				$expr->andX(
1030
					$expr->eq($aliasMembership . '.inheritance_first', $aliasInitiator . '.single_id'),
1031
					$expr->eq($aliasMembership . '.circle_id', $aliasInitiator . '.circle_id')
1032
				)
1033
			);
1034
1035
			$aliasInheritedBy = $this->generateAlias($aliasInitiator, self::INHERITED_BY);
1036
			$this->leftJoin(
1037
				$aliasInitiator, CoreRequestBuilder::TABLE_MEMBER, $aliasInheritedBy,
1038
				$expr->andX(
1039
					$expr->eq($aliasMembership . '.single_id', $aliasInheritedBy . '.single_id'),
1040
					$expr->eq($aliasMembership . '.inheritance_last', $aliasInheritedBy . '.circle_id')
1041
				)
1042
			);
1043
1044
			$default = [];
1045
			if ($this->getBool('canBeVisitor', $options, false)) {
1046
				$default = [
1047
					'user_id'   => $initiator->getUserId(),
1048
					'single_id' => $initiator->getSingleId(),
1049
					'user_type' => $initiator->getUserType(),
1050
					'instance'  => $initiator->getInstance()
1051
				];
1052
			}
1053
			$this->generateMemberSelectAlias($aliasInitiator, $default);
1054
1055
			$this->generateMemberSelectAlias($aliasInheritedBy);
1056
			$aliasInheritedByMembership = $this->generateAlias($aliasInheritedBy, self::MEMBERSHIPS);
1057
			$this->generateMembershipSelectAlias($aliasMembership, $aliasInheritedByMembership);
1058
		} catch (RequestBuilderException $e) {
1059
			\OC::$server->getLogger()->log(3, '-- ' . $e->getMessage());
1060
		}
1061
	}
1062
1063
1064
	/**
1065
	 * @param string $alias
1066
	 *
1067
	 * @return ICompositeExpression
1068
	 * @throws RequestBuilderException
1069
	 */
1070
	protected function limitInitiatorVisibility(string $alias): ICompositeExpression {
1071
		$aliasMembership = $this->generateAlias($alias, self::MEMBERSHIPS, $options);
1072
		$getPersonalCircle = $this->getBool('getPersonalCircle', $options, false);
1073
1074
		$expr = $this->expr();
1075
1076
		// Visibility to non-member is
1077
		// - 0 (default), if initiator is member
1078
		// - 2 (Personal), if initiator is owner)
1079
		// - 4 (Visible to everyone)
1080
		$orX = $expr->orX();
1081
		$orX->add(
1082
			$expr->andX(
1083
				$expr->gte($aliasMembership . '.level', $this->createNamedParameter(Member::LEVEL_MEMBER))
1084
			)
1085
		);
1086
1087
		if ($getPersonalCircle) {
1088
			$orX->add(
1089
				$expr->andX(
1090
					$expr->bitwiseAnd($alias . '.config', Circle::CFG_PERSONAL),
1091
					$expr->eq($aliasMembership . '.level', $this->createNamedParameter(Member::LEVEL_OWNER))
1092
				)
1093
			);
1094
		}
1095
		if (!$this->getBool('mustBeMember', $options, true)) {
1096
			$orX->add($expr->bitwiseAnd($alias . '.config', Circle::CFG_VISIBLE));
1097
		}
1098
		if ($this->getBool('canBeVisitor', $options, false)) {
1099
			// TODO: should find a better way, also filter on remote initiator on non-federated ?
1100
			$orX->add($expr->gte($alias . '.config', $this->createNamedParameter(0)));
1101
		}
1102
		if ($this->getBool('canBeVisitorOnOpen', $options, false)) {
1103
			$andOpen = $expr->andX();
1104
			$andOpen->add($expr->bitwiseAnd($alias . '.config', Circle::CFG_OPEN));
1105
			$andOpen->add(
1106
				$this->createFunction('NOT') . $expr->bitwiseAnd($alias . '.config', Circle::CFG_REQUEST)
1107
			);
1108
			$orX->add($andOpen);
1109
		}
1110
1111
		$this->andWhere($orX);
1112
1113
		return $orX;
1114
//		$orTypes = $this->generateLimit($qb, $circleUniqueId, $userId, $type, $name, $forceAll);
1115
//		if (sizeof($orTypes) === 0) {
1116
//			throw new ConfigNoCircleAvailableException(
1117
//				$this->l10n->t(
1118
//					'You cannot use the Circles Application until your administrator has allowed at least one type of circles'
1119
//				)
1120
//			);
1121
//		}
1122
1123
//		$orXTypes = $this->expr()
1124
//						 ->orX();
1125
//		foreach ($orTypes as $orType) {
1126
//			$orXTypes->add($orType);
1127
//		}
1128
//
1129
//		$qb->andWhere($orXTypes);
1130
	}
1131
1132
1133
	/**
1134
	 * CFG_SINGLE, CFG_HIDDEN and CFG_BACKEND means hidden from listing.
1135
	 *
1136
	 * @param string $aliasCircle
1137
	 * @param int $flag
1138
	 */
1139
	public function filterCircles(
1140
		string $aliasCircle,
1141
		int $flag = Circle::CFG_SINGLE | Circle::CFG_HIDDEN | Circle::CFG_BACKEND
1142
	): void {
1143
		if ($flag === 0) {
1144
			return;
1145
		}
1146
1147
		$expr = $this->expr();
1148
		$hide = $expr->andX();
1149
		foreach (Circle::$DEF_CFG as $cfg => $v) {
1150
			if ($flag & $cfg) {
1151
				$hide->add($this->createFunction('NOT') . $expr->bitwiseAnd($aliasCircle . '.config', $cfg));
1152
			}
1153
		}
1154
1155
		$this->andWhere($hide);
1156
	}
1157
1158
1159
	/**
1160
	 * Limit visibility on Sensitive information when search for members.
1161
	 *
1162
	 * @param string $alias
1163
	 *
1164
	 * @return ICompositeExpression
1165
	 */
1166
	private function limitRemoteVisibility_Sensitive_Members(string $alias): ICompositeExpression {
1167
		$expr = $this->expr();
1168
		$andPassive = $expr->andX();
1169
		$andPassive->add(
1170
			$expr->eq($alias . '.type', $this->createNamedParameter(RemoteInstance::TYPE_PASSIVE))
1171
		);
1172
1173
		$orMemberOrLevel = $expr->orX();
1174
		$orMemberOrLevel->add(
1175
			$expr->eq($this->getDefaultSelectAlias() . '.instance', $alias . '.instance')
1176
		);
1177
		// TODO: do we need this ? (display members from the local instance)
1178
		$orMemberOrLevel->add(
1179
			$expr->emptyString($this->getDefaultSelectAlias() . '.instance')
1180
		);
1181
1182
		$orMemberOrLevel->add(
1183
			$expr->eq(
1184
				$this->getDefaultSelectAlias() . '.level',
1185
				$this->createNamedParameter(Member::LEVEL_OWNER)
1186
			)
1187
		);
1188
		$andPassive->add($orMemberOrLevel);
1189
1190
		return $andPassive;
1191
	}
1192
1193
1194
	/**
1195
	 *
1196
	 * @param string $aliasCircle
1197
	 * @param int $flag
1198
	 */
1199
	public function filterConfig(string $aliasCircle, int $flag): void {
1200
		$this->andWhere($this->expr()->bitwiseAnd($aliasCircle . '.config', $flag));
1201
	}
1202
1203
1204
	/**
1205
	 * Link to storage/filecache
1206
	 *
1207
	 * @param string $aliasShare
1208
	 *
1209
	 * @throws RequestBuilderException
1210
	 */
1211
	public function leftJoinFileCache(string $aliasShare) {
1212
		$expr = $this->expr();
1213
1214
		$aliasFileCache = $this->generateAlias($aliasShare, self::FILE_CACHE);
1215
		$aliasStorages = $this->generateAlias($aliasFileCache, self::STORAGES);
1216
1217
		$this->generateSelectAlias(
1218
			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...
1219
			$aliasFileCache,
1220
			$aliasFileCache,
1221
			[]
1222
		)
1223
			 ->generateSelectAlias(
1224
				 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...
1225
				 $aliasStorages,
1226
				 $aliasStorages,
1227
				 []
1228
			 )
1229
			 ->leftJoin(
1230
				 $aliasShare, CoreRequestBuilder::TABLE_FILE_CACHE, $aliasFileCache,
1231
				 $expr->eq($aliasShare . '.file_source', $aliasFileCache . '.fileid')
1232
			 )
1233
			 ->leftJoin(
1234
				 $aliasFileCache, CoreRequestBuilder::TABLE_STORAGES, $aliasStorages,
1235
				 $expr->eq($aliasFileCache . '.storage', $aliasStorages . '.numeric_id')
1236
			 );
1237
	}
1238
1239
1240
	/**
1241
	 * @param string $aliasShare
1242
	 * @param string $aliasShareMemberships
1243
	 *
1244
	 * @throws RequestBuilderException
1245
	 */
1246
	public function leftJoinShareChild(string $aliasShare, string $aliasShareMemberships = '') {
1247
		$expr = $this->expr();
1248
1249
		$aliasShareChild = $this->generateAlias($aliasShare, self::SHARE);
1250
		if ($aliasShareMemberships === '') {
1251
			$aliasShareMemberships = $this->generateAlias($aliasShare, self::MEMBERSHIPS, $options);
1252
		}
1253
1254
		$this->leftJoin(
1255
			$aliasShareMemberships, CoreRequestBuilder::TABLE_SHARE, $aliasShareChild,
1256
			$expr->andX(
1257
				$expr->eq($aliasShareChild . '.parent', $aliasShare . '.id'),
1258
				$expr->eq($aliasShareChild . '.share_with', $aliasShareMemberships . '.single_id')
1259
			)
1260
		);
1261
1262
		$this->generateSelectAlias(
1263
			['id', 'file_target', 'permissions'],
1264
			$aliasShareChild,
1265
			'child_',
1266
			[]
1267
		);
1268
1269
//		$this->selectAlias($aliasShareParent . '.permissions', 'parent_perms');
1270
	}
1271
1272
1273
	/**
1274
	 * @param string $alias
1275
	 * @param FederatedUser $federatedUser
1276
	 * @param bool $reshares
1277
	 */
1278
	public function limitToShareOwner(string $alias, FederatedUser $federatedUser, bool $reshares): void {
1279
		$expr = $this->expr();
1280
1281
		$orX = $expr->orX($this->exprLimit('uid_initiator', $federatedUser->getUserId(), $alias));
1282
1283
		if ($reshares) {
1284
			$orX->add($this->exprLimit('uid_owner', $federatedUser->getUserId(), $alias));
1285
		}
1286
1287
		$this->andWhere($orX);
1288
	}
1289
1290
1291
	/**
1292
	 * @param string $aliasMount
1293
	 * @param string $aliasMountMemberships
1294
	 *
1295
	 * @throws RequestBuilderException
1296
	 */
1297
	public function leftJoinMountpoint(string $aliasMount, string $aliasMountMemberships = '') {
1298
		$expr = $this->expr();
1299
1300
		$aliasMountpoint = $this->generateAlias($aliasMount, self::MOUNTPOINT);
1301
		if ($aliasMountMemberships === '') {
1302
			$aliasMountMemberships = $this->generateAlias($aliasMount, self::MEMBERSHIPS, $options);
1303
		}
1304
1305
		$this->leftJoin(
1306
			$aliasMountMemberships, CoreRequestBuilder::TABLE_MOUNTPOINT, $aliasMountpoint,
1307
			$expr->andX(
1308
				$expr->eq($aliasMountpoint . '.mount_id', $aliasMount . '.mount_id'),
1309
				$expr->eq($aliasMountpoint . '.single_id', $aliasMountMemberships . '.single_id')
1310
			)
1311
		);
1312
1313
		$this->selectAlias($aliasMountpoint . '.mountpoint', $aliasMountpoint . '_mountpoint');
1314
		$this->selectAlias($aliasMountpoint . '.mountpoint_hash', $aliasMountpoint . '_mountpoint_hash');
1315
	}
1316
1317
1318
	/**
1319
	 * @param string $alias
1320
	 * @param array $default
1321
	 *
1322
	 * @return CoreQueryBuilder
1323
	 */
1324
	private function generateCircleSelectAlias(string $alias, array $default = []): self {
1325
		$this->generateSelectAlias(
1326
			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...
1327
			$alias,
1328
			$alias,
1329
			$default
1330
		);
1331
1332
		return $this;
1333
	}
1334
1335
	/**
1336
	 * @param string $alias
1337
	 * @param array $default
1338
	 *
1339
	 * @return $this
1340
	 */
1341
	private function generateMemberSelectAlias(string $alias, array $default = []): self {
1342
		$this->generateSelectAlias(
1343
			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...
1344
			$alias,
1345
			$alias,
1346
			$default
1347
		);
1348
1349
		return $this;
1350
	}
1351
1352
1353
	/**
1354
	 * @param string $alias
1355
	 * @param array $default
1356
	 * @param string $prefix
1357
	 *
1358
	 * @return $this
1359
	 */
1360
	private function generateMembershipSelectAlias(
1361
		string $alias,
1362
		string $prefix = '',
1363
		array $default = []
1364
	): self {
1365
		$this->generateSelectAlias(
1366
			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...
1367
			$alias,
1368
			($prefix === '') ? $alias : $prefix,
1369
			$default
1370
		);
1371
1372
		return $this;
1373
	}
1374
1375
1376
	/**
1377
	 * @param string $alias
1378
	 * @param array $default
1379
	 *
1380
	 * @return $this
1381
	 */
1382
	private function generateRemoteInstanceSelectAlias(string $alias, array $default = []): self {
1383
		$this->generateSelectAlias(
1384
			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...
1385
			$alias,
1386
			$alias,
1387
			$default
1388
		);
1389
1390
		return $this;
1391
	}
1392
1393
1394
	/**
1395
	 * @param array $path
1396
	 * @param array $options
1397
	 */
1398
	public function setOptions(array $path, array $options): void {
1399
		$options = [self::OPTIONS => $options];
1400
		foreach (array_reverse($path) as $item) {
1401
			$options = [$item => $options];
1402
		}
1403
1404
		$this->options = $options;
1405
	}
1406
1407
1408
	/**
1409
	 * @param string $base
1410
	 * @param string $extension
1411
	 * @param array|null $options
1412
	 *
1413
	 * @return string
1414
	 * @throws RequestBuilderException
1415
	 */
1416
	public function generateAlias(string $base, string $extension, ?array &$options = []): string {
1417
		$search = str_replace('_', '.', $base);
1418
		$path = $search . '.' . $extension;
1419
		if (!$this->validKey($path, self::$SQL_PATH)
1420
			&& !in_array($extension, $this->getArray($search, self::$SQL_PATH))) {
1421
			throw new RequestBuilderException($extension . ' not found in ' . $search);
1422
		}
1423
1424
		if (!is_array($options)) {
1425
			$options = [];
1426
		}
1427
1428
		$optionPath = '';
1429
		foreach (explode('.', $path) as $p) {
1430
			$optionPath = trim($optionPath . '.' . $p, '.');
1431
			$options = array_merge(
1432
				$options,
1433
				$this->getArray($optionPath . '.' . self::OPTIONS, self::$SQL_PATH),
1434
				$this->getArray($optionPath . '.' . self::OPTIONS, $this->options)
1435
			);
1436
		}
1437
1438
		return $base . '_' . $extension;
1439
	}
1440
1441
1442
	/**
1443
	 * @param string $prefix
1444
	 *
1445
	 * @return array
1446
	 */
1447
	public function getAvailablePath(string $prefix): array {
1448
		$prefix = trim($prefix, '_');
1449
		$search = str_replace('_', '.', $prefix);
1450
1451
		$path = [];
1452
		foreach ($this->getArray($search, self::$SQL_PATH) as $arr => $item) {
1453
			if (is_numeric($arr)) {
1454
				$k = $item;
1455
			} else {
1456
				$k = $arr;
1457
			}
1458
			$path[$k] = $prefix . '_' . $k . '_';
1459
		}
1460
1461
		return $path;
1462
	}
1463
1464
}
1465
1466