Donation   F
last analyzed

Complexity

Total Complexity 71

Size/Duplication

Total Lines 737
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 1

Test Coverage

Coverage 20.69%

Importance

Changes 0
Metric Value
wmc 71
lcom 2
cbo 1
dl 0
loc 737
ccs 36
cts 174
cp 0.2069
rs 2.583
c 0
b 0
f 0

57 Methods

Rating   Name   Duplication   Size   Complexity  
A setDonorFullName() 0 5 1
A getDonorFullName() 0 3 1
A setDonorCity() 0 5 1
A getDonorCity() 0 3 1
A setDonorEmail() 0 5 1
A getDonorEmail() 0 3 1
A setDonorOptsIntoNewsletter() 0 5 1
A getDonorOptsIntoNewsletter() 0 3 1
A setDonationReceipt() 0 5 1
A getDonationReceipt() 0 3 1
A setPublicRecord() 0 5 1
A getPublicRecord() 0 3 1
A setAmount() 0 5 1
A getAmount() 0 3 1
A setPaymentIntervalInMonths() 0 5 1
A getPaymentIntervalInMonths() 0 3 1
A setPaymentType() 0 5 1
A getPaymentType() 0 3 1
A setComment() 0 5 1
A getComment() 0 3 1
A setBankTransferCode() 0 5 1
A getBankTransferCode() 0 3 1
A setSource() 0 5 1
A getSource() 0 3 1
A setRemoteAddr() 0 5 1
A getRemoteAddr() 0 3 1
A setHash() 0 5 1
A getHash() 0 3 1
A setIsPublic() 0 5 1
A getIsPublic() 0 3 1
A setCreationTime() 0 5 1
A getCreationTime() 0 3 1
A setDeletionTime() 0 5 1
A getDeletionTime() 0 3 1
A setDtExp() 0 5 1
A getDtExp() 0 3 1
A setStatus() 0 5 1
A getStatus() 0 3 1
A setDtGruen() 0 5 1
A getDtGruen() 0 3 1
A setDtBackup() 0 5 1
A getDtBackup() 0 3 1
A getId() 0 3 1
A getPayment() 0 3 1
A setPayment() 0 3 1
A setId() 0 3 1
A getUExpiry() 0 3 1
A uTokenIsExpired() 0 3 1
A validateToken() 0 9 1
B getEntryType() 0 22 8
A setData() 0 5 1
A getData() 0 3 1
A getDecodedData() 0 9 3
A encodeAndSetData() 0 3 1
A getDataObject() 0 11 4
A setDataObject() 0 18 3
A modifyDataObject() 0 5 1

How to fix   Complexity   

Complex Class

Complex classes like Donation 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. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

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 Donation, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
declare( strict_types = 1 );
4
5
namespace WMDE\Fundraising\Entities;
6
7
use Doctrine\ORM\Mapping as ORM;
8
use Gedmo\Mapping\Annotation as Gedmo;
9
use WMDE\Fundraising\Store\DonationData;
10
11
/**
12
 * @since 2.0
13
 *
14
 * @ORM\Table(
15
 *     name="spenden",
16
 *     indexes={
17
 *         @ORM\Index(name="d_email", columns={"email"}, flags={"fulltext"}),
18
 *         @ORM\Index(name="d_name", columns={"name"}, flags={"fulltext"}),
19
 *         @ORM\Index(name="d_ort", columns={"ort"}, flags={"fulltext"}),
20
 *         @ORM\Index(name="d_dt_new", columns={"dt_new", "is_public"}),
21
 *         @ORM\Index(name="d_zahlweise", columns={"zahlweise", "dt_new"}),
22
 *         @ORM\Index(name="d_dt_gruen", columns={"dt_gruen", "dt_del"}),
23
 *         @ORM\Index(name="d_ueb_code", columns={"ueb_code"}),
24
 *         @ORM\Index(name="d_dt_backup", columns={"dt_backup"}),
25
 *         @ORM\Index(name="d_status", columns={"status", "dt_new"}),
26
 *         @ORM\Index(name="d_comment_list", columns={"is_public", "dt_del"})
27
 *     }
28
 * )
29
 * @ORM\Entity
30
 */
