Completed
Pull Request — master (#1038)
by René
04:22
created

OptionService   B

Complexity

Total Complexity 44

Size/Duplication

Total Lines 322
Duplicated Lines 0 %

Test Coverage

Coverage 0%

Importance

Changes 2
Bugs 0 Features 0
Metric Value
wmc 44
eloc 119
c 2
b 0
f 0
dl 0
loc 322
ccs 0
cts 163
cp 0
rs 8.8798

11 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 14 1
A confirm() 0 14 3
A list() 0 11 3
A add() 0 12 2
C setOrder() 0 48 13
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
	 * OptionService 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
		$acl = $this->acl->set($pollId, $token);
94
95
		if (!$acl->getAllowView()) {
96
			throw new NotAuthorizedException;
97
		}
98
99
		try {
100
			return $this->optionMapper->findByPoll($acl->getPollId());
101
		} catch (DoesNotExistException $e) {
102
			return [];
103
		}
104
	}
105
106
107
	/**
108
	 * Add a new option
109
	 * @NoAdminRequired
110
	 * @param int $pollId
111
	 * @param int $timestamp
112
	 * @param string $pollOptionText
113
	 * @return Option
114
	 * @throws NotAuthorizedException
115
	 */
116
	public function add($pollId, $timestamp = 0, $pollOptionText = '') {
117
118
		$this->poll = $this->pollMapper->find($pollId);
119
		if (!$this->acl->set($pollId)->getAllowEdit()) {
120
			throw new NotAuthorizedException;
121
		}
122
123
		$this->option = new Option();
124
		$this->option->setPollId($pollId);
125
		$this->setOption($timestamp, $pollOptionText, 0);
126
127
		return $this->optionMapper->insert($this->option);
128
	}
129
130
	/**
131
	 * Update option
132
	 * @NoAdminRequired
133
	 * @param int $optionId
134
	 * @param int $timestamp
135
	 * @param string $pollOptionText
136
	 * @param int $order
137
	 * @return Option
138
	 * @throws NotAuthorizedException
139
	 */
140
	public function update($optionId, $timestamp = 0, $pollOptionText = '', $order = 0) {
141
142
		$this->option = $this->optionMapper->find($optionId);
143
		$this->poll = $this->pollMapper->find($this->option->getPollId());
144
145
		if (!$this->acl->set($this->option->getPollId())->getAllowEdit()) {
146
			throw new NotAuthorizedException;
147
		}
148
149
		$this->setOption($timestamp, $pollOptionText, $order);
150
151
		return $this->optionMapper->update($this->option);
152
	}
153
154
	/**
155
	 * Delete option
156
	 * @NoAdminRequired
157
	 * @param int $optionId
158
	 * @return Option deleted Option
159
	 * @throws NotAuthorizedException
160
	 */
161
	public function delete($optionId) {
162
		$this->option = $this->optionMapper->find($optionId);
163
164
		if (!$this->acl->set($this->option->getPollId())->getAllowEdit()) {
165
			throw new NotAuthorizedException;
166
		}
167
168
		$this->optionMapper->delete($this->option);
169
170
		return $this->option;
171
	}
172
173
	/**
174
	 * Switch optoin confirmation
175
	 * @NoAdminRequired
176
	 * @param int $optionId
177
	 * @return Option confirmed Option
178
	 * @throws NotAuthorizedException
179
	 */
180
	public function confirm($optionId) {
181
		$this->option = $this->optionMapper->find($optionId);
182
183
		if (!$this->acl->set($this->option->getPollId())->getAllowEdit()) {
184
			throw new NotAuthorizedException;
185
		}
186
187
		if ($this->option->getConfirmed()) {
188
			$this->option->setConfirmed(0);
189
		} else {
190
			$this->option->setConfirmed(time());
191
		}
192
193
		return $this->optionMapper->update($this->option);
194
	}
195
196
	/**
197
	 * Copy options from $fromPoll to $toPoll
198
	 * @NoAdminRequired
199
	 * @param int $fromPollId
200
	 * @param int $toPollId
201
	 * @return array Array of Option objects
202
	 * @throws NotAuthorizedException
203
	 */
204
	public function clone($fromPollId, $toPollId) {
205
206
		if (!$this->acl->set($fromPollId)->getAllowView()) {
207
			throw new NotAuthorizedException;
208
		}
209
210
		foreach ($this->optionMapper->findByPoll($fromPollId) as $origin) {
211
			$option = new Option();
212
			$option->setPollId($toPollId);
213
			$option->setConfirmed(0);
214
			$option->setPollOptionText($origin->getPollOptionText());
215
			$option->setTimestamp($origin->getTimestamp());
216
			$option->setOrder($origin->getOrder());
217
			$this->optionMapper->insert($option);
218
		}
219
220
		return $this->optionMapper->findByPoll($toPollId);
221
	}
