Failed Conditions
Branch newinternal (104de7)
by Simon
09:33
created

Request   B

Complexity

Total Complexity 38

Size/Duplication

Total Lines 376
Duplicated Lines 5.59 %

Coupling/Cohesion

Components 2
Dependencies 3

Importance

Changes 11
Bugs 1 Features 0
Metric Value
wmc 38
c 11
b 1
f 0
lcom 2
cbo 3
dl 21
loc 376
rs 8.3999

27 Methods

Rating   Name   Duplication   Size   Complexity  
A getIp() 0 4 1
A setIp() 0 4 1
A getName() 0 4 1
A setName() 0 4 1
A getComment() 0 4 1
A setComment() 0 4 1
A getStatus() 0 4 1
A setStatus() 0 4 1
A getDate() 0 4 1
A getEmailSent() 0 4 1
A setEmailSent() 0 4 2
A getReserved() 0 4 1
A setReserved() 0 9 2
A getUserAgent() 0 4 1
A setUserAgent() 0 4 1
A getForwardedIp() 0 4 1
A setForwardedIp() 0 4 1
A hasComments() 0 23 3
A getEmailConfirm() 0 4 1
A setEmailConfirm() 0 4 1
A generateEmailConfirmationHash() 0 4 1
A getEmail() 0 4 1
A setEmail() 0 4 1
B getClosureReason() 0 24 2
B getWasCreated() 0 30 3
B save() 6 65 5
A getClosureDate() 15 15 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
namespace Waca\DataObjects;
3
4
use DateTime;
5
use DateTimeImmutable;
6
use Exception;
7
use Waca\DataObject;
8
use Waca\Exceptions\OptimisticLockFailedException;
9
10
/**
11
 * Request data object
12
 *
13
 * This data object is the main request object.
14
 */
