Completed
Pull Request — master (#79)
by Maxence
03:23
created

CircleProviderRequestBuilder::joinCircleMembers()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 21
Code Lines 11

Duplication

Lines 14
Ratio 66.67 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 14
loc 21
rs 9.3142
cc 2
eloc 11
nc 2
nop 1
1
<?php
2
3
/**
4
 * Circles - Bring cloud-users closer together.
5
 *
6
 * This file is licensed under the Affero General Public License version 3 or
7
 * later. See the COPYING file.
8
 *
9
 * @author Maxence Lange <[email protected]>
10
 * @copyright 2017
11
 * @license GNU AGPL version 3 or any later version
12
 *
13
 * This program is free software: you can redistribute it and/or modify
14
 * it under the terms of the GNU Affero General Public License as
15
 * published by the Free Software Foundation, either version 3 of the
16
 * License, or (at your option) any later version.
17
 *
18
 * This program is distributed in the hope that it will be useful,
19
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21
 * GNU Affero General Public License for more details.
22
 *
23
 * You should have received a copy of the GNU Affero General Public License
24
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
25
 *
26
 */
27
28
namespace OCA\Circles\Db;
29
30
31
use Doctrine\DBAL\Platforms\PostgreSqlPlatform;
32
use Doctrine\DBAL\Query\QueryBuilder;
33
use OCA\Circles\Model\Member;
34
use OCP\DB\QueryBuilder\IQueryBuilder;
35
use OCP\IDBConnection;
36
use OCP\Share;
37
use OCP\Share\IShare;
38
39
class CircleProviderRequestBuilder {
40
41
42
	/** @var IDBConnection */
43
	protected $dbConnection;
44
45
46
	/**
47
	 * returns the SQL request to get a specific share from the fileId and circleId
48
	 *
49
	 * @param int $fileId
50
	 * @param int $circleId
51
	 *
52
	 * @return \OCP\DB\QueryBuilder\IQueryBuilder
53
	 * @internal param $share
54
	 *
55
	 */
56
	protected function findShareParentSql($fileId, $circleId) {
57
58
		$qb = $this->getBaseSelectSql();
59
		$this->limitToShareParent($qb);
60
		$this->limitToCircle($qb, $circleId);
61
		$this->limitToFiles($qb, $fileId);
62
63
		return $qb;
64
	}
65
66
67
	/**
68
	 * Limit the request to a Circle.
69
	 *
70
	 * @param IQueryBuilder $qb
71
	 * @param integer $circleId
72
	 */
73
	protected function limitToCircle(& $qb, $circleId) {
74
		$expr = $qb->expr();
75
		$pf = ($qb->getType() === QueryBuilder::SELECT) ? 's.' : '';
76
77
		$qb->andWhere($expr->eq($pf . 'share_with', $qb->createNamedParameter($circleId)));
78
	}
79
80
81
	/**
82
	 * Limit the request to the Share by its Id.
83
	 *
84
	 * @param IQueryBuilder $qb
85
	 * @param $shareId
86
	 */
87
	protected function limitToShare(& $qb, $shareId) {
88
		$expr = $qb->expr();
89
		$pf = ($qb->getType() === QueryBuilder::SELECT) ? 's.' : '';
90
91
		$qb->andWhere($expr->eq($pf . 'id', $qb->createNamedParameter($shareId)));
92
	}
93
94
95
	/**
96
	 * Limit the request to the top share (no children)
97
	 *
98
	 * @param IQueryBuilder $qb
99
	 */
100
	protected function limitToShareParent(& $qb) {
101
		$expr = $qb->expr();
102
103
		$qb->andWhere($expr->isNull('parent'));
104
	}
105
106
107
	/**
108
	 * limit the request to the children of a share
109
	 *
110
	 * @param IQueryBuilder $qb
111
	 * @param $userId
112
	 * @param int $parentId
113
	 */
114
	protected function limitToShareChildren(& $qb, $userId, $parentId = -1) {
115
		$expr = $qb->expr();
116
		$qb->andWhere($expr->eq('share_with', $qb->createNamedParameter($userId)));
117
118
		if ($parentId > -1) {
119
			$qb->andWhere($expr->eq('parent', $qb->createNamedParameter($parentId)));
120
		} else {
121
			$qb->andWhere($expr->isNotNull('parent'));
122
		}
123
	}
124
125
126
	/**
127
	 * limit the request to the share itself AND its children.
128
	 * perfect if you want to delete everything related to a share
129
	 *
130
	 * @param IQueryBuilder $qb
131
	 * @param $circleId
132
	 */
133
	protected function limitToShareAndChildren(& $qb, $circleId) {
134
		$expr = $qb->expr();
135
		$pf = ($qb->getType() === QueryBuilder::SELECT) ? 's.' : '';
136
137
		/** @noinspection PhpMethodParametersCountMismatchInspection */
138
		$qb->andWhere(
139
			$expr->orX(
140
				$expr->eq($pf . 'parent', $qb->createNamedParameter($circleId)),
141
				$expr->eq($pf . 'id', $qb->createNamedParameter($circleId))
142
			)
143
		);
144
	}
145
146
147
	/**
148
	 * limit the request to a fileId.
149
	 *
150
	 * @param IQueryBuilder $qb
151
	 * @param $fileId
152
	 */
153
	protected function limitToFiles(& $qb, $files) {
154
155
		if (!is_array($files)) {
156
			$files = array($files);
157
		}
158
159
		$expr = $qb->expr();
160
		$pf = ($qb->getType() === QueryBuilder::SELECT) ? 's.' : '';
161
		$qb->andWhere(
162
			$expr->in(
163
				$pf . 'file_source',
164
				$qb->createNamedParameter($files, IQueryBuilder::PARAM_INT_ARRAY)
165
			)
166
		);
167
	}
168
169
170
	/**
171
	 * @param IQueryBuilder $qb
172
	 * @param int $limit
173
	 * @param int $offset
174
	 */
175
	protected function limitToPage(& $qb, $limit = -1, $offset = 0) {
176
		if ($limit !== -1) {
177
			$qb->setMaxResults($limit);
178
		}
179
180
		$qb->setFirstResult($offset);
181
	}
182
183
	/**
184
	 * limit the request to a userId
185
	 *
186
	 * @param IQueryBuilder $qb
187
	 * @param string $userId
188
	 * @param bool $reShares
189
	 */
190
	protected function limitToShareOwner(& $qb, $userId, $reShares = false) {
191
		$expr = $qb->expr();
192
		$pf = ($qb->getType() === QueryBuilder::SELECT) ? 's.' : '';
193
194
		if ($reShares === false) {
195
			$qb->andWhere($expr->eq($pf . 'uid_initiator', $qb->createNamedParameter($userId)));
196
		} else {
197
			/** @noinspection PhpMethodParametersCountMismatchInspection */
198
			$qb->andWhere(
199
				$expr->orX(
200
					$expr->eq($pf . 'uid_owner', $qb->createNamedParameter($userId)),
201
					$expr->eq($pf . 'uid_initiator', $qb->createNamedParameter($userId))
202
				)
203
			);
204
		}
205
	}
206
207
208
	/**
209
	 * link circle field
210
	 *
211
	 * @deprecated
212
	 *
213
	 * @param IQueryBuilder $qb
214
	 * @param integer $shareId
215
	 */
216
	// TODO - put this as a leftjoin
217
	protected function linkCircleField(& $qb, $shareId = -1) {
218
		$expr = $qb->expr();
219
220
		// TODO - Remove this in 12.0.1
221 View Code Duplication
		if ($qb->getConnection()
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
222
			   ->getDatabasePlatform() instanceof PostgreSqlPlatform
1 ignored issue
show
Bug introduced by
The class Doctrine\DBAL\Platforms\PostgreSqlPlatform does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
223
		) {
224
			$tmpOrX = $expr->eq('s.share_with', $qb->createFunction('CAST(c.id AS TEXT)'));
225
		} else {
226
			$tmpOrX =
227
				$expr->eq('s.share_with', $expr->castColumn('c.id', IQueryBuilder::PARAM_STR));
228
		}
229
230
		$qb->from(CirclesMapper::TABLENAME, 'c');
231
232
		if ($shareId === -1) {
233
			$qb->andWhere($tmpOrX);
234
235
			return;
236
		}
237
238
		/** @noinspection PhpMethodParametersCountMismatchInspection */
239
		$qb->andWhere(
240
			$expr->orX(
241
				$tmpOrX,
242
				$expr->eq('s.parent', $qb->createNamedParameter($shareId))
243
			)
244
		);
245
		//->orderBy('c.circle_name');
0 ignored issues
show
Unused Code Comprehensibility introduced by
84% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
246
	}
247
248
249
	/**
250
	 * @param IQueryBuilder $qb
251
	 */
252
	protected function linkToCircleOwner(& $qb) {
253
		$expr = $qb->expr();
254
255
		/** @noinspection PhpMethodParametersCountMismatchInspection */
256
		$qb->leftJoin(
257
			'c', 'circles_members', 'mo', $expr->andX(
258
			$expr->eq('c.id', 'mo.circle_id'),
259
			$expr->eq('mo.level', $qb->createNamedParameter(Member::LEVEL_OWNER))
260
		)
261
		);
262
	}
263
264
265
	/**
266
	 * Link to member (userId) of circle
267
	 *
268
	 * @param IQueryBuilder $qb
269
	 * @param string $userId
270
	 */
271
	protected function linkToMember(& $qb, $userId) {
272
		$expr = $qb->expr();
273
274
		// TODO - Remove this in 12.0.1
275 View Code Duplication
		if ($qb->getConnection()
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
276
			   ->getDatabasePlatform() instanceof PostgreSqlPlatform
1 ignored issue
show
Bug introduced by
The class Doctrine\DBAL\Platforms\PostgreSqlPlatform does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
277
		) {
278
			$tmpAndX = $expr->eq('s.share_with', $qb->createFunction('CAST(m.circle_id AS TEXT)'));
279
		} else {
280
			$tmpAndX = $expr->eq(
281
				's.share_with', $expr->castColumn('m.circle_id', IQueryBuilder::PARAM_STR)
282
			);
283
		}
284
285
		$qb->from(MembersMapper::TABLENAME, 'm')
286
		   ->andWhere($tmpAndX)
287
		   ->andWhere($expr->eq('m.user_id', $qb->createNamedParameter($userId)))
288
		   ->andWhere($expr->gte('m.level', $qb->createNamedParameter(Member::LEVEL_MEMBER)));
289
290
	}
291
292
293
	/**
294
	 * Link to all members of circle
295
	 *
296
	 * @param IQueryBuilder $qb
297
	 */
298
	protected function joinCircleMembers(& $qb) {
299
		$expr = $qb->expr();
300
301
		$qb->from(MembersMapper::TABLENAME, 'm');
302
303
		// TODO - Remove this in 12.0.1
304 View Code Duplication
		if ($qb->getConnection()
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
305
			   ->getDatabasePlatform() instanceof PostgreSqlPlatform
1 ignored issue
show
Bug introduced by
The class Doctrine\DBAL\Platforms\PostgreSqlPlatform does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
306
		) {
307
			$qb->andWhere(
308
				$expr->eq('s.share_with', $qb->createFunction('CAST(m.circle_id AS TEXT)'))
309
			);
310
		} else {
311
312
			$qb->andWhere(
313
				$expr->eq(
314
					's.share_with', $expr->castColumn('m.circle_id', IQueryBuilder::PARAM_STR)
315
				)
316
			);
317
		}
318
	}
319
320
321
	/**
322
	 * Link to storage/filecache
323
	 *
324
	 * @param IQueryBuilder $qb
325
	 * @param string $userId
326
	 */
327
	protected function linkToFileCache(& $qb, $userId) {
328
		$expr = $qb->expr();
329
330
		/** @noinspection PhpMethodParametersCountMismatchInspection */
331
		$qb->leftJoin('s', 'filecache', 'f', $expr->eq('s.file_source', 'f.fileid'))
332
		   ->leftJoin('f', 'storages', 'st', $expr->eq('f.storage', 'st.numeric_id'))
333
		   ->leftJoin(
334
			   's', 'share', 's2', $expr->andX(
335
			   $expr->eq('s.id', 's2.parent'),
336
			   $expr->eq('s2.share_with', $qb->createNamedParameter($userId))
337
		   )
338
		   );
339
	}
340
341
342
	/**
343
	 * add share to the database and return the ID
344
	 *
345
	 * @param IShare $share
346
	 *
347
	 * @return IQueryBuilder
348
	 */
349
	protected function getBaseInsertSql($share) {
350
		$qb = $this->dbConnection->getQueryBuilder();
351
		$qb->insert('share')
352
		   ->setValue('share_type', $qb->createNamedParameter(Share::SHARE_TYPE_CIRCLE))
353
		   ->setValue('item_type', $qb->createNamedParameter($share->getNodeType()))
354
		   ->setValue('item_source', $qb->createNamedParameter($share->getNodeId()))
355
		   ->setValue('file_source', $qb->createNamedParameter($share->getNodeId()))
356
		   ->setValue('file_target', $qb->createNamedParameter($share->getTarget()))
357
		   ->setValue('share_with', $qb->createNamedParameter($share->getSharedWith()))
358
		   ->setValue('uid_owner', $qb->createNamedParameter($share->getShareOwner()))
359
		   ->setValue('uid_initiator', $qb->createNamedParameter($share->getSharedBy()))
360
		   ->setValue('permissions', $qb->createNamedParameter($share->getPermissions()))
361
		   ->setValue('token', $qb->createNamedParameter($share->getToken()))
362
		   ->setValue('stime', $qb->createFunction('UNIX_TIMESTAMP()'));
363
364
		return $qb;
365
	}
366
367
368
	/**
369
	 * generate and return a base sql request.
370
	 *
371
	 * @param int $shareId
372
	 *
373
	 * @return IQueryBuilder
374
	 */
375
	protected function getBaseSelectSql($shareId = -1) {
376
		$qb = $this->dbConnection->getQueryBuilder();
377
378
		/** @noinspection PhpMethodParametersCountMismatchInspection */
379
		$qb->select(
380
			's.id', 's.share_type', 's.share_with', 's.uid_owner', 's.uid_initiator',
381
			's.parent', 's.item_type', 's.item_source', 's.item_target', 's.file_source',
382
			's.file_target', 's.permissions', 's.stime', 's.accepted', 's.expiration',
383
			's.token', 's.mail_send', 'c.type AS circle_type', 'c.name AS circle_name',
384
			'mo.user_id AS circle_owner'
385
		);
386
		$this->linkToCircleOwner($qb);
387
		$this->joinShare($qb);
388
389
		// TODO: Left-join circle and REMOVE this line
390
		$this->linkCircleField($qb, $shareId);
391
392
		return $qb;
393
	}
394
395
396
	/**
397
	 * Generate and return a base sql request
398
	 * This one should be used to retrieve a complete list of users (ie. access list).
399
	 *
400
	 * @return IQueryBuilder
401
	 */
402
	protected function getAccessListBaseSelectSql() {
403
		$qb = $this->dbConnection->getQueryBuilder();
404
405
		/** @noinspection PhpMethodParametersCountMismatchInspection */
406
		$qb->select(
407
			'm.user_id', 's.file_source', 's.file_target'
408
		);
409
		$this->joinCircleMembers($qb);
410
		$this->joinShare($qb);
411
412
		return $qb;
413
	}
414
415
416
	protected function getCompleteSelectSql() {
417
		$qb = $this->dbConnection->getQueryBuilder();
418
419
		/** @noinspection PhpMethodParametersCountMismatchInspection */
420
		$qb->select(
421
			's.*', 'f.fileid', 'f.path', 'f.permissions AS f_permissions', 'f.storage',
422
			'f.path_hash', 'f.parent AS f_parent', 'f.name', 'f.mimetype', 'f.mimepart',
423
			'f.size', 'f.mtime', 'f.storage_mtime', 'f.encrypted', 'f.unencrypted_size',
424
			'f.etag', 'f.checksum', 'c.type AS circle_type', 'c.name AS circle_name',
425
			's2.id AS parent_id', 's2.file_target AS parent_target',
426
			's2.permissions AS parent_perms'
427
		)
428
		   ->selectAlias('st.id', 'storage_string_id');
429
430
		$this->joinShare($qb);
431
		$this->linkCircleField($qb);
432
433
434
		return $qb;
435
	}
436
437
438
	/**
439
	 * @param IQueryBuilder $qb
440
	 */
441
	private function joinShare(& $qb) {
442
		$expr = $qb->expr();
443
444
		/** @noinspection PhpMethodParametersCountMismatchInspection */
445
		$qb->from('share', 's')
446
		   ->where($expr->eq('s.share_type', $qb->createNamedParameter(Share::SHARE_TYPE_CIRCLE)))
447
		   ->andWhere(
448
			   $expr->orX(
449
				   $expr->eq('s.item_type', $qb->createNamedParameter('file')),
450
				   $expr->eq('s.item_type', $qb->createNamedParameter('folder'))
451
			   )
452
		   );
453
	}
454
455
456
	/**
457
	 * generate and return a base sql request.
458
	 *
459
	 * @return \OCP\DB\QueryBuilder\IQueryBuilder
460
	 */
461 View Code Duplication
	protected function getBaseDeleteSql() {
462
		$qb = $this->dbConnection->getQueryBuilder();
463
		$expr = $qb->expr();
464
465
		$qb->delete('share')
466
		   ->where($expr->eq('share_type', $qb->createNamedParameter(Share::SHARE_TYPE_CIRCLE)));
467
468
		return $qb;
469
	}
470
471
472
	/**
473
	 * generate and return a base sql request.
474
	 *
475
	 * @return \OCP\DB\QueryBuilder\IQueryBuilder
476
	 */
477 View Code Duplication
	protected function getBaseUpdateSql() {
478
		$qb = $this->dbConnection->getQueryBuilder();
479
		$expr = $qb->expr();
480
481
		$qb->update('share')
482
		   ->where($expr->eq('share_type', $qb->createNamedParameter(Share::SHARE_TYPE_CIRCLE)));
483
484
		return $qb;
485
	}
486
}
487