| 1 |
<?php |
| 2 |
|
| 3 |
namespace Give\DonationForms\Actions; |
| 4 |
|
| 5 |
use Give\DonationForms\DataTransferObjects\ValidationRouteData; |
| 6 |
use Give\DonationForms\Exceptions\DonationFormFieldErrorsException; |
| 7 |
use Give\DonationForms\Exceptions\DonationFormForbidden; |
| 8 |
use Give\Helpers\Form\Utils as FormUtils; |
| 9 |
use WP_Error; |
| 10 |
|
| 11 |
/** |
| 12 |
* Holds a donation form request to the form's own validation rules before anything else acts on it. |
| 13 |
* |
| 14 |
* Gateways that must talk to their processor before the donate route runs (PayPal Commerce creates |
| 15 |
* its order when the PayPal button is clicked) call this so the request meets the same rules form |
| 16 |
* processing applies, without the gateway learning anything about form configuration. |
| 17 |
* |
| 18 |
* Visual Form Builder (v3) forms validate through ValidationRouteData, the same DTO the validate |
| 19 |
* route uses: every schema field present in the request is checked, security challenge fields are |
| 20 |
* skipped, and trashed or unpublished forms are refused. Option-based (v2) forms run the legacy |
| 21 |
* validator give_donation_form_validate_fields() and then fire give_checkout_error_checks, the same |
| 22 |
* sequence give_process_donation_form() runs before it creates a payment, so the level check and |
| 23 |
* add-on rules hooked there apply too. The legacy validator reads $_POST directly, so for v2 forms |
| 24 |
* the request must be the current POST request. |
| 25 |
* |
| 26 |
* @since 4.16.7.1 |
| 27 |
*/ |
| 28 |
class ValidateDonationFormRequest |
| 29 |
{ |
| 30 |
/** |
| 31 |
* @since 4.16.7.1 |
| 32 |
* |
| 33 |
* @param int $formId The form the caller already verified. For v3 forms it overrides any formId |
| 34 |
* in the request; for v2 forms the request's give-form-id must match it. |
| 35 |
* @param array $request The request values, keyed by field name. |
| 36 |
* |
| 37 |
* @throws DonationFormFieldErrorsException|DonationFormForbidden |
| 38 |
*/ |
| 39 |
public function __invoke(int $formId, array $request): void |
| 40 |
{ |
| 41 |
if (FormUtils::isV3Form($formId)) { |
| 42 |
$request['formId'] = $formId; |
| 43 |
|
| 44 |
ValidationRouteData::fromRequest($request)->validate(); |
| 45 |
|
| 46 |
return; |
| 47 |
} |
| 48 |
|
| 49 |
$this->validateLegacyRequest($formId); |
| 50 |
} |
| 51 |
|
| 52 |
/** |
| 53 |
* The legacy validator reports through the session error store, so it is cleared before and |
| 54 |
* after the run: before, so an earlier failed attempt in the same session cannot bleed in; |
| 55 |
* after, because the errors now live on the exception. |
| 56 |
* |
| 57 |
* @since 4.16.7.1 |
| 58 |
* |
| 59 |
* @throws DonationFormFieldErrorsException |
| 60 |
*/ |
| 61 |
private function validateLegacyRequest(int $formId): void |
| 62 |
{ |
| 63 |
if (absint($_POST['give-form-id'] ?? 0) !== $formId) { |
| 64 |
throw new DonationFormFieldErrorsException( |
| 65 |
new WP_Error( |
| 66 |
'give_invalid_donation_form', |
| 67 |
__('The donation form ID is invalid. Please reload the page and try again.', 'give') |
| 68 |
) |
| 69 |
); |
| 70 |
} |
| 71 |
|
| 72 |
give_clear_errors(); |
| 73 |
$validData = give_donation_form_validate_fields(); |
| 74 |
|
| 75 |
/** This action is documented in includes/process-donation.php */ |
| 76 |
do_action('give_checkout_error_checks', $validData, give_clean($_POST)); |
| 77 |
|
| 78 |
$errors = give_get_errors(); |
| 79 |
|
| 80 |
give_clear_errors(); |
| 81 |
|
| 82 |
if (!$errors) { |
| 83 |
return; |
| 84 |
} |
| 85 |
|
| 86 |
$wpError = new WP_Error(); |
| 87 |
|
| 88 |
foreach ($errors as $errorId => $error) { |
| 89 |
$wpError->add($errorId, is_array($error) ? $error['message'] : $error); |
| 90 |
} |
| 91 |
|
| 92 |
throw new DonationFormFieldErrorsException($wpError); |
| 93 |
} |
| 94 |
} |
| 95 |
|