Completed
Push — master ( a32ba7...f7592a )
by Maxence
05:20
created

CircleProviderRequestBuilder   A

Complexity

Total Complexity 35

Size/Duplication

Total Lines 503
Duplicated Lines 16.7 %

Coupling/Cohesion

Components 1
Dependencies 1

Importance

Changes 0
Metric Value
wmc 35
lcom 1
cbo 1
dl 84
loc 503
rs 9
c 0
b 0
f 0

23 Methods

Rating   Name   Duplication   Size   Complexity  
A findShareParentSql() 0 9 1
A limitToCircles() 15 15 3
A limitToShare() 0 6 2
A limitToShareParent() 0 5 1
A limitToShareChildren() 0 10 2
A limitToShareAndChildren() 0 12 2
A limitToFiles() 15 15 3
A limitToPage() 0 7 2
A limitToShareOwner() 0 16 3
B linkCircleField() 0 24 2
A exprLinkToMemberAsCircleMember() 0 19 1
A linkToMember() 0 14 2
A linkToCircleOwner() 15 15 1
A exprLinkToMemberAsGroupMember() 21 21 1
A joinCircleMembers() 0 13 1
A linkToFileCache() 0 18 1
A getBaseInsertSql() 0 17 1
A getBaseSelectSql() 0 18 1
A getAccessListBaseSelectSql() 0 9 1
A getCompleteSelectSql() 0 21 1
A joinShare() 0 15 1
A getBaseDeleteSql() 9 9 1
A getBaseUpdateSql() 9 9 1

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

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
 * @author Vinicius Cubas Brand <[email protected]>
11
 * @author Daniel Tygel <[email protected]>
12
 *
13
 * @copyright 2017
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
namespace OCA\Circles\Db;
32
33
34
use Doctrine\DBAL\Query\QueryBuilder;
35
use OCA\Circles\Model\Circle;
36
use OCA\Circles\Model\Member;
37
use OCP\DB\QueryBuilder\IQueryBuilder;
38
use OCP\Share;
39
use OCP\Share\IShare;
40
41
class CircleProviderRequestBuilder extends CoreRequestBuilder {
42
43
44
	/**
45
	 * returns the SQL request to get a specific share from the fileId and circleId
46
	 *
47
	 * @param int $fileId
48
	 * @param int $circleId
49
	 *
50
	 * @return IQueryBuilder
51
	 */
52
	protected function findShareParentSql($fileId, $circleId) {
53
54
		$qb = $this->getBaseSelectSql();
55
		$this->limitToShareParent($qb);
56
		$this->limitToCircles($qb, [$circleId]);
57
		$this->limitToFiles($qb, $fileId);
58
59
		return $qb;
60
	}
61
62
63
	/**
64
	 * Limit the request to the given Circles.
65
	 *
66
	 * @param IQueryBuilder $qb
67
	 * @param array $circleUniqueIds
68
	 */
69 View Code Duplication
	protected function limitToCircles(IQueryBuilder &$qb, $circleUniqueIds) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
70
71
		if (!is_array($circleUniqueIds)) {
72
			$circleUniqueIds = array($circleUniqueIds);
73
		}
74
75
		$expr = $qb->expr();
76
		$pf = ($qb->getType() === QueryBuilder::SELECT) ? 's.' : '';
77
		$qb->andWhere(
78
			$expr->in(
79
				$pf . 'share_with',
80
				$qb->createNamedParameter($circleUniqueIds, IQueryBuilder::PARAM_STR_ARRAY)
81
			)
82
		);
83
	}
84
85
86
	/**
87
	 * Limit the request to the Share by its Id.
88
	 *
89
	 * @param IQueryBuilder $qb
90
	 * @param $shareId
91
	 */
92
	protected function limitToShare(IQueryBuilder &$qb, $shareId) {
93
		$expr = $qb->expr();
94
		$pf = ($qb->getType() === QueryBuilder::SELECT) ? 's.' : '';
95
96
		$qb->andWhere($expr->eq($pf . 'id', $qb->createNamedParameter($shareId)));
97
	}
98
99
100
	/**
101
	 * Limit the request to the top share (no children)
102
	 *
103
	 * @param IQueryBuilder $qb
104
	 */