15
class Request extends DataObject
16
{
17
	private $email;
18
	private $ip;
19
	private $name;
20
	/** @var string|null */
21
	private $comment;
22
	private $status = "Open";
23
	private $date;
24
	private $emailsent = 0;
25
	private $emailconfirm;
26
	private $reserved = 0;
27
	private $useragent;
28
	private $forwardedip;
29
	private $hasComments = false;
30
	private $hasCommentsResolved = false;
31
32
	/**
33
	 * @throws Exception
34
	 */
35
	public function save()
36
	{
37
		if ($this->isNew()) {
38
			// insert
39
			$statement = $this->dbObject->prepare(<<<SQL
40
INSERT INTO `request` (
41
	email, ip, name, comment, status, date, emailsent,
42
	emailconfirm, reserved, useragent, forwardedip
43
) VALUES (
44
	:email, :ip, :name, :comment, :status, CURRENT_TIMESTAMP(), :emailsent,
45
	:emailconfirm, :reserved, :useragent, :forwardedip
46
);
47
SQL
48
			);
49
			$statement->bindValue(":email", $this->email);
50
			$statement->bindValue(":ip", $this->ip);
51
			$statement->bindValue(":name", $this->name);
52
			$statement->bindValue(":comment", $this->comment);
53
			$statement->bindValue(":status", $this->status);
54
			$statement->bindValue(":emailsent", $this->emailsent);
55
			$statement->bindValue(":emailconfirm", $this->emailconfirm);
56
			$statement->bindValue(":reserved", $this->reserved);
57
			$statement->bindValue(":useragent", $this->useragent);
58
			$statement->bindValue(":forwardedip", $this->forwardedip);
59
60 View Code Duplication
			if ($statement->execute()) {
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...
61
				$this->id = (int)$this->dbObject->lastInsertId();
62
			}
63
			else {
64
				throw new Exception($statement->errorInfo());
65
			}
66
		}
67
		else {
68
			// update
69
			$statement = $this->dbObject->prepare(<<<SQL
70
UPDATE `request` SET
71
	status = :status,
72
	emailsent = :emailsent,
73
	emailconfirm = :emailconfirm,
74
	reserved = :reserved,
75
	updateversion = updateversion + 1
76
WHERE id = :id AND updateversion = :updateversion
77
LIMIT 1;
78
SQL
79
			);
80
81
			$statement->bindValue(':id', $this->id);
82
			$statement->bindValue(':updateversion', $this->updateversion);
83
84
			$statement->bindValue(':status', $this->status);
85
			$statement->bindValue(':emailsent', $this->emailsent);
86
			$statement->bindValue(':emailconfirm', $this->emailconfirm);
87
			$statement->bindValue(':reserved', $this->reserved);
88
89
			if (!$statement->execute()) {
90
				throw new Exception($statement->errorInfo());
91
			}
92
93
			if ($statement->rowCount() !== 1) {
94
				throw new OptimisticLockFailedException();
95
			}
96
97
			$this->updateversion++;
98
		}
99
	}
100
101
	/**
102
	 * @return string
103
	 */
104
	public function getIp()
105
	{
106
		return $this->ip;
107
	}
108
109
	/**
110
	 * @param string $ip
111
	 */
112
	public function setIp($ip)
113
	{
114
		$this->ip = $ip;
115
	}
116
117
	/**
118
	 * @return string
119
	 */
120
	public function getName()
121
	{
122
		return $this->name;
123
	}
124
125
	/**
126
	 * @param string $name
127
	 */
128
	public function setName($name)
129
	{
130
		$this->name = $name;
131
	}
132
133
	/**
134
	 * @return string|null
135
	 */
136
	public function getComment()
137
	{
138
		return $this->comment;
139
	}
140
141
	/**
142
	 * @param string $comment
143
	 */
144
	public function setComment($comment)
145
	{
146
		$this->comment = $comment;
147
	}
148
149
	/**
150
	 * @return string
151
	 */
152
	public function getStatus()
153
	{
154
		return $this->status;
155
	}
156
157
	/**
158
	 * @param string $status
159
	 */
160
	public function setStatus($status)
161
	{
162
		$this->status = $status;
163
	}
164
165
	/**
166
	 * Returns the time the request was first submitted
167
	 *
168
	 * @return DateTimeImmutable
169
	 */
170
	public function getDate()
171
	{
172
		return new DateTimeImmutable($this->date);
173
	}
174
175
	/**
176
	 * @return bool
177
	 */
178
	public function getEmailSent()
179
	{
180
		return $this->emailsent == "1";
181
	}
182
183
	/**
184
	 * @param bool $emailSent
185
	 */
186
	public function setEmailSent($emailSent)
187
	{
188
		$this->emailsent = $emailSent ? 1 : 0;
189
	}
190
191
	/**
192
	 * @todo allow this to return null instead
0 ignored issues
show
Coding Style introduced by
Comment refers to a TODO task

This check looks TODO comments that have been left in the code.

``TODO``s show that something is left unfinished and should be attended to.

Loading history...
193
	 * @return int
194
	 */
195
	public function getReserved()
196
	{
197
		return $this->reserved;
198
	}
199
200
	/**
201
	 * @param int|null $reserved
202
	 */
203
	public function setReserved($reserved)
204
	{
205
		if ($reserved === null) {
206
			// @todo this shouldn't be needed!
0 ignored issues
show
Coding Style Best Practice introduced by
Comments for TODO tasks are often forgotten in the code; it might be better to use a dedicated issue tracker.
Loading history...
207
			$reserved = 0;
208
		}
209
210
		$this->reserved = $reserved;
211
	}
212
213
	/**
214
	 * @return string
215
	 */
216
	public function getUserAgent()
217
	{
218
		return $this->useragent;
219
	}
220
221
	/**
222
	 * @param string $useragent
223
	 */
224
	public function setUserAgent($useragent)
225
	{
226
		$this->useragent = $useragent;
227
	}
228
229
	/**
230
	 * @return string|null
231
	 */
232
	public function getForwardedIp()
233
	{
234
		return $this->forwardedip;
235
	}
236
237
	/**
238
	 * @param string|null $forwardedip
239
	 */
240
	public function setForwardedIp($forwardedip)
241
	{
242
		$this->forwardedip = $forwardedip;
243
	}
244
245
	/**
246
	 * @return bool
247
	 */
248
	public function hasComments()
249
	{
250
		if ($this->hasCommentsResolved) {
251
			return $this->hasComments;
252
		}
253
254
		if ($this->comment != "") {
255
			$this->hasComments = true;
256
			$this->hasCommentsResolved = true;
257
258
			return true;
259
		}
260
261
		$commentsQuery = $this->dbObject->prepare("SELECT COUNT(*) AS num FROM comment WHERE request = :id;");
262
		$commentsQuery->bindValue(":id", $this->id);
263
264
		$commentsQuery->execute();
265
266
		$this->hasComments = ($commentsQuery->fetchColumn() != 0);
267
		$this->hasCommentsResolved = true;
268
269
		return $this->hasComments;
270
	}
271
272
	/**
273
	 * @return string
274
	 */
275
	public function getEmailConfirm()
276
	{
277
		return $this->emailconfirm;
278
	}
279
280
	/**
281
	 * @param string $emailconfirm
282
	 */
283
	public function setEmailConfirm($emailconfirm)
284
	{
285
		$this->emailconfirm = $emailconfirm;
286
	}
287
288
	public function generateEmailConfirmationHash()
289
	{
290
		$this->emailconfirm = bin2hex(openssl_random_pseudo_bytes(16));
291
	}
292
293
	/**
294
	 * @return string|null
295
	 */
296
	public function getEmail()
297
	{
298
		return $this->email;
299
	}
300
301
	/**
302
	 * @param string|null $email
303
	 */
304
	public function setEmail($email)
305
	{
306
		$this->email = $email;
307
	}
308
309
	/**
310
	 * @return string
311
	 * @throws Exception
312
	 */
313
	public function getClosureReason()
314
	{
315
		if ($this->status != 'Closed') {
316
			throw new Exception("Can't get closure reason for open request.");
317
		}
318
319
		$statement = $this->dbObject->prepare(<<<SQL
320
SELECT closes.mail_desc
321
FROM log
322
INNER JOIN closes ON log.action = closes.closes
323
WHERE log.objecttype = 'Request'
324
AND log.objectid = :requestId
325
AND log.action LIKE 'Closed%'
326
ORDER BY log.timestamp DESC
327
LIMIT 1;
328
SQL
329
		);
330
331
		$statement->bindValue(":requestId", $this->id);
332
		$statement->execute();
333
		$reason = $statement->fetchColumn();
334
335
		return $reason;
336
	}
337
338
	/**
339
	 * Gets a value indicating whether the request was closed as created or not.
340
	 */
341
	public function getWasCreated()
342
	{
343
		if ($this->status != 'Closed') {
344
			throw new Exception("Can't get closure reason for open request.");
345
		}
346
347
		$statement = $this->dbObject->prepare(<<<SQL
348
SELECT emailtemplate.oncreated, log.action
349
FROM log
350
LEFT JOIN emailtemplate ON CONCAT('Closed ', emailtemplate.id) = log.action
351
WHERE log.objecttype = 'Request'
352
AND log.objectid = :requestId
353
AND log.action LIKE 'Closed%'
354
ORDER BY log.timestamp DESC
355
LIMIT 1;
356
SQL
357
		);
358
359
		$statement->bindValue(":requestId", $this->id);
360
		$statement->execute();
361
		$onCreated = $statement->fetchColumn(0);
362
		$logAction = $statement->fetchColumn(1);
363
		$statement->closeCursor();
364
365
		if ($onCreated === null) {
366
			return $logAction === "Closed custom-y";
367
		}
368
369
		return (bool)$onCreated;
370
	}
371
372
	/**
373
	 * @return DateTime
374
	 */
375 View Code Duplication
	public function getClosureDate()
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...
376
	{
377
		$logQuery = $this->dbObject->prepare(<<<SQL
378
SELECT timestamp FROM log
379
WHERE objectid = :request AND objecttype = 'Request' AND action LIKE 'Closed%'
380
ORDER BY timestamp DESC LIMIT 1;
381
SQL
382
		);
383
		$logQuery->bindValue(":request", $this->getId());
384
		$logQuery->execute();
385
		$logTime = $logQuery->fetchColumn();
386
		$logQuery->closeCursor();
387
388
		return new DateTime($logTime);
389
	}
390
}
391