31
class Donation {
32
33
	/**
34
	 * @since 2.0
35
	 */
36
	public const STATUS_NEW = 'N'; // status for direct debit
37
	public const STATUS_PROMISE = 'Z'; // status for bank transfer
38
	public const STATUS_EXTERNAL_INCOMPLETE = 'X'; // status for external payments
39
	public const STATUS_EXTERNAL_BOOKED = 'B'; // status for external payments
40
	public const STATUS_MODERATION = 'P';
41
	public const STATUS_CANCELLED = 'D';
42
43
	/**
44
	 * @since 6.1
45
	 * @deprecated since 6.1; This status is defined for historical reasons. It should not be used to define a
46
	 * donation's status anymore.
47
	 */
48
	public const STATUS_EXPORTED = 'E';
49
50
	/**
51
	 * @var integer
52
	 *
53
	 * @ORM\Column(name="id", type="integer")
54
	 * @ORM\Id
55
	 * @ORM\GeneratedValue(strategy="IDENTITY")
56
	 */
57
	private $id;
58
59
	/**
60
	 * @var string
61
	 *
62
	 * @ORM\Column(name="status", type="string", length=1, options={"default":"N", "fixed":true}, nullable=false)
63
	 */
64
	private $status = self::STATUS_NEW;
65
66
	/**
67
	 * @var string
68
	 *
69
	 * @ORM\Column(name="name", type="string", length=250, nullable=true)
70
	 */
71
	private $donorFullName;
72
73
	/**
74
	 * @var string
75
	 *
76
	 * @ORM\Column(name="ort", type="string", length=250, nullable=true)
77
	 */
78
	private $donorCity;
79
80
	/**
81
	 * @var string
82
	 *
83
	 * @ORM\Column(name="email", type="string", length=250, nullable=true)
84
	 */
85
	private $donorEmail;
86
87
	/**
88
	 * @var boolean
89
	 *
90
	 * @ORM\Column(name="info", type="boolean", options={"default":0}, nullable=false)
91
	 */
92
	private $donorOptsIntoNewsletter = 0;
93
94
	/**
95
	 * @var boolean
96
	 *
97
	 * @ORM\Column(name="bescheinigung", type="boolean", nullable=true)
98
	 */
99
	private $donationReceipt;
100
101
	/**
102
	 * @var string
103
	 *
104
	 * @ORM\Column(name="eintrag", type="string", length=250, options={"default":""}, nullable=false)
105
	 */
106
	private $publicRecord = '';
107
108
	/**
109
	 * @var string
110
	 *
111
	 * @ORM\Column(name="betrag", type="string", length=250, nullable=true)
112
	 */
113
	private $amount;
114
115
	/**
116
	 * @var integer
117
	 *
118
	 * @ORM\Column(name="periode", type="smallint", options={"default":0}, nullable=false)
119
	 */
120
	private $paymentIntervalInMonths = 0;
121
122
	/**
123
	 * @var string
124
	 *
125
	 * @ORM\Column(name="zahlweise", type="string", length=3, options={"default":"BEZ", "fixed":true}, nullable=false)
126
	 */
127
	private $paymentType = 'BEZ';
128
129
	/**
130
	 * @var string
131
	 *
132
	 * @ORM\Column(name="kommentar", type="text", options={"default":""}, nullable=false)
133
	 */
134
	private $comment = '';
135
136
	/**
137
	 * @var string
138
	 *
139
	 * @ORM\Column(name="ueb_code", type="string", length=32, options={"default":""}, nullable=false)
140
	 */
141
	private $bankTransferCode = '';
142
143
	/**
144
	 * @var string
145
	 *
146
	 * @ORM\Column(name="data", type="text", nullable=true)
147
	 */
148
	private $data;
149
150
	/**
151
	 * @var string
152
	 *
153
	 * @ORM\Column(name="source", type="string", length=250, nullable=true)
154
	 */
155
	private $source;
156
157
	/**
158
	 * @var string
159
	 *
160
	 * @ORM\Column(name="remote_addr", type="string", length=250, options={"default":""}, nullable=false)
161
	 */
162
	private $remoteAddr = '';
163
164
	/**
165
	 * @var string
166
	 *
167
	 * @ORM\Column(name="hash", type="string", length=250, nullable=true)
168
	 */
169
	private $hash;
170
171
	/**
172
	 * @var boolean
173
	 *
174
	 * @ORM\Column(name="is_public", type="boolean", options={"default":0}, nullable=false)
175
	 */
176
	private $isPublic = 0;
177
178
	/**
179
	 * @var \DateTime
180
	 *
181
	 * @Gedmo\Timestampable(on="create")
182
	 * @ORM\Column(name="dt_new", type="datetime")
183
	 */
184
	private $creationTime;
185
186
	/**
187
	 * @var \DateTime
188
	 *
189
	 * @ORM\Column(name="dt_del", type="datetime", nullable=true)
190
	 */
191
	private $deletionTime;
192
193
	/**
194
	 * @var \DateTime
195
	 *
196
	 * @ORM\Column(name="dt_exp", type="datetime", nullable=true)
197
	 */
198
	private $dtExp;
199
200
	/**
201
	 * @var \DateTime
202
	 *
203
	 * @ORM\Column(name="dt_gruen", type="datetime", nullable=true)
204
	 */
205
	private $dtGruen;
206
207
	/**
208
	 * @var \DateTime
209
	 *
210
	 * @ORM\Column(name="dt_backup", type="datetime", nullable=true)
211
	 */
212
	private $dtBackup;
213
214
	/**
215
	 * @ORM\OneToOne(targetEntity="WMDE\Fundraising\Entities\DonationPayment", cascade={"all"}, fetch="EAGER")
216
	 */
217
	private $payment;
218
219
	/**
220
	 * @param string $donorFullName
221
	 *
222
	 * @return self
223
	 */
224
	public function setDonorFullName( $donorFullName ) {
225
		$this->donorFullName = $donorFullName;
226
227
		return $this;
228
	}
229
230
	/**
231
	 * @return string
232
	 */
233
	public function getDonorFullName() {
234
		return $this->donorFullName;
235
	}
236
237
	/**
238
	 * @param string $donorCity
239
	 *
240
	 * @return self
241
	 */
242
	public function setDonorCity( $donorCity ) {
243
		$this->donorCity = $donorCity;
244
245
		return $this;
246
	}
247
248
	/**
249
	 * @return string
250
	 */
251
	public function getDonorCity() {
252
		return $this->donorCity;
253
	}
254
255
	/**
256
	 * @param string $donorEmail
257
	 *
258
	 * @return self
259
	 */
260
	public function setDonorEmail( $donorEmail ) {
261
		$this->donorEmail = $donorEmail;
262
263
		return $this;
264
	}
265
266
	/**
267
	 * @return string
268
	 */
269
	public function getDonorEmail() {
270
		return $this->donorEmail;
271
	}
272
273
	/**
274
	 * @param boolean $donorOptsIntoNewsletter
275
	 *
276
	 * @return self
277
	 */
278
	public function setDonorOptsIntoNewsletter( $donorOptsIntoNewsletter ) {
279
		$this->donorOptsIntoNewsletter = $donorOptsIntoNewsletter;
280
281
		return $this;
282
	}
283
284
	/**
285
	 * @return boolean
286
	 */
287
	public function getDonorOptsIntoNewsletter() {
288
		return $this->donorOptsIntoNewsletter;
289
	}
290
291
	/**
292
	 * Set donation receipt state
293
	 *
294
	 * @param boolean $donationReceipt
295
	 * @return self
296
	 */
297
	public function setDonationReceipt( $donationReceipt ) {
298
		$this->donationReceipt = $donationReceipt;
299
300
		return $this;
301
	}
302
303
	/**
304
	 * Get donation receipt state
305
	 *
306
	 * @return boolean
307
	 */
308
	public function getDonationReceipt() {
309
		return $this->donationReceipt;
310
	}
311
312
	/**
313
	 * Set publicly displayed donation record
314
	 *
315
	 * @param string $publicRecord
316
	 * @return self
317
	 */
318
	public function setPublicRecord( $publicRecord ) {
319
		$this->publicRecord = $publicRecord;
320
321
		return $this;
322
	}
323
324
	/**
325
	 * Get publicly displayed donation record
326
	 *
327
	 * @return string
328
	 */
329
	public function getPublicRecord() {
330
		return $this->publicRecord;
331
	}
332
333
	/**
334
	 * @param string $amount
335
	 * @return self
336
	 */
337
	public function setAmount( $amount ) {
338
		$this->amount = $amount;
339
340
		return $this;
341
	}
342
343
	/**
344
	 * @return string
345
	 */
346
	public function getAmount() {
347
		return $this->amount;
348
	}
349
350
	/**
351
	 * @param integer $paymentIntervalInMonths
352
	 *
353
	 * @return self
354
	 */
355
	public function setPaymentIntervalInMonths( $paymentIntervalInMonths ) {
356
		$this->paymentIntervalInMonths = $paymentIntervalInMonths;
357
358
		return $this;
359
	}
360
361
	/**
362
	 * @return integer
363
	 */
364
	public function getPaymentIntervalInMonths() {
365
		return $this->paymentIntervalInMonths;
366
	}
367
368
	/**
369
	 * Set payment type short code
370
	 *
371
	 * @param string $paymentType
372
	 * @return self
373
	 */
374
	public function setPaymentType( $paymentType ) {
375
		$this->paymentType = $paymentType;
376
377
		return $this;
378
	}
379
380
	/**
381
	 * Get payment type short code
382
	 *
383
	 * @return string
384
	 */
385
	public function getPaymentType() {
386
		return $this->paymentType;
387
	}
388
389
	/**
390
	 * @param string $comment
391
	 * @return self
392
	 */
393
	public function setComment( $comment ) {
394
		$this->comment = $comment;
395
396
		return $this;
397
	}
398
399
	/**
400
	 * @return string
401
	 */
402
	public function getComment() {
403
		return $this->comment;
404
	}
405
406
	/**
407
	 * Set bank transfer reference code
408
	 *
409
	 * @param string $bankTransferCode
410
	 *
411
	 * @return self
412
	 */
413
	public function setBankTransferCode( $bankTransferCode ) {
414
		$this->bankTransferCode = $bankTransferCode;
415
416
		return $this;
417
	}
418
419
	/**
420
	 * Get bank transfer reference code
421
	 *
422
	 * @return string
423
	 */
424
	public function getBankTransferCode() {
425
		return $this->bankTransferCode;
426
	}
427
428
	/**
429
	 * @param string $source
430
	 * @return self
431
	 */
432
	public function setSource( $source ) {
433
		$this->source = $source;
434
435
		return $this;
436
	}
437
438
	/**
439
	 * @return string
440
	 */
441
	public function getSource() {
442
		return $this->source;
443
	}
444
445
	/**
446
	 * @param string $remoteAddr
447
	 * @return self
448
	 */
449
	public function setRemoteAddr( $remoteAddr ) {
450
		$this->remoteAddr = $remoteAddr;
451
452
		return $this;
453
	}
454
455
	/**
456
	 * @return string
457
	 */
458
	public function getRemoteAddr() {
459
		return $this->remoteAddr;
460
	}
461
462
	/**
463
	 * @param string $hash
464
	 * @return self
465
	 */
466
	public function setHash( $hash ) {
467
		$this->hash = $hash;
468
469
		return $this;
470
	}
471
472
	/**
473
	 * @return string
474
	 */
475
	public function getHash() {
476
		return $this->hash;
477
	}
478
479
	/**
480
	 * Sets if the donations comment should be public or private.
481
	 * @param boolean $isPublic
482
	 * @return self
483
	 */
484
	public function setIsPublic( $isPublic ) {
485
		$this->isPublic = $isPublic;
486
487
		return $this;
488
	}
489
490
	/**
491
	 * Gets if the donations comment is public or private.
492
	 * @return boolean
493
	 */
494
	public function getIsPublic() {
495
		return $this->isPublic;
496
	}
497
498
	/**
499
	 * @param \DateTime $creationTime
500
	 *
501
	 * @return self
502
	 */
503
	public function setCreationTime( $creationTime ) {
504
		$this->creationTime = $creationTime;
505
506
		return $this;
507
	}
508
509
	/**
510
	 * @return \DateTime
511
	 */
512
	public function getCreationTime() {
513
		return $this->creationTime;
514
	}
515
516
	/**
517
	 * @param \DateTime|null $deletionTime
518
	 *
519
	 * @return self
520
	 */
521
	public function setDeletionTime( $deletionTime ) {
522
		$this->deletionTime = $deletionTime;
523
524
		return $this;
525
	}
526
527
	/**
528
	 * @return \DateTime|null
529
	 */
530
	public function getDeletionTime() {
531
		return $this->deletionTime;
532
	}
533
534
	/**
535
	 * @param \DateTime $dtExp
536
	 * @return self
537
	 */
538
	public function setDtExp( $dtExp ) {
539
		$this->dtExp = $dtExp;
540
541
		return $this;
542
	}
543
544
	/**
545
	 * @return \DateTime
546
	 */
547
	public function getDtExp() {
548
		return $this->dtExp;
549
	}
550
551
	/**
552
	 * @param string $status
553
	 * @return self
554
	 */
555
	public function setStatus( $status ) {
556
		$this->status = $status;
557
558
		return $this;
559
	}
560
561
	/**
562
	 * @return string
563
	 */
564
	public function getStatus() {
565
		return $this->status;
566
	}
567
568
	/**
569
	 * @param \DateTime $dtGruen
570
	 * @return self
571
	 */
572
	public function setDtGruen( $dtGruen ) {
573
		$this->dtGruen = $dtGruen;
574
575
		return $this;
576
	}
577
578
	/**
579
	 * @return \DateTime
580
	 */
581
	public function getDtGruen() {
582
		return $this->dtGruen;
583
	}
584
585
	/**
586
	 * @param \DateTime $dtBackup
587
	 * @return self
588
	 */
589
	public function setDtBackup( $dtBackup ) {
590
		$this->dtBackup = $dtBackup;
591
592
		return $this;
593
	}
594
595
	/**
596
	 * @return \DateTime
597
	 */
598
	public function getDtBackup() {
599
		return $this->dtBackup;
600
	}
601
602
	/**
603
	 * @return integer|null
604
	 */
605 3
	public function getId() {
606 3
		return $this->id;
607
	}
608
609
	public function getPayment(): ?DonationPayment {
610
		return $this->payment;
611
	}
612
613
	public function setPayment( DonationPayment $payment ) {
614
		$this->payment = $payment;
615
	}
616
617
618
	/**
619
	 * @since 2.0
620
	 *
621
	 * @param integer|null $id
622
	 */
623 2
	public function setId( $id ) {
624 2
		$this->id = $id;
625 2
	}
626
627
	public function getUExpiry() {
628
		return $this->getDecodedData()['uexpiry'];
629
	}
630
631
	public function uTokenIsExpired() {
632
		return time() > strtotime( $this->getUExpiry() );
633
	}
634
635
	public function validateToken( $tokenToCheck, $serverSecret ) {
636
		$checkToken = preg_replace( '/\$.*$/', '', $tokenToCheck );
637
638
		$checkToken = $checkToken . '$' .
639
			sha1( sha1( "$checkToken+$serverSecret" ) . '|' .
640
				sha1( "{$this->id}+$serverSecret" ) . '|' .
641
				sha1( "{$this->creationTime->format( 'Y-m-d H:i:s' )}+$serverSecret" ) );
642
		return $checkToken === $tokenToCheck;
643
	}
644
645
	public function getEntryType( $mode = null ) {
646
		$data = $this->getDecodedData();
647
648
		if ( $mode === null ) {
649
			$mode = $this->publicRecord;
650
			if ( !is_int( $mode ) ) {
651
				return $this->publicRecord;
652
			}
653
		}
654
655
		if ( $mode == 1 || $mode == 2 ) {
656
			$eintrag = $this->donorFullName;
657
		} else {
658
			$eintrag = 'anonym';
659
		}
660
661
		if ( ( $mode == 1 || $mode == 3 ) && !empty( $data['ort'] ) ) {
662
			$eintrag .= ', ' . $data['ort'];
663
		}
664
665
		return $eintrag;
666
	}
667
668
	/**
669
	 * @deprecated since 2.0, use encodeAndSetData or setDataObject instead
670
	 *
671
	 * @param string $data Base 64 encoded, serialized PHP array
672
	 * @return self
673
	 */
674
	public function setData( $data ) {
675
		$this->data = $data;
676
677
		return $this;
678
	}
679
680
	/**
681
	 * @deprecated since 2.0, use @see getDecodedData or @see getDataObject instead
682
	 *
683
	 * @return string Base 64 encoded, serialized PHP array
684
	 */
685
	public function getData() {
686
		return $this->data;
687
	}
688
689
	/**
690
	 * NOTE: if possible, use @see getDataObject instead, as it provides a nicer API.
691
	 *
692
	 * @since 2.0
693
	 * @return array
694
	 */
695 8
	public function getDecodedData() {
696 8
		if ( $this->data === null ) {
697 4
			return [];
698
		}
699
700 6
		$data = unserialize( base64_decode( $this->data ) );
701
702 6
		return is_array( $data ) ? $data : [];
703
	}
704
705
	/**
706
	 * NOTE: if possible, use @see modifyDataObject instead, as it provides a nicer API.
707
	 *
708
	 * @since 2.0
709
	 * @param array $data
710
	 */
711 6
	public function encodeAndSetData( array $data ) {
712 6
		$this->data = base64_encode( serialize( $data ) );
713 6
	}
714
715
	/**
716
	 * WARNING: updates made to the return value will not be reflected in the Donation state.
717
	 * Similarly, updates to the Donation state will not propagate to the returned object.
718
	 * To update the Donation state, explicitly call @see setDataObject.
719
	 *
720
	 * @since 2.0
721
	 * @return DonationData
722
	 */
723 3
	public function getDataObject() {
724 3
		$dataArray = $this->getDecodedData();
725
726 3
		$data = new DonationData();
727
728 3
		$data->setAccessToken( array_key_exists( 'token', $dataArray ) ? $dataArray['token'] : null );
729 3
		$data->setUpdateToken( array_key_exists( 'utoken', $dataArray ) ? $dataArray['utoken'] : null );
730 3
		$data->setUpdateTokenExpiry( array_key_exists( 'uexpiry', $dataArray ) ? $dataArray['uexpiry'] : null );
731
732 3
		return $data;
733
	}
734
735
	/**
736
	 * @since 2.0
737
	 * @param DonationData $data
738
	 */
739 4
	public function setDataObject( DonationData $data ) {
740 4
		$dataArray = array_merge(
741 4
			$this->getDecodedData(),
742
			[
743 4
				'token' => $data->getAccessToken(),
744 4
				'utoken' => $data->getUpdateToken(),
745 4
				'uexpiry' => $data->getUpdateTokenExpiry(),
746
			]
747
		);
748
749 4
		foreach ( [ 'token', 'utoken', 'uexpiry' ] as $keyName ) {
750 4
			if ( is_null( $dataArray[$keyName] ) ) {
751 3
				unset( $dataArray[$keyName] );
752
			}
753
		}
754
755 4
		$this->encodeAndSetData( $dataArray );
756 4
	}
757
758
	/**
759
	 * @since 2.0
760
	 * @param callable $modificationFunction Takes a modifiable DonationData parameter
761
	 */
762 1
	public function modifyDataObject( callable $modificationFunction ) {
763 1
		$dataObject = $this->getDataObject();
764 1
		$modificationFunction( $dataObject );
765 1
		$this->setDataObject( $dataObject );
766 1
	}
767
}
768