222
223
	/**
224
	 * Reorder options with the order specified by $options
225
	 * @NoAdminRequired
226
	 * @param int $pollId
227
	 * @param array $options - Array of options
228
	 * @return array Array of Option objects
229
	 * @throws NotAuthorizedException
230
	 * @throws BadRequestException
231
	 */
232
	public function reorder($pollId, $options) {
233
234
		$this->poll = $this->pollMapper->find($pollId);
235
236
		if (!$this->acl->set($pollId)->getAllowEdit()) {
237
			throw new NotAuthorizedException;
238
		}
239
240
		if ($this->poll->getType() === 'datePoll') {
241
			throw new BadRequestException("Not allowed in date polls");
242
		}
243
244
		$i = 0;
245
		foreach ($options as $option) {
246
			$this->option = $this->optionMapper->find($option['id']);
247
			if ($pollId === intval($this->option->getPollId())) {
248
				$this->option->setOrder(++$i);
249
				$this->optionMapper->update($this->option);
250
			}
251
		}
252
253
		return $this->optionMapper->findByPoll($pollId);
254
	}
255
256
	/**
257
	 * Change order for $optionId and reorder the options
258
	 * @NoAdminRequired
259
	 * @param int $optionId
260
	 * @param int $newOrder
261
	 * @return array Array of Option objects
262
	 * @throws NotAuthorizedException
263
	 * @throws BadRequestException
264
	 */
265
	public function setOrder($optionId, $newOrder) {
266
267
		$this->option = $this->optionMapper->find($optionId);
268
		$pollId = $this->option->getPollId();
269
		$this->poll = $this->pollMapper->find($pollId);
270
271
		if (!$this->acl->set($pollId)->getAllowEdit()) {
272
			throw new NotAuthorizedException;
273
		}
274
275
		if ($this->poll->getType() === 'datePoll') {
276
			throw new BadRequestException("Not allowed in date polls");
277
		}
278
279
		if ($newOrder < 1) {
280
			$newOrder = 1;
281
		} elseif ($newOrder > $this->getHighestOrder($pollId)) {
282
			$newOrder = $this->getHighestOrder($pollId);
283
		}
284
285
		$oldOrder = $this->option->getOrder();
286
287
		foreach ($this->optionMapper->findByPoll($pollId) as $option) {
288
			$currentOrder = $option->getOrder();
289
			if ($currentOrder > $oldOrder && $currentOrder <= $newOrder) {
290
291
				$option->setOrder($currentOrder - 1);
292
				$this->optionMapper->update($option);
293
294
			} elseif (
295
					   ($currentOrder < $oldOrder && $currentOrder >= $newOrder)
296
					|| ($currentOrder < $oldOrder && $currentOrder = $newOrder)
297
				) {
298
299
				$option->setOrder($currentOrder + 1);
300
				$this->optionMapper->update($option);
301
302
			} elseif ($currentOrder === $oldOrder) {
303
304
				$option->setOrder($newOrder);
305
				$this->optionMapper->update($option);
306
307
			} else {
308
				continue;
309
			}
310
		}
311
312
		return $this->optionMapper->findByPoll($this->option->getPollId());
313
	}
314
315
	/**
316
	 * Set option entities validated
317
	 * @NoAdminRequired
318
	 * @param int $timestamp
319
	 * @param string $pollOptionText
320
	 * @param int $order
321
	 * @throws BadRequestException
322
	 */
323
	private function setOption($timestamp = 0, $pollOptionText = '', $order = 0) {
324
		if ($this->poll->getType() === 'datePoll') {
325
			if ($timestamp) {
326
				$this->option->setTimestamp($timestamp);
327
				$this->option->setOrder($timestamp);
328
				$this->option->setPollOptionText(date('c', $timestamp));
329
			} else {
330
				throw new BadRequestException("Date poll must have a timestamp");
331
			}
332
		} elseif ($this->poll->getType() === 'textPoll') {
333
			if ($pollOptionText) {
334
				$this->option->setPollOptionText($pollOptionText);
335
			} else {
336
				throw new BadRequestException("Text poll must have a pollOptionText");
337
			}
338
339
			if (!$order && !$this->option->getOrder()) {
340
				$order = $this->getHighestOrder($this->option->getPollId()) + 1;
341
				$this->option->setOrder($order);
342
			}
343
		}
344
	}
345
346
	/**
347
	 * Get the highest order number in $pollId
348
	 * @NoAdminRequired
349
	 * @param int $pollId
350
	 * @return int Highest order number
351
	 */
352
	private function getHighestOrder($pollId) {
353
		$order = 0;
354
		foreach ($this->optionMapper->findByPoll($pollId) as $option) {
355
			if ($option->getOrder() > $order) {
356
				$order = $option->getOrder();
357
			}
358
		}
359
		return $order;
360
	}
361
}
362