PluginProbe ʕ •ᴥ•ʔ
MailPoet – Newsletters, Email Marketing, and Automation / 5.34.2
MailPoet – Newsletters, Email Marketing, and Automation v5.34.2
5.34.3 5.34.2 5.34.1 5.34.0 5.33.1 5.33.0 5.32.0 5.31.0 5.30.0 5.29.0 5.28.1 5.28.0 5.27.0 5.26.0 5.26.1 5.25.0 5.24.0 4.43.0 4.43.1 4.44.0 4.44.1 4.45.0 4.46.0 4.47.0 4.48.0 4.48.1 4.48.2 4.49.0 4.49.1 4.5.0 4.5.1 4.5.2 4.50.0 4.50.1 4.51.0 4.51.1 4.51.2 4.52.0 4.53.0 4.54.0 4.55.0 4.56.0 4.57.0 4.58.0 4.58.1 4.58.2 4.6.0 4.6.1 4.6.2 4.7.0 4.7.1 4.8.0 4.8.1 4.9.0 5.0.0 5.0.1 5.0.2 5.1.0 5.1.1 5.10.0 5.10.1 5.11.0 5.12.0 5.12.1 5.12.10 5.12.11 5.12.12 5.12.13 5.12.2 5.12.3 5.12.4 5.12.5 5.12.6 5.12.7 5.12.8 5.12.9 5.13.0 5.13.1 5.13.2 5.14.0 5.14.1 5.14.2 5.14.3 5.15.0 5.15.1 5.16.0 5.16.1 5.16.2 5.16.3 5.16.4 5.17.0 5.17.1 5.17.2 5.17.3 5.17.4 5.17.5 5.17.6 5.18.0 5.19.0 5.2.0 5.2.1 5.2.2 5.2.3 5.20.0 5.21.0 5.21.1 5.21.2 5.21.3 5.22.0 5.22.1 5.22.2 5.22.3 5.22.4 5.23.0 5.23.1 5.23.2 5.3.0 5.3.1 5.3.2 5.3.3 5.3.4 5.3.5 5.3.6 5.3.7 5.4.0 5.4.1 5.4.2 5.5.0 5.5.1 5.5.2 5.6.0 5.6.1 5.6.2 5.6.3 5.6.4 5.7.0 5.7.1 5.8.0 5.8.1 5.9.0 3.0.0-beta.15 3.7.1 3.0.0-beta.16 3.7.2 3.0.0-beta.17 3.7.3 3.0.0-beta.18 3.7.4 3.0.0-beta.19 3.7.5 3.0.0-beta.2 3.7.6 3.0.0-beta.20 3.7.8 3.0.0-beta.21 3.70.0 3.0.0-beta.22 3.71.0 3.0.0-beta.23 3.71.1 3.0.0-beta.23.1 3.71.2 3.0.0-beta.23.2 3.71.3 3.0.0-beta.24 3.72.0 3.0.0-beta.25 3.73.0 3.0.0-beta.26 3.73.1 3.0.0-beta.27 3.73.2 3.0.0-beta.28 3.74.0 3.0.0-beta.29 3.74.1 3.0.0-beta.3 3.74.2 3.0.0-beta.30 3.74.3 3.0.0-beta.31 3.75.0 3.0.0-beta.32 3.75.1 3.0.0-beta.33 3.76.0 3.0.0-beta.33.1 3.77.0 3.0.0-beta.34.0.0 3.77.1 3.0.0-beta.36.0.0 3.78.0 3.0.0-beta.36.0.1 3.79.0 3.0.0-beta.36.2.0 3.8 3.0.0-beta.36.3.0 3.8.1 3.0.0-beta.36.3.1 3.8.2 3.0.0-beta.37.0.0 3.8.3 3.0.0-beta.4 3.8.4 3.0.0-beta.5 3.8.5 3.0.0-beta.6 3.8.6 3.0.0-beta.7 3.80.0 3.0.0-beta.7.1 3.81.0 3.0.0-beta.8 3.82.0 3.0.0-beta.9 3.83.0 3.0.0-rc.1.0.0 3.84.0 3.0.0-rc.1.0.1 3.84.1 3.0.0-rc.1.0.2 3.85.0 3.0.0-rc.1.0.3 3.85.1 3.0.0-rc.1.0.4 3.86.0 3.0.0-rc.2.0.0 3.87.0 3.0.0-rc.2.0.1 3.87.1 3.0.0-rc.2.0.2 3.87.2 3.0.0-rc.2.0.3 3.88.0 3.0.1 3.88.1 3.0.2 3.88.2 3.0.3 3.89.0 3.0.4 3.89.1 3.0.5 3.89.2 3.0.6 3.89.3 3.0.7 3.89.4 3.0.8 3.9.0 3.0.9 3.9.1 3.1.0 3.90.0 3.10 3.90.1 3.10.1 3.90.2 3.100.0 3.91.0 3.100.1 3.91.1 3.100.2 3.92.0 3.101.0 3.92.1 3.101.1 3.93.0 3.102.0 3.93.1 3.102.1 3.94.0 3.103.0 3.95.0 3.103.1 3.95.1 3.11.0 3.96.0 3.11.1 3.96.1 3.11.2 3.97.0 3.11.3 3.98.0 3.11.4 3.98.1 3.11.5 3.99.0 3.12.0 3.99.1 3.12.1 4.0.0 3.13.0 4.0.1 3.14.0 4.1.0 3.14.1 4.1.1 3.15.0 4.10.0 3.16.0 4.11.0 3.16.1 4.11.1 3.16.2 4.12.0 3.16.3 4.12.1 3.17.0 4.12.2 3.17.1 4.13.0 3.17.2 4.14.0 3.18.0 4.15.0 3.18.1 4.16.0 3.18.2 4.17.0 3.19.0 4.17.1 3.19.1 4.18.0 3.19.2 4.18.1 3.19.3 4.19.0 3.2.0 4.2.0 3.2.1 4.20.0 3.2.2 4.20.1 3.2.3 4.20.2 3.2.4 4.21.0 3.2.5 4.22.0 3.20.0 4.22.1 3.21.0 4.22.2 3.21.1 4.23.0 3.22.0 4.24.0 3.23.0 4.25.0 3.23.1 4.26.0 3.23.2 4.26.1 3.24.0 4.27.0 3.25.0 4.28.0 3.25.1 4.29.0 3.26.0 4.3.0 3.26.1 4.3.1 3.27.0 4.30.0 3.28.0 4.31.0 3.29.0 4.31.1 3.3.0 4.32.0 3.3.1 4.33.0 3.3.2 4.34.0 3.3.3 4.35.0 3.3.4 4.35.1 3.3.5 4.36.0 3.3.6 4.37.0 3.30.0 4.38.0 3.31.0 4.39.0 3.31.1 4.4.0 3.32.0 4.40.0 3.32.1 4.41.0 3.32.2 4.41.1 3.33.0 4.41.2 3.34.0 4.41.3 3.34.1 4.42.0 3.34.2 4.42.1 3.34.3 3.34.4 3.35.0 3.35.1 3.35.3 3.35.4 3.36.0 3.37.0 3.37.1 3.37.2 3.37.3 3.38.0 3.38.1 3.39.0 3.39.1 3.39.2 3.4.0 3.4.1 3.4.2 3.4.3 3.4.4 3.40.0 3.40.1 3.41.0 3.41.1 3.41.2 3.42.0 3.42.1 3.42.2 3.42.3 3.43.0 3.43.1 3.44.0 3.45.0 3.45.1 3.46.0 3.46.1 3.46.10 3.46.11 3.46.12 3.46.13 3.46.14 3.46.2 3.46.3 3.46.4 3.46.5 3.46.6 3.46.7 3.46.8 3.46.9 3.47.0 3.47.1 3.47.10 3.47.11 3.47.2 3.47.3 3.47.5 3.47.6 3.47.7 3.47.9 3.48.0 3.48.1 3.49.0 3.49.1 3.5.0 3.5.1 3.50.0 3.51.0 3.51.1 3.51.2 3.52.0 3.53.0 3.54.0 3.54.1 3.54.2 3.54.3 3.55.0 3.55.1 3.56.0 3.56.1 3.56.2 3.57.0 3.57.1 3.58.0 3.59.0 3.59.1 3.59.2 3.6.0 3.6.1 3.6.2 3.6.3 3.6.4 3.6.5 3.6.6 3.6.7 3.60.0 3.60.1 3.60.10 3.60.11 3.60.12 3.60.2 3.60.3 3.60.4 3.60.6 3.60.7 3.60.8 3.60.9 3.61.0 3.62.0 3.62.1 3.63.0 3.64.0 3.64.1 3.64.2 3.64.3 3.65.0 trunk 3.65.1 3.0.0 3.66.0 3.0.0-beta.1 3.67.0 3.0.0-beta.10 3.67.1 3.0.0-beta.11 3.68.0 3.0.0-beta.12 3.69.0 3.0.0-beta.13 3.69.1 3.0.0-beta.14 3.7.0
mailpoet / lib / API / REST / ListingRequestValidationTrait.php
mailpoet / lib / API / REST Last commit date
API.php 6 months ago AbstractListingEndpoint.php 3 weeks ago ApiException.php 2 months ago Endpoint.php 3 months ago EndpointContainer.php 3 years ago ErrorResponse.php 3 years ago Exception.php 3 years ago ListingRequestValidationTrait.php 1 month ago Request.php 3 years ago Response.php 1 year ago index.php 3 years ago
ListingRequestValidationTrait.php
140 lines
1 <?php declare(strict_types = 1);
2
3 namespace MailPoet\API\REST;
4
5 if (!defined('ABSPATH')) exit;
6
7
8 use DateTimeImmutable;
9
10 /**
11 * Shared request validation for DataViews-backed listing endpoints
12 * (see {@see AbstractListingEndpoint}). Provides the reusable building blocks —
13 * sort field/order, pagination integers, and `yyyy-MM-dd` date filters — so each
14 * listing only declares its own allowed sort fields and filter keys.
15 *
16 * Error codes are namespaced per listing via {@see getListingValidationErrorPrefix()}
17 * so a 400 still says which listing rejected the request
18 * (e.g. `mailpoet_logs_invalid_orderby`).
19 */
20 trait ListingRequestValidationTrait {
21 /** Lowercase listing slug used to build error codes, e.g. `logs` or `forms`. */
22 abstract protected function getListingValidationErrorPrefix(): string;
23
24 private function listingValidationError(string $message, string $suffix): ApiException {
25 return new ApiException(
26 $message,
27 400,
28 'mailpoet_' . $this->getListingValidationErrorPrefix() . '_invalid_' . $suffix
29 );
30 }
31
32 /**
33 * @param mixed $sortField
34 * @param string[] $allowedFields
35 */
36 protected function validateSortField($sortField, array $allowedFields): void {
37 if ($sortField === null || $sortField === '') {
38 return;
39 }
40 if (!is_string($sortField) || !in_array($sortField, $allowedFields, true)) {
41 throw $this->listingValidationError(
42 sprintf(
43 // translators: %s is a comma-separated list of allowed sort fields.
44 __('Unsupported sort field. Allowed values are: %s.', 'mailpoet'),
45 implode(', ', $allowedFields)
46 ),
47 'orderby'
48 );
49 }
50 }
51
52 /** @param mixed $sortOrder */
53 protected function validateSortOrder($sortOrder): void {
54 if ($sortOrder === null || $sortOrder === '') {
55 return;
56 }
57 if (!is_string($sortOrder) || !in_array(strtolower($sortOrder), ['asc', 'desc'], true)) {
58 throw $this->listingValidationError(
59 sprintf(
60 // translators: %s is a comma-separated list of allowed sort orders.
61 __('Unsupported sort order. Allowed values are: %s.', 'mailpoet'),
62 implode(', ', ['asc', 'desc'])
63 ),
64 'order'
65 );
66 }
67 }
68
69 protected function validatePagination(Request $request): void {
70 $this->validatePositiveInteger($request->getParam('page'), 'page', 1, self::MAX_PAGE);
71 $this->validatePositiveInteger($request->getParam('per_page'), 'per_page', 1, self::MAX_PER_PAGE);
72 $this->validatePositiveInteger($request->getParam('limit'), 'limit', 1, self::MAX_PER_PAGE);
73 $this->validatePositiveInteger($request->getParam('offset'), 'offset', 0, self::MAX_PAGE);
74 }
75
76 /** @param mixed $value */
77 private function validatePositiveInteger($value, string $name, int $min, int $max): void {
78 if ($value === null || $value === '') {
79 return;
80 }
81 $integer = $this->getIntegerValue($value);
82 if ($integer === null || $integer < $min || $integer > $max) {
83 throw $this->listingValidationError(
84 sprintf(
85 // translators: %1$s is a request parameter name, %2$d is the maximum accepted value.
86 __('%1$s must be an integer no greater than %2$d.', 'mailpoet'),
87 $name,
88 $max
89 ),
90 $name
91 );
92 }
93 }
94
95 /** @param mixed $value */
96 private function getIntegerValue($value): ?int {
97 if (is_int($value)) {
98 return $value;
99 }
100 if (is_string($value) && ctype_digit($value)) {
101 return (int)$value;
102 }
103 return null;
104 }
105
106 /**
107 * @param array<string, mixed> $filters
108 */
109 protected function validateDateFilter(array $filters, string $field): ?DateTimeImmutable {
110 if (!array_key_exists($field, $filters) || $filters[$field] === '') {
111 return null;
112 }
113 if (!is_string($filters[$field])) {
114 throw $this->listingValidationError(
115 __('Date filters must use the YYYY-MM-DD format.', 'mailpoet'),
116 $field
117 );
118 }
119
120 $date = DateTimeImmutable::createFromFormat('!Y-m-d', $filters[$field]);
121 $errors = DateTimeImmutable::getLastErrors();
122 if (!$date || (is_array($errors) && ($errors['warning_count'] > 0 || $errors['error_count'] > 0)) || $date->format('Y-m-d') !== $filters[$field]) {
123 throw $this->listingValidationError(
124 __('Date filters must use the YYYY-MM-DD format.', 'mailpoet'),
125 $field
126 );
127 }
128 return $date;
129 }
130
131 protected function validateDateRange(?DateTimeImmutable $from, ?DateTimeImmutable $to): void {
132 if ($from && $to && $from > $to) {
133 throw $this->listingValidationError(
134 __('The from date must be before or equal to the to date.', 'mailpoet'),
135 'date_range'
136 );
137 }
138 }
139 }
140