105
	protected function limitToShareParent(IQueryBuilder &$qb) {
106
		$expr = $qb->expr();
107
108
		$qb->andWhere($expr->isNull('parent'));
109
	}
110
111
112
	/**
113
	 * limit the request to the children of a share
114
	 *
115
	 * @param IQueryBuilder $qb
116
	 * @param $userId
117
	 * @param int $parentId
118
	 */
119
	protected function limitToShareChildren(IQueryBuilder &$qb, $userId, $parentId = -1) {
120
		$expr = $qb->expr();
121
		$qb->andWhere($expr->eq('share_with', $qb->createNamedParameter($userId)));
122
123
		if ($parentId > -1) {
124
			$qb->andWhere($expr->eq('parent', $qb->createNamedParameter($parentId)));
125
		} else {
126
			$qb->andWhere($expr->isNotNull('parent'));
127
		}
128
	}
129
130
131
	/**
132
	 * limit the request to the share itself AND its children.
133
	 * perfect if you want to delete everything related to a share
134
	 *
135
	 * @param IQueryBuilder $qb
136
	 * @param $circleId
137
	 */
138
	protected function limitToShareAndChildren(IQueryBuilder &$qb, $circleId) {
139
		$expr = $qb->expr();
140
		$pf = ($qb->getType() === QueryBuilder::SELECT) ? 's.' : '';
141
142
		/** @noinspection PhpMethodParametersCountMismatchInspection */
143
		$qb->andWhere(
144
			$expr->orX(
145
				$expr->eq($pf . 'parent', $qb->createNamedParameter($circleId)),
146
				$expr->eq($pf . 'id', $qb->createNamedParameter($circleId))
147
			)
148
		);
149
	}
150
151
152
	/**
153
	 * limit the request to a fileId.
154
	 *
155
	 * @param IQueryBuilder $qb
156
	 * @param $files
157
	 */
158 View Code Duplication
	protected function limitToFiles(IQueryBuilder &$qb, $files) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
159
160
		if (!is_array($files)) {
161
			$files = array($files);
162
		}
163
164
		$expr = $qb->expr();
165
		$pf = ($qb->getType() === QueryBuilder::SELECT) ? 's.' : '';
166
		$qb->andWhere(
167
			$expr->in(
168
				$pf . 'file_source',
169
				$qb->createNamedParameter($files, IQueryBuilder::PARAM_INT_ARRAY)
170
			)
171
		);
172
	}
173
174
175
	/**
176
	 * @param IQueryBuilder $qb
177
	 * @param int $limit
178
	 * @param int $offset
179
	 */
180
	protected function limitToPage(IQueryBuilder &$qb, $limit = -1, $offset = 0) {
181
		if ($limit !== -1) {
182
			$qb->setMaxResults($limit);
183
		}
184
185
		$qb->setFirstResult($offset);
186
	}
187
188
189
	/**
190
	 * limit the request to a userId
191
	 *
192
	 * @param IQueryBuilder $qb
193
	 * @param string $userId
194
	 * @param bool $reShares
195
	 */
196
	protected function limitToShareOwner(IQueryBuilder &$qb, $userId, $reShares = false) {
197
		$expr = $qb->expr();
198
		$pf = ($qb->getType() === QueryBuilder::SELECT) ? 's.' : '';
199
200
		if ($reShares === false) {
201
			$qb->andWhere($expr->eq($pf . 'uid_initiator', $qb->createNamedParameter($userId)));
202
		} else {
203
			/** @noinspection PhpMethodParametersCountMismatchInspection */
204
			$qb->andWhere(
205
				$expr->orX(
206
					$expr->eq($pf . 'uid_owner', $qb->createNamedParameter($userId)),
207
					$expr->eq($pf . 'uid_initiator', $qb->createNamedParameter($userId))
208
				)
209
			);
210
		}
211
	}
212
213
214
	/**
215
	 * link circle field
216
	 *
217
	 * @deprecated
218
	 *
219
	 * @param IQueryBuilder $qb
220
	 * @param int $shareId
221
	 */
222
	protected function linkCircleField(IQueryBuilder &$qb, $shareId = -1) {
223
		$expr = $qb->expr();
224
225
		$qb->from(CoreRequestBuilder::TABLE_CIRCLES, 'c');
226
227
		$tmpOrX = $expr->eq(
228
			's.share_with',
229
			$qb->createFunction('SUBSTR(`c`.`unique_id`, 1, ' . Circle::SHORT_UNIQUE_ID_LENGTH . ')')
230
		);
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
	}
