Passed
Pull Request — master (#1016)
by René
05:15
created

OptionService   B

Complexity

Total Complexity 48

Size/Duplication

Total Lines 326
Duplicated Lines 0 %

Test Coverage

Coverage 0%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 48
eloc 120
c 1
b 0
f 0
dl 0
loc 326
ccs 0
cts 165
cp 0
rs 8.5599

11 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 14 1
A list() 0 10 3
A add() 0 12 2
C setOrder() 0 53 17
A confirm() 0 14 3
A getHighestOrder() 0 8 3
A clone() 0 17 3
B setOption() 0 19 7
A reorder() 0 22 5
A update() 0 12 2
A delete() 0 10 2

How to fix   Complexity   

Complex Class

Complex classes like OptionService often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use OptionService, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * @copyright Copyright (c) 2017 Vinzenz Rosenkranz <[email protected]>
4
 *
5
 * @author René Gieling <[email protected]>
6
 *
7
 * @license GNU AGPL version 3 or any later version
8
 *
9
 *  This program is free software: you can redistribute it and/or modify
10
 *  it under the terms of the GNU Affero General Public License as
11
 *  published by the Free Software Foundation, either version 3 of the
12
 *  License, or (at your option) any later version.
13
 *
14
 *  This program is distributed in the hope that it will be useful,
15
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
 *  GNU Affero General Public License for more details.
18
 *
19
 *  You should have received a copy of the GNU Affero General Public License
20
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
21
 *
22
 */
23
24
namespace OCA\Polls\Service;
25
26
use Exception;
27
use OCP\AppFramework\Db\DoesNotExistException;
28
use OCA\Polls\Exceptions\NotAuthorizedException;
29
use OCA\Polls\Exceptions\BadRequestException;
30
31
use OCA\Polls\Db\OptionMapper;
32
use OCA\Polls\Db\Option;
33
use OCA\Polls\Db\PollMapper;
34
use OCA\Polls\Db\Poll;
35
use OCA\Polls\Service\LogService;
36
use OCA\Polls\Model\Acl;
37
38
class OptionService {
39
40
	/** @var OptionMapper */
41
	private $optionMapper;
42
43
	/** @var Option */
44
	private $option;
45
46
	/** @var PollMapper */
47
	private $pollMapper;
48
49
	/** @var Poll */
50
	private $poll;
51
52
	/** @var LogService */
53
	private $logService;
54
55
	/** @var Acl */
56
	private $acl;
57
58
	/**
59
	 * OptionController constructor.
60
	 * @param OptionMapper $optionMapper
61
	 * @param Option $option
62
	 * @param PollMapper $pollMapper
63
	 * @param Poll $poll
64
	 * @param LogService $logService
65
	 * @param Acl $acl
66
	 */
67
68
	public function __construct(
69
		OptionMapper $optionMapper,
70
		Option $option,
71
		PollMapper $pollMapper,
72
   	 	Poll $poll,
73
		LogService $logService,
74
		Acl $acl
75
	) {
76
		$this->optionMapper = $optionMapper;
77
		$this->option = $option;
78
		$this->pollMapper = $pollMapper;
79
		$this->poll = $poll;
80
		$this->logService = $logService;
81
		$this->acl = $acl;
82
	}
83
84
	/**
85
	 * Get all options of given poll
86
	 * @NoAdminRequired
87
	 * @param int $pollId
88
	 * @param string $token
89
	 * @return array Array of Option objects
90
	 * @throws NotAuthorizedException
91
	 */
92
	public function list($pollId = 0, $token = '') {
93
94
		if (!$this->acl->setPollIdOrToken($pollId, $token)->getAllowView()) {
95
			throw new NotAuthorizedException;
96
		}
97
98
		try {
99
			return $this->optionMapper->findByPoll($pollId);
100
		} catch (DoesNotExistException $e) {
101
			return [];
102
		}
103
	}
104
105
106
	/**
107
	 * Add a new option
108
	 * @NoAdminRequired
109
	 * @param int $pollId
110
	 * @param int $timestamp
111
	 * @param string $pollOptionText
112
	 * @return Option
113
	 * @throws NotAuthorizedException
114
	 */
115
	public function add($pollId, $timestamp = 0, $pollOptionText = '') {
116
117
		$this->poll = $this->pollMapper->find($pollId);
118
		if (!$this->acl->setPollId($pollId)->getAllowEdit()) {
119
			throw new NotAuthorizedException;
120
		}
121
122
		$this->option = new Option();
123
		$this->option->setPollId($pollId);
124
		$this->setOption($timestamp, $pollOptionText, 0);
125
126
		return $this->optionMapper->insert($this->option);
127
	}
128
129
	/**
130
	 * Update option
131
	 * @NoAdminRequired
132
	 * @param int $optionId
133
	 * @param int $timestamp
134
	 * @param string $pollOptionText
135
	 * @param int $order
136
	 * @return Option
137
	 * @throws NotAuthorizedException
138
	 */
139
	public function update($optionId, $timestamp = 0, $pollOptionText = '', $order = 0) {
140
141
		$this->option = $this->optionMapper->find($optionId);
142
		$this->poll = $this->pollMapper->find($this->option->getPollId());
143
144
		if (!$this->acl->setPollId($this->option->getPollId())->getAllowEdit()) {
145
			throw new NotAuthorizedException;
146
		}
147
148
		$this->setOption($timestamp, $pollOptionText, $order);
149
150
		return $this->optionMapper->update($this->option);
151
	}
152
153
	/**
154
	 * Delete option
155
	 * @NoAdminRequired
156
	 * @param int $optionId
157
	 * @return Option deleted Option
158
	 * @throws NotAuthorizedException
159
	 */
160
	public function delete($optionId) {
161
		$this->option = $this->optionMapper->find($optionId);
162
163
		if (!$this->acl->setPollId($this->option->getPollId())->getAllowEdit()) {
164
			throw new NotAuthorizedException;
165
		}
166
167
		$this->optionMapper->delete($this->option);
168
169
		return $this->option;
170
	}
171
172
	/**
173
	 * Switch optoin confirmation
174
	 * @NoAdminRequired
175
	 * @param int $optionId
176
	 * @return Option confirmed Option
177
	 * @throws NotAuthorizedException
178
	 */
179
	public function confirm($optionId) {
180
		$this->option = $this->optionMapper->find($optionId);
181
182
		if (!$this->acl->setPollId($this->option->getPollId())->getAllowEdit()) {
183
			throw new NotAuthorizedException;
184
		}
185
186
		if ($this->option->getConfirmed()) {
187
			$this->option->setConfirmed(0);
188
		} else {
189
			$this->option->setConfirmed(time());
190
		}
191
192
		return $this->optionMapper->update($this->option);
193
	}
194
195
	/**
196
	 * Copy options from $fromPoll to $toPoll
197
	 * @NoAdminRequired
198
	 * @param int $fromPollId
199
	 * @param int $toPollId
200
	 * @return array Array of Option objects
201
	 * @throws NotAuthorizedException
202
	 */
203
	public function clone($fromPollId, $toPollId) {
204
205
		if (!$this->acl->setPollId($fromPollId)->getAllowView()) {
206
			throw new NotAuthorizedException;
207
		}
208
209
		foreach ($this->optionMapper->findByPoll($fromPollId) as $origin) {
210
			$option = new Option();
211
			$option->setPollId($toPollId);
212
			$option->setConfirmed(0);
213
			$option->setPollOptionText($origin->getPollOptionText());
214
			$option->setTimestamp($origin->getTimestamp());
215
			$option->setOrder($origin->getOrder());
216
			$this->optionMapper->insert($option);
217
		}
218
219
		return $this->optionMapper->findByPoll($toPollId);
220
	}
221
222
	/**
223
	 * Reorder options with the order specified by $options
224
	 * @NoAdminRequired
225
	 * @param int $pollId
226
	 * @param array $options - Array of options
227
	 * @return array Array of Option objects
228
	 * @throws NotAuthorizedException
229
	 * @throws BadRequestException
230
	 */
231
	public function reorder($pollId, $options) {
232
233
		$this->poll = $this->pollMapper->find($pollId);
234
235
		if (!$this->acl->setPollId($pollId)->getAllowEdit()) {
236
			throw new NotAuthorizedException;
237
		}
238
239
		if ($this->poll->getType() === 'datePoll') {
240
			throw new BadRequestException("Not allowed in date polls");
241
		}
242
243
		$i = 0;
244
		foreach ($options as $option) {
245
			$this->option = $this->optionMapper->find($option['id']);
246
			if ($pollId === intval($this->option->getPollId())) {
247
				$this->option->setOrder(++$i);
248
				$this->optionMapper->update($this->option);
249
			}
250
		}
251
252
		return $this->optionMapper->findByPoll($pollId);
253
	}
254
255
	/**
256
	 * Change order for $optionId and reorder the options
257
	 * @NoAdminRequired
258
	 * @param int $optionId
259
	 * @param int $newOrder
260
	 * @return array Array of Option objects
261
	 * @throws NotAuthorizedException
262
	 * @throws BadRequestException
263
	 */
264
	public function setOrder($optionId, $newOrder) {
265
266
		$this->option = $this->optionMapper->find($optionId);
267
		$pollId = $this->option->getPollId();
268
		$this->poll = $this->pollMapper->find($pollId);
269
270
		if (!$this->acl->setPollId($pollId)->getAllowEdit()) {
271
			throw new NotAuthorizedException;
272
		}
273
274
		if ($this->poll->getType() === 'datePoll') {
275
			throw new BadRequestException("Not allowed in date polls");
276
		}
277
278
		if ($newOrder < 1) {
279
			$newOrder = 1;
280
		} elseif ($newOrder > $this->getHighestOrder($pollId)) {
281
			$newOrder = $this->getHighestOrder($pollId);
282
		}
283
284
		$oldOrder = $this->option->getOrder();
285
286
		foreach ($this->optionMapper->findByPoll($pollId) as $option) {
287
			$currentOrder = $option->getOrder();
288
			if (
289
				   ($currentOrder < $oldOrder && $currentOrder < $newOrder)
290
				|| ($currentOrder > $oldOrder && $currentOrder > $newOrder)
291
			) {
292
293
				continue;
294
295
			} elseif ($currentOrder > $oldOrder && $currentOrder <= $newOrder) {
296
297
				$option->setOrder($currentOrder - 1);
298
				$this->optionMapper->update($option);
299
300
			} elseif (
301
					   ($currentOrder < $oldOrder && $currentOrder >= $newOrder)
302
					|| ($currentOrder < $oldOrder && $currentOrder = $newOrder)
303
				) {
304
305
				$option->setOrder($currentOrder + 1);
306
				$this->optionMapper->update($option);
307
308
			} elseif ($currentOrder === $oldOrder) {
309
310
				$option->setOrder($newOrder);
311
				$this->optionMapper->update($option);
312
313
			}
314
		}
315
316
		return $this->optionMapper->findByPoll($this->option->getPollId());
317
	}
318
319
	/**
320
	 * Set option entities validated
321
	 * @NoAdminRequired
322
	 * @param int $timestamp
323
	 * @param string $pollOptionText
324
	 * @param int $order
325
	 * @throws BadRequestException
326
	 */
327
	private function setOption($timestamp = 0, $pollOptionText = '', $order = 0) {
328
		if ($this->poll->getType() === 'datePoll') {
329
			if ($timestamp) {
330
				$this->option->setTimestamp($timestamp);
331
				$this->option->setOrder($timestamp);
332
				$this->option->setPollOptionText(date('c', $timestamp));
333
			} else {
334
				throw new BadRequestException("Date poll must have a timestamp");
335
			}
336
		} elseif ($this->poll->getType() === 'textPoll') {
337
			if ($pollOptionText) {
338
				$this->option->setPollOptionText($pollOptionText);
339
			} else {
340
				throw new BadRequestException("Text poll must have a pollOptionText");
341
			}
342
343
			if (!$order && !$this->option->getOrder()) {
344
				$order = $this->getHighestOrder($this->option->getPollId()) + 1;
345
				$this->option->setOrder($order);
346
			}
347
		}
348
	}
349
350
	/**
351
	 * Get the highest order number in $pollId
352
	 * @NoAdminRequired
353
	 * @param int $pollId
354
	 * @return int Highest order number
355
	 */
356
	private function getHighestOrder($pollId) {
357
		$order = 0;
358
		foreach ($this->optionMapper->findByPoll($pollId) as $option) {
359
			if ($option->getOrder() > $order) {
360
				$order = $option->getOrder();
361
			}
362
		}
363
		return $order;
364
	}
365
}
366