Completed
Pull Request — master (#594)
by Jeroen De
12:09
created

AddDonationValidator::validatePayment()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 9
rs 9.6666
c 0
b 0
f 0
cc 2
eloc 6
nc 2
nop 0
1
<?php
2
3
declare( strict_types = 1 );
4
5
namespace WMDE\Fundraising\Frontend\DonatingContext\UseCases\AddDonation;
6
7
use WMDE\Fundraising\Frontend\DonatingContext\UseCases\AddDonation\AddDonationValidationResult as Result;
8
use WMDE\Fundraising\Frontend\PaymentContext\Domain\Model\PaymentType;
9
use WMDE\Fundraising\Frontend\Validation\AmountValidator;
10
use WMDE\Fundraising\Frontend\Validation\BankDataValidator;
11
use WMDE\Fundraising\Frontend\Validation\ConstraintViolation;
12
use WMDE\Fundraising\Frontend\Validation\EmailValidator;
13
14
/**
15
 * @license GNU GPL v2+
16
 * @author Gabriel Birke < [email protected] >
17
 */
18
class AddDonationValidator {
19
	private $amountValidator;
20
	private $bankDataValidator;
21
	private $emailValidator;
22
23
	/**
24
	 * @var AddDonationRequest
25
	 */
26
	private $request;
27
28
	/**
29
	 * @var ConstraintViolation[]
30
	 */
31
	private $violations;
32
33
	private $maximumFieldLengths = [
34
		Result::SOURCE_DONOR_EMAIL => 250,
35
		Result::SOURCE_DONOR_COMPANY => 100,
36
		Result::SOURCE_DONOR_FIRST_NAME => 50,
37
		Result::SOURCE_DONOR_LAST_NAME => 50,
38
		Result::SOURCE_DONOR_SALUTATION => 16,
39
		Result::SOURCE_DONOR_TITLE => 16,
40
		Result::SOURCE_DONOR_STREET_ADDRESS => 100,
41
		Result::SOURCE_DONOR_POSTAL_CODE => 8,
42
		Result::SOURCE_DONOR_CITY => 100,
43
		Result::SOURCE_DONOR_COUNTRY => 8,
44
		Result::SOURCE_BANK_NAME => 50,
45
		Result::SOURCE_BIC => 32,
46
	];
47
48
	public function __construct( AmountValidator $amountValidator, BankDataValidator $bankDataValidator,
49
								 EmailValidator $emailValidator ) {
50
51
		$this->amountValidator = $amountValidator;
52
		$this->bankDataValidator = $bankDataValidator;
53
		$this->emailValidator = $emailValidator;
54
	}
55
56
	public function validate( AddDonationRequest $addDonationRequest ): Result {
57
		$this->request = $addDonationRequest;
58
		$this->violations = [];
59
60
		$this->validateAmount();
61
		$this->validatePayment();
62
		$this->validateBankData();
63
		$this->validateDonorName();
64
		$this->validateDonorEmail();
65
		$this->validateDonorAddress();
66
67
		return new Result( ...$this->violations );
68
	}
69
70
	private function validateAmount() {
71
		// TODO validate without euro class, put conversion in AmountValidator
72
		$result = $this->amountValidator->validate(
73
			$this->request->getAmount()->getEuroFloat(),
74
			$this->request->getPaymentType()
75
		);
76
77
		$violations = array_map( function( ConstraintViolation $violation ) {
78
			$violation->setSource( Result::SOURCE_PAYMENT_AMOUNT );
79
			return $violation;
80
		}, $result->getViolations() );
81
		$this->addViolations( $violations );
82
	}
83
84
	private function addViolations( array $violations ) {
85
		$this->violations = array_merge( $this->violations, $violations );
0 ignored issues
show
Documentation Bug introduced by
It seems like array_merge($this->violations, $violations) of type array is incompatible with the declared type array<integer,object<WMD...n\ConstraintViolation>> of property $violations.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
86
	}
87
88
	private function validateBankData() {
89
		if ( $this->request->getPaymentType() !== PaymentType::DIRECT_DEBIT ) {
90
			return;
91
		}
92
93
		$bankData = $this->request->getBankData();
94
		$validationResult = $this->bankDataValidator->validate( $bankData );
0 ignored issues
show
Bug introduced by
It seems like $bankData defined by $this->request->getBankData() on line 93 can be null; however, WMDE\Fundraising\Fronten...taValidator::validate() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
95
96
		$this->addViolations( $validationResult->getViolations() );
97
		$this->validateFieldLength( $bankData->getBankName(), Result::SOURCE_BANK_NAME );
98
		$this->validateFieldLength( $bankData->getBic(), Result::SOURCE_BIC );
99
	}
100
101
	private function validateDonorEmail() {
102
		if ( $this->request->donorIsAnonymous() ) {
103
			return;
104
		}
105
		if ( $this->emailValidator->validate( $this->request->getDonorEmailAddress() )->hasViolations() ) {
106
			$this->addViolations( [ new ConstraintViolation(
107
				$this->request->getDonorEmailAddress(),
108
				Result::VIOLATION_MISSING,
109
				Result::SOURCE_DONOR_EMAIL
110
			) ] );
111
		} else {
112
			$this->validateFieldLength( $this->request->getDonorEmailAddress(), Result::SOURCE_DONOR_EMAIL );
113
		}
114
	}
115
116
	private function validateDonorName() {
117
		if ( $this->request->donorIsAnonymous() ) {
118
			return;
119
		}
120
		if ( $this->request->donorIsCompany() ) {
121
			$this->validateCompanyName();
122
		}
123
		else {
124
			$this->validatePersonName();
125
		}
126
	}
127
128
	private function validateCompanyName() {
129
		if ( $this->request->getDonorCompany() === '' ) {
130
			$this->violations[] = new ConstraintViolation(
131
				$this->request->getDonorCompany(),
132
				Result::VIOLATION_MISSING,
133
				Result::SOURCE_DONOR_COMPANY
134
			);
135
		} else {
136
			$this->validateFieldLength( $this->request->getDonorCompany(), Result::SOURCE_DONOR_COMPANY );
137
		}
138
	}
139
140
	private function validatePersonName() {
141
		$violations = [];
142
143
		if ( $this->request->getDonorFirstName() === '' ) {
144
			$violations[] = new ConstraintViolation(
145
				$this->request->getDonorFirstName(),
146
				Result::VIOLATION_MISSING,
147
				Result::SOURCE_DONOR_FIRST_NAME
148
			);
149
		} else {
150
			$this->validateFieldLength( $this->request->getDonorFirstName(), Result::SOURCE_DONOR_FIRST_NAME );
151
		}
152
153
		if ( $this->request->getDonorLastName() === '' ) {
154
			$violations[] = new ConstraintViolation(
155
				$this->request->getDonorLastName(),
156
				Result::VIOLATION_MISSING,
157
				Result::SOURCE_DONOR_LAST_NAME
158
			);
159
		} else {
160
			$this->validateFieldLength( $this->request->getDonorLastName(), Result::SOURCE_DONOR_LAST_NAME );
161
		}
162
163
		if ( $this->request->getDonorSalutation() === '' ) {
164
			$violations[] = new ConstraintViolation(
165
				$this->request->getDonorSalutation(),
166
				Result::VIOLATION_MISSING,
167
				Result::SOURCE_DONOR_SALUTATION
168
			);
169
		} else {
170
			$this->validateFieldLength( $this->request->getDonorSalutation(), Result::SOURCE_DONOR_SALUTATION );
171
		}
172
173
		$this->validateFieldLength( $this->request->getDonorTitle(), Result::SOURCE_DONOR_TITLE );
174
		// TODO: check if donor title is in the list of allowed titles?
175
176
		$this->addViolations( $violations );
177
	}
178
179
	private function validateDonorAddress() {
180
		if ( $this->request->donorIsAnonymous() ) {
181
			return;
182
		}
183
184
		$violations = [];
185
186
		if ( $this->request->getDonorStreetAddress() === '' ) {
187
			$violations[] = new ConstraintViolation(
188
				$this->request->getDonorStreetAddress(),
189
				Result::VIOLATION_MISSING,
190
				Result::SOURCE_DONOR_STREET_ADDRESS
191
			);
192
		} else {
193
			$this->validateFieldLength( $this->request->getDonorStreetAddress(), Result::SOURCE_DONOR_STREET_ADDRESS );
194
		}
195
196
		if ( $this->request->getDonorPostalCode() === '' ) {
197
			$violations[] = new ConstraintViolation(
198
				$this->request->getDonorPostalCode(),
199
				Result::VIOLATION_MISSING,
200
				Result::SOURCE_DONOR_POSTAL_CODE
201
			);
202
		} else {
203
			$this->validateFieldLength( $this->request->getDonorPostalCode(), Result::SOURCE_DONOR_POSTAL_CODE );
204
		}
205
206
		if ( $this->request->getDonorCity() === '' ) {
207
			$violations[] = new ConstraintViolation(
208
				$this->request->getDonorCity(),
209
				Result::VIOLATION_MISSING,
210
				Result::SOURCE_DONOR_CITY
211
			);
212
		} else {
213
			$this->validateFieldLength( $this->request->getDonorCity(), Result::SOURCE_DONOR_CITY );
214
		}
215
216
		if ( $this->request->getDonorCountryCode() === '' ) {
217
			$violations[] = new ConstraintViolation(
218
				$this->request->getDonorCountryCode(),
219
				Result::VIOLATION_MISSING,
220
				Result::SOURCE_DONOR_COUNTRY
221
			);
222
		} else {
223
			$this->validateFieldLength( $this->request->getDonorCountryCode(), Result::SOURCE_DONOR_COUNTRY );
224
		}
225
226
		if ( !preg_match( '/^\\d{4,5}$/', $this->request->getDonorPostalCode() ) ) {
227
			$violations[] = new ConstraintViolation(
228
				$this->request->getDonorPostalCode(),
229
				Result::VIOLATION_NOT_POSTCODE,
230
				Result::SOURCE_DONOR_POSTAL_CODE
231
			);
232
		}
233
234
		$this->addViolations( $violations );
235
	}
236
237
	private function validatePayment() {
238
		if ( ! in_array( $this->request->getPaymentType(), PaymentType::getPaymentTypes() ) ) {
239
			$this->violations[] = new ConstraintViolation(
240
				$this->request->getPaymentType(),
241
				Result::VIOLATION_WRONG_PAYMENT_TYPE,
242
				Result::SOURCE_PAYMENT_TYPE
243
			);
244
		}
245
	}
246
247
	private function validateFieldLength( string $value, string $fieldName ) {
248
		if ( strlen( $value ) > $this->maximumFieldLengths[$fieldName] )  {
249
			$this->violations[] = new ConstraintViolation( $value, Result::VIOLATION_WRONG_LENGTH, $fieldName );
250
		}
251
	}
252
}