246
247
248
	/**
249
	 * @param IQueryBuilder $qb
250
	 */
251 View Code Duplication
	protected function linkToCircleOwner(IQueryBuilder &$qb) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
252
		$expr = $qb->expr();
253
254
		$qb->selectAlias('mo.user_id', 'circle_owner');
255
		/** @noinspection PhpMethodParametersCountMismatchInspection */
256
		$qb->leftJoin(
257
			'c', CoreRequestBuilder::TABLE_MEMBERS, 'mo', $expr->andX(
258
			$expr->eq(
259
				'mo.circle_id',
260
        $qb->createFunction('SUBSTR(`c`.`unique_id`, 1, ' . Circle::SHORT_UNIQUE_ID_LENGTH . ')')
261
			), $expr->eq('mo.user_type', $qb->createNamedParameter(Member::TYPE_USER)),
262
			$expr->eq('mo.level', $qb->createNamedParameter(Member::LEVEL_OWNER))
263
		)
264
		);
265
	}
266
267
268
	/**
269
	 * Link to member (userId) of circle
270
	 *
271
	 * @param IQueryBuilder $qb
272
	 * @param string $userId
273
	 * @param bool $groupMemberAllowed
274
	 */
275
	protected function linkToMember(IQueryBuilder &$qb, $userId, $groupMemberAllowed) {
276
		$expr = $qb->expr();
277
278
		$qb->from(CoreRequestBuilder::TABLE_MEMBERS, 'm');
279
280
		$orX = $expr->orX();
281
		$orX->add($this->exprLinkToMemberAsCircleMember($qb, $userId));
282
		if ($groupMemberAllowed === true) {
283
			$orX->add($this->exprLinkToMemberAsGroupMember($qb, $userId));
284
		}
285
286
		$qb->andWhere($orX);
287
288
	}
289
290
291
	/**
292
	 * generate CompositeExpression to link to a Member as a Real Circle Member
293
	 *
294
	 * @param IQueryBuilder $qb
295
	 * @param string $userId
296
	 *
297
	 * @return \OCP\DB\QueryBuilder\ICompositeExpression
298
	 */
299
	private function exprLinkToMemberAsCircleMember(IQueryBuilder &$qb, $userId) {
300
301
		$expr = $qb->expr();
302
		$andX = $expr->andX();
303
304
		$andX->add($expr->eq('m.user_id', $qb->createNamedParameter($userId)));
305
		$andX->add($expr->gt('m.level', $qb->createNamedParameter(0)));
306
		$andX->add($expr->eq('m.user_type', $qb->createNamedParameter(Member::TYPE_USER)));
307
		$andX->add(
308
			$expr->eq(
309
				'm.circle_id',
310
				$qb->createFunction(
311
					'SUBSTR(`c`.`unique_id`, 1, ' . Circle::SHORT_UNIQUE_ID_LENGTH . ')'
312
				)
313
			)
314
		);
315
316
		return $andX;
317
	}
318
319
320
	/**
321
	 * generate CompositeExpression to link to a Member as a Group Member (core NC)
322
	 *
323
	 * @param IQueryBuilder $qb
324
	 * @param string $userId
325
	 *
326
	 * @return \OCP\DB\QueryBuilder\ICompositeExpression
327
	 */
328 View Code Duplication
	private function exprLinkToMemberAsGroupMember(IQueryBuilder &$qb, $userId) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
329
		$expr = $qb->expr();
330
331
		/** @noinspection PhpMethodParametersCountMismatchInspection */
332
		$qb->leftJoin(
333
			'c', CoreRequestBuilder::TABLE_GROUPS, 'g',
334
			$expr->andX(
335
				$expr->eq(
336
					'g.circle_id',
337
					$qb->createFunction('SUBSTR(`c`.`unique_id`, 1, ' . Circle::SHORT_UNIQUE_ID_LENGTH . ')')
338
				)
339
			)
340
		);
341
342
		$qb->leftJoin(
343
			'g', CoreRequestBuilder::NC_TABLE_GROUP_USER, 'ncgu',
344
			$expr->eq('ncgu.gid', 'g.group_id')
345
		);
