Completed
Push — master ( 912623...0260a2 )
by Maxence
13s queued 11s
created

CirclesRequestBuilder   A

Complexity

Total Complexity 30

Size/Duplication

Total Lines 380
Duplicated Lines 14.74 %

Coupling/Cohesion

Components 2
Dependencies 5

Importance

Changes 0
Metric Value
wmc 30
lcom 2
cbo 5
dl 56
loc 380
rs 10
c 0
b 0
f 0

15 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 7 7 1
A limitToNonPersonalCircle() 0 7 1
A limitRegardingCircleType() 0 21 3
A generateLimit() 0 11 1
A generateLimitPersonal() 0 16 3
A generateLimitSecret() 0 23 3
A generateLimitClosed() 11 11 2
A generateLimitPublic() 11 11 2
A leftJoinUserIdAsViewer() 0 27 2
A leftJoinOwner() 0 27 3
A getCirclesInsertSql() 7 7 1
A getCirclesUpdateSql() 10 10 1
A getCirclesDeleteSql() 10 10 1
A getCirclesSelectSql() 0 14 1
B parseCirclesSelectSql() 0 39 5

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
 * @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\Query\QueryBuilder;
32
use OCA\Circles\Exceptions\ConfigNoCircleAvailableException;
33
use OCA\Circles\Model\Circle;
34
use OCA\Circles\Model\Member;
35
use OCA\Circles\Service\ConfigService;
36
use OCA\Circles\Service\MiscService;
37
use OCA\Circles\Service\TimezoneService;
38
use OCP\DB\QueryBuilder\ICompositeExpression;
39
use OCP\DB\QueryBuilder\IQueryBuilder;
40
use OCP\IDBConnection;
41
use OCP\IL10N;
42
43
class CirclesRequestBuilder extends CoreRequestBuilder {
44
45
46
	/** @var MembersRequest */
47
	protected $membersRequest;
48
49
	/**
50
	 * CirclesRequestBuilder constructor.
51
	 *
52
	 * {@inheritdoc}
53
	 * @param MembersRequest $membersRequest
54
	 */
55 View Code Duplication
	public function __construct(
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...
56
		IL10N $l10n, IDBConnection $connection, MembersRequest $membersRequest,
57
		ConfigService $configService, TimezoneService $timezoneService, MiscService $miscService
58
	) {
59
		parent::__construct($l10n, $connection, $configService, $timezoneService, $miscService);
60
		$this->membersRequest = $membersRequest;
61
	}
62
63
64
	/**
65
	 * Limit the search to a non-personal circle
66
	 *
67
	 * @param IQueryBuilder $qb
68
	 */
69
	protected function limitToNonPersonalCircle(IQueryBuilder &$qb) {
70
		$expr = $qb->expr();
71
72
		$qb->andWhere(
73
			$expr->neq('c.type', $qb->createNamedParameter(Circle::CIRCLES_PERSONAL))
74
		);
75
	}
76
77
78
	/**
79
	 * @param IQueryBuilder $qb
80
	 * @param string $userId
81
	 * @param string $circleUniqueId
82
	 * @param $type
83
	 * @param $name
84
	 * @param bool $forceAll
85
	 *
86
	 * @throws ConfigNoCircleAvailableException
87
	 */
88
	protected function limitRegardingCircleType(
89
		IQueryBuilder &$qb, string $userId, $circleUniqueId, int $type,
90
		string $name, bool $forceAll = false
91
	) {
92
		$orTypes = $this->generateLimit($qb, $circleUniqueId, $userId, $type, $name, $forceAll);
93
		if (sizeof($orTypes) === 0) {
94
			throw new ConfigNoCircleAvailableException(
95
				$this->l10n->t(
96
					'You cannot use the Circles Application until your administrator has allowed at least one type of circles'
97
				)
98
			);
99
		}
100
101
		$orXTypes = $qb->expr()
102
					   ->orX();
103
		foreach ($orTypes as $orType) {
104
			$orXTypes->add($orType);
105
		}
106
107
		$qb->andWhere($orXTypes);
108
	}
109
110
111
	/**
112
	 * @param IQueryBuilder $qb
113
	 * @param string $circleUniqueId
114
	 * @param $userId
115
	 * @param $type
116
	 * @param $name
117
	 * @param bool $forceAll
118
	 *
119
	 * @return array
120
	 */
121
	private function generateLimit(
122
		IQueryBuilder &$qb, $circleUniqueId, $userId, $type, $name, $forceAll = false
123
	) {
124
		$orTypes = [];
125
		array_push($orTypes, $this->generateLimitPersonal($qb, $userId, $type, $forceAll));
126
		array_push($orTypes, $this->generateLimitSecret($qb, $circleUniqueId, $type, $name));
127
		array_push($orTypes, $this->generateLimitClosed($qb, $type));
128
		array_push($orTypes, $this->generateLimitPublic($qb, $type));
129
130
		return array_filter($orTypes);
131
	}
132
133
134
	/**
135
	 * @param IQueryBuilder $qb
136
	 * @param int|string $userId
137
	 * @param int $type
138
	 * @param bool $forceAll
139
	 *
140
	 * @return ICompositeExpression
141
	 */
142
	private function generateLimitPersonal(IQueryBuilder $qb, $userId, $type, $forceAll = false) {
143
		if (!(Circle::CIRCLES_PERSONAL & (int)$type)) {
144
			return null;
145
		}
146
		$expr = $qb->expr();
147
148
		$andX = $expr->andX();
149
		$andX->add($expr->eq('c.type', $qb->createNamedParameter(Circle::CIRCLES_PERSONAL)));
150
		$andX->add($expr->eq('o.instance', $qb->createNamedParameter('')));
151
152
		if (!$forceAll) {
153
			$andX->add($expr->eq('o.user_id', $qb->createNamedParameter((string)$userId)));
154
		}
155
156
		return $andX;
157
	}
158
159
160
	/**
161
	 * @param IQueryBuilder $qb
162
	 * @param string $circleUniqueId
163
	 * @param int $type
164
	 * @param string $name
165
	 *
166
	 * @return string
167
	 */
168
	private function generateLimitSecret(IQueryBuilder $qb, $circleUniqueId, $type, $name) {
169
		if (!(Circle::CIRCLES_SECRET & (int)$type)) {
170
			return null;
171
		}
172
		$expr = $qb->expr();
173
174
		$orX = $expr->orX($expr->gte('u.level', $qb->createNamedParameter(Member::LEVEL_MEMBER)));
175
		$orX->add($expr->eq('c.name', $qb->createNamedParameter($name)))
176
			->add($expr->eq('c.alt_name', $qb->createNamedParameter($name)))
177
			->add($expr->eq('c.unique_id', $qb->createNamedParameter($circleUniqueId)));
178
179
		if ($this->leftJoinedNCGroupAndUser) {
180
			$orX->add($expr->gte('g.level', $qb->createNamedParameter(Member::LEVEL_MEMBER)));
181
		}
182
183
		/** @noinspection PhpMethodParametersCountMismatchInspection */
184
		$sqb = $expr->andX(
185
			$expr->eq('c.type', $qb->createNamedParameter(Circle::CIRCLES_SECRET)),
186
			$expr->orX($orX)
187
		);
188
189
		return $sqb;
190
	}
191
192
193
	/**
194
	 * @param IQueryBuilder $qb
195
	 * @param int $type
196
	 *
197
	 * @return string
198
	 */
199 View Code Duplication
	private function generateLimitClosed(IQueryBuilder $qb, $type) {
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...
200
		if (!(Circle::CIRCLES_CLOSED & (int)$type)) {
201
			return null;
202
		}
203
204
		return $qb->expr()
205
				  ->eq(
206
					  'c.type',
207
					  $qb->createNamedParameter(Circle::CIRCLES_CLOSED)
208
				  );
209
	}
210
211
212
	/**
213
	 * @param IQueryBuilder $qb
214
	 * @param int $type
215
	 *
216
	 * @return string
217
	 */
218 View Code Duplication
	private function generateLimitPublic(IQueryBuilder $qb, $type) {
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...
219
		if (!(Circle::CIRCLES_PUBLIC & (int)$type)) {
220
			return null;
221
		}
222
223
		return $qb->expr()
224
				  ->eq(
225
					  'c.type',
226
					  $qb->createNamedParameter(Circle::CIRCLES_PUBLIC)
227
				  );
228
	}
229
230
231
	/**
232
	 * add a request to the members list, using the current user ID.
233
	 * will returns level and stuff.
234
	 *
235
	 * @param IQueryBuilder $qb
236
	 * @param string $userId
237
	 * @param int $type
238
	 * @param string $instanceId
239
	 */
240
	public function leftJoinUserIdAsViewer(IQueryBuilder &$qb, string $userId, int $type, string $instanceId
241
	) {
242
		if ($qb->getType() !== QueryBuilder::SELECT) {
243
			return;
244
		}
245
246
		$expr = $qb->expr();
247
		$pf = '' . $this->default_select_alias . '.';
248
249
		/** @noinspection PhpMethodParametersCountMismatchInspection */
250
		$qb->selectAlias('u.user_id', 'viewer_userid')
251
		   ->selectAlias('u.user_type', 'viewer_type')
252
		   ->selectAlias('u.instance', 'viewer_instance')
253
		   ->selectAlias('u.status', 'viewer_status')
254
		   ->selectAlias('u.member_id', 'viewer_member_id')
255
		   ->selectAlias('u.cached_name', 'viewer_cached_name')
256
		   ->selectAlias('u.level', 'viewer_level')
257
		   ->leftJoin(
258
			   $this->default_select_alias, CoreRequestBuilder::TABLE_MEMBERS, 'u',
259
			   $expr->andX(
260
				   $expr->eq('u.circle_id', $pf . 'unique_id'),
261
				   $expr->eq('u.user_id', $qb->createNamedParameter($userId)),
262
				   $expr->eq('u.instance', $qb->createNamedParameter($instanceId)),
263
				   $expr->eq('u.user_type', $qb->createNamedParameter($type))
264
			   )
265
		   );
266
	}
267
268
269
	/**
270
	 * Left Join members table to get the owner of the circle.
271
	 *
272
	 * @param IQueryBuilder $qb
273
	 * @param string $ownerId
274
	 */
275
	public function leftJoinOwner(IQueryBuilder &$qb, string $ownerId = '') {
276
277
		if ($qb->getType() !== QueryBuilder::SELECT) {
278
			return;
279
		}
280
281
		$expr = $qb->expr();
282
		$pf = $this->default_select_alias . '.';
283
284
		/** @noinspection PhpMethodParametersCountMismatchInspection */
285
		$qb->selectAlias('o.user_id', 'owner_userid')
286
		   ->selectAlias('o.instance', 'owner_instance')
287
		   ->selectAlias('o.status', 'owner_status')
288
		   ->selectAlias('o.level', 'owner_level')
289
		   ->leftJoin(
290
			   $this->default_select_alias, CoreRequestBuilder::TABLE_MEMBERS, 'o',
291
			   $expr->andX(
292
				   $expr->eq('o.circle_id', $pf . 'unique_id'),
293
				   $expr->eq('o.level', $qb->createNamedParameter(Member::LEVEL_OWNER)),
294
				   $expr->eq('o.user_type', $qb->createNamedParameter(Member::TYPE_USER))
295
			   )
296
		   );
297
298
		if ($ownerId !== '') {
299
			$qb->andWhere($expr->eq('o.user_id', $qb->createNamedParameter($ownerId)));
300
		}
301
	}
302
303
304
	/**
305
	 * Base of the Sql Insert request for Shares
306
	 *
307
	 *
308
	 * @return IQueryBuilder
309
	 */
310 View Code Duplication
	protected function getCirclesInsertSql() {
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...
311
		$qb = $this->dbConnection->getQueryBuilder();
312
		$qb->insert(self::TABLE_CIRCLES)
313
		   ->setValue('creation', $qb->createNamedParameter($this->timezoneService->getUTCDate()));
314
315
		return $qb;
316
	}
317
318
319
	/**
320
	 * Base of the Sql Update request for Shares
321
	 *
322
	 * @param int $uniqueId
323
	 *
324
	 * @return IQueryBuilder
325
	 */
326 View Code Duplication
	protected function getCirclesUpdateSql($uniqueId) {
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...
327
		$qb = $this->dbConnection->getQueryBuilder();
328
		$qb->update(self::TABLE_CIRCLES)
329
		   ->where(
330
			   $qb->expr()
331
				  ->eq('unique_id', $qb->createNamedParameter($uniqueId))
332
		   );
333
334
		return $qb;
335
	}
336
337
338
	/**
339
	 * Base of the Sql Delete request
340
	 *
341
	 * @param string $circleUniqueId
342
	 *
343
	 * @return IQueryBuilder
344
	 */
345 View Code Duplication
	protected function getCirclesDeleteSql($circleUniqueId) {
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...
346
		$qb = $this->dbConnection->getQueryBuilder();
347
		$qb->delete(self::TABLE_CIRCLES)
348
		   ->where(
349
			   $qb->expr()
350
				  ->eq('unique_id', $qb->createNamedParameter($circleUniqueId))
351
		   );
352
353
		return $qb;
354
	}
355
356
357
	/**
358
	 * @return IQueryBuilder
359
	 */
360
	protected function getCirclesSelectSql() {
361
		$qb = $this->dbConnection->getQueryBuilder();
362
363
		/** @noinspection PhpMethodParametersCountMismatchInspection */
364
		$qb->selectDistinct('c.unique_id')
365
		   ->addSelect(
366
			   'c.id', 'c.name', 'c.alt_name', 'c.description', 'c.settings', 'c.type', 'contact_addressbook',
367
			   'contact_groupname', 'c.creation'
368
		   )
369
		   ->from(CoreRequestBuilder::TABLE_CIRCLES, 'c');
370
		$this->default_select_alias = 'c';
371
372
		return $qb;
373
	}
374
375
376
	/**
377
	 * @param array $data
378
	 *
379
	 * @return Circle
380
	 */
381
	protected function parseCirclesSelectSql($data) {
382
383
		$circle = new Circle();
384
		$circle->setId($data['id']);
385
		$circle->setUniqueId($data['unique_id']);
386
		$circle->setName($data['name']);
387
		$circle->setAltName($data['alt_name']);
388
		$circle->setDescription($data['description']);
389
		if ($data['contact_addressbook'] !== null) {
390
			$circle->setContactAddressBook($data['contact_addressbook']);
391
		}
392
		if ($data['contact_groupname'] !== null) {
393
			$circle->setContactGroupName($data['contact_groupname']);
394
		}
395
		$circle->setSettings($data['settings']);
396
		$circle->setType($data['type']);
397
		$circle->setCreation($data['creation']);
398
399
		if (key_exists('viewer_level', $data)) {
400
			$user = new Member($data['viewer_userid'], Member::TYPE_USER, $circle->getUniqueId());
401
			$user->setStatus($data['viewer_status']);
402
			$user->setMemberId($data['viewer_member_id']);
403
			$user->setCachedName($data['viewer_cached_name']);
404
			$user->setType($data['viewer_type']);
405
			$user->setInstance($data['viewer_instance']);
406
			$user->setLevel($data['viewer_level']);
407
			$circle->setViewer($user);
408
		}
409
410
		if (key_exists('owner_level', $data)) {
411
			$owner = new Member($data['owner_userid'], Member::TYPE_USER, $circle->getUniqueId());
412
			$owner->setStatus($data['owner_status']);
413
			$owner->setInstance($data['owner_instance']);
414
			$owner->setLevel($data['owner_level']);
415
			$circle->setOwner($owner);
416
		}
417
418
		return $circle;
419
	}
420
421
422
}
423