346
347
		return $expr->andX($expr->eq('ncgu.uid', $qb->createNamedParameter($userId)));
348
	}
349
350
351
	/**
352
	 * Link to all members of circle
353
	 *
354
	 * @param IQueryBuilder $qb
355
	 */
356
	protected function joinCircleMembers(IQueryBuilder &$qb) {
357
		$expr = $qb->expr();
358
359
		/** @noinspection PhpMethodParametersCountMismatchInspection */
360
		$qb->addSelect('m.user_id')
361
		   ->from(CoreRequestBuilder::TABLE_MEMBERS, 'm')
362
		   ->andWhere(
363
			   $expr->andX(
364
				   $expr->eq('s.share_with', 'm.circle_id'),
365
				   $expr->eq('m.user_type', $qb->createNamedParameter(Member::TYPE_USER))
366
			   )
367
		   );
368
	}
369
370
371
	/**
372
	 * Link to storage/filecache
373
	 *
374
	 * @param IQueryBuilder $qb
375
	 * @param string $userId
376
	 */
377
	protected function linkToFileCache(IQueryBuilder &$qb, $userId) {
378
		$expr = $qb->expr();
379
380
		/** @noinspection PhpMethodParametersCountMismatchInspection */
381
		$qb->leftJoin('s', 'filecache', 'f', $expr->eq('s.file_source', 'f.fileid'))
382
		   ->leftJoin('f', 'storages', 'st', $expr->eq('f.storage', 'st.numeric_id'))
383
		   ->leftJoin(
384
			   's', 'share', 's2', $expr->andX(
385
			   $expr->eq('s.id', 's2.parent'),
386
			   $expr->eq('s2.share_with', $qb->createNamedParameter($userId))
387
		   )
388
		   );
389
390
		$qb->selectAlias('s2.id', 'parent_id');
391
		$qb->selectAlias('s2.file_target', 'parent_target');
392
		$qb->selectAlias('s2.permissions', 'parent_perms');
393
394
	}
395
396
397
	/**
398
	 * add share to the database and return the ID
399
	 *
400
	 * @param IShare $share
401
	 *
402
	 * @return IQueryBuilder
403
	 */
404
	protected function getBaseInsertSql($share) {
405
		$qb = $this->dbConnection->getQueryBuilder();
406
		$qb->insert('share')
407
		   ->setValue('share_type', $qb->createNamedParameter(Share::SHARE_TYPE_CIRCLE))
408
		   ->setValue('item_type', $qb->createNamedParameter($share->getNodeType()))
409
		   ->setValue('item_source', $qb->createNamedParameter($share->getNodeId()))
410
		   ->setValue('file_source', $qb->createNamedParameter($share->getNodeId()))
411
		   ->setValue('file_target', $qb->createNamedParameter($share->getTarget()))
412
		   ->setValue('share_with', $qb->createNamedParameter($share->getSharedWith()))
413
		   ->setValue('uid_owner', $qb->createNamedParameter($share->getShareOwner()))
414
		   ->setValue('uid_initiator', $qb->createNamedParameter($share->getSharedBy()))
415
		   ->setValue('permissions', $qb->createNamedParameter($share->getPermissions()))
416
		   ->setValue('token', $qb->createNamedParameter($share->getToken()))
417
		   ->setValue('stime', $qb->createFunction('UNIX_TIMESTAMP()'));
418
419
		return $qb;
420
	}
421
422
423
	/**
424
	 * generate and return a base sql request.
425
	 *
426
	 * @param int $shareId
427
	 *
428
	 * @return IQueryBuilder
429
	 */
430
	protected function getBaseSelectSql($shareId = -1) {
431
		$qb = $this->dbConnection->getQueryBuilder();
432
433
		/** @noinspection PhpMethodParametersCountMismatchInspection */
434
		$qb->select(
435
			's.id', 's.share_type', 's.share_with', 's.uid_owner', 's.uid_initiator',
436
			's.parent', 's.item_type', 's.item_source', 's.item_target', 's.permissions', 's.stime',
437
			's.accepted', 's.expiration',
438
			's.token', 's.mail_send', 'c.type AS circle_type', 'c.name AS circle_name'
439
		);
440
		$this->linkToCircleOwner($qb);
441
		$this->joinShare($qb);
442
443
		// TODO: Left-join circle and REMOVE this line
444
		$this->linkCircleField($qb, $shareId);
0 ignored issues
show
Deprecated Code introduced by
The method OCA\Circles\Db\CirclePro...lder::linkCircleField() has been deprecated.

This method has been deprecated.

Loading history...
445
446
		return $qb;
447
	}
448
449
450
	/**
451
	 * Generate and return a base sql request
452
	 * This one should be used to retrieve a complete list of users (ie. access list).
453
	 *
454
	 * @return IQueryBuilder
455
	 */
456
	protected function getAccessListBaseSelectSql() {
457
		$qb = $this->dbConnection->getQueryBuilder();
458
459
		/** @noinspection PhpMethodParametersCountMismatchInspection */
460
		$this->joinCircleMembers($qb);
461
		$this->joinShare($qb);
462
463
		return $qb;
464
	}
465
466
467
	/**
468
	 * @return IQueryBuilder
469
	 */
470
	protected function getCompleteSelectSql() {
471
		$qb = $this->dbConnection->getQueryBuilder();
472
473
		/** @noinspection PhpMethodParametersCountMismatchInspection */
474
		$qb->selectDistinct('s.id')
475
		   ->addSelect(
476
			   's.*', 'f.fileid', 'f.path', 'f.permissions AS f_permissions', 'f.storage',
477
			   'f.path_hash', 'f.parent AS f_parent', 'f.name', 'f.mimetype', 'f.mimepart',
478
			   'f.size', 'f.mtime', 'f.storage_mtime', 'f.encrypted', 'f.unencrypted_size',
479
			   'f.etag', 'f.checksum', 'c.type AS circle_type', 'c.name AS circle_name'
480
		   )
481
		   ->selectAlias('st.id', 'storage_string_id');
482
483
484
		$this->linkToCircleOwner($qb);
485
		$this->joinShare($qb);
486
		$this->linkCircleField($qb);
0 ignored issues
show
Deprecated Code introduced by
The method OCA\Circles\Db\CirclePro...lder::linkCircleField() has been deprecated.

This method has been deprecated.

Loading history...
487
488
489
		return $qb;
490
	}
491
492
493
	/**
494
	 * @param IQueryBuilder $qb
495
	 */
496
	private function joinShare(IQueryBuilder &$qb) {
497
		$expr = $qb->expr();
498
499
		/** @noinspection PhpMethodParametersCountMismatchInspection */
500
		$qb->addSelect('s.file_source', 's.file_target');
501
		/** @noinspection PhpMethodParametersCountMismatchInspection */
502
		$qb->from('share', 's')
503
		   ->andWhere($expr->eq('s.share_type', $qb->createNamedParameter(Share::SHARE_TYPE_CIRCLE)))
504
		   ->andWhere(
505
			   $expr->orX(
506
				   $expr->eq('s.item_type', $qb->createNamedParameter('file')),
507
				   $expr->eq('s.item_type', $qb->createNamedParameter('folder'))
508
			   )
509
		   );
510
	}
511
512
513
	/**
514
	 * generate and return a base sql request.
515
	 *
516
	 * @return \OCP\DB\QueryBuilder\IQueryBuilder
517
	 */
518 View Code Duplication
	protected function getBaseDeleteSql() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
519
		$qb = $this->dbConnection->getQueryBuilder();
520
		$expr = $qb->expr();
521
522
		$qb->delete('share')
523
		   ->where($expr->eq('share_type', $qb->createNamedParameter(Share::SHARE_TYPE_CIRCLE)));
524
525
		return $qb;
526
	}
527
528
529
	/**
530
	 * generate and return a base sql request.
531
	 *
532
	 * @return \OCP\DB\QueryBuilder\IQueryBuilder
533
	 */
534 View Code Duplication
	protected function getBaseUpdateSql() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
535
		$qb = $this->dbConnection->getQueryBuilder();
536
		$expr = $qb->expr();
537
538
		$qb->update('share')
539
		   ->where($expr->eq('share_type', $qb->createNamedParameter(Share::SHARE_TYPE_CIRCLE)));
540
541
		return $qb;
542
	}
543
}
544