Copy Validator to email-editor package
Because the email-editor package should be independent. We copy Validator to the package, at least for now. [MAILPOET-6216]
This commit is contained in:
@ -2,7 +2,7 @@
|
||||
|
||||
namespace MailPoet\EmailEditor\Engine;
|
||||
|
||||
use MailPoet\Validator\Builder;
|
||||
use MailPoet\EmailEditor\Validator\Builder;
|
||||
|
||||
class EmailApiController {
|
||||
/**
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
namespace MailPoet\EmailEditor\Engine;
|
||||
|
||||
use MailPoet\Validator\Builder;
|
||||
use MailPoet\EmailEditor\Validator\Builder;
|
||||
|
||||
class EmailStylesSchema {
|
||||
public function getSchema(): array {
|
||||
|
@ -3,7 +3,7 @@
|
||||
namespace MailPoet\EmailEditor\Engine\Templates;
|
||||
|
||||
use MailPoet\EmailEditor\Engine\ThemeController;
|
||||
use MailPoet\Validator\Builder;
|
||||
use MailPoet\EmailEditor\Validator\Builder;
|
||||
use WP_Theme_JSON;
|
||||
|
||||
class TemplatePreview {
|
||||
|
57
packages/php/email-editor/src/Validator/Builder.php
Normal file
57
packages/php/email-editor/src/Validator/Builder.php
Normal file
@ -0,0 +1,57 @@
|
||||
<?php declare(strict_types = 1);
|
||||
|
||||
namespace MailPoet\EmailEditor\Validator;
|
||||
|
||||
use MailPoet\EmailEditor\Validator\Schema\AnyOfSchema;
|
||||
use MailPoet\EmailEditor\Validator\Schema\ArraySchema;
|
||||
use MailPoet\EmailEditor\Validator\Schema\BooleanSchema;
|
||||
use MailPoet\EmailEditor\Validator\Schema\IntegerSchema;
|
||||
use MailPoet\EmailEditor\Validator\Schema\NullSchema;
|
||||
use MailPoet\EmailEditor\Validator\Schema\NumberSchema;
|
||||
use MailPoet\EmailEditor\Validator\Schema\ObjectSchema;
|
||||
use MailPoet\EmailEditor\Validator\Schema\OneOfSchema;
|
||||
use MailPoet\EmailEditor\Validator\Schema\StringSchema;
|
||||
|
||||
// See: https://developer.wordpress.org/rest-api/extending-the-rest-api/schema/
|
||||
class Builder {
|
||||
public static function string(): StringSchema {
|
||||
return new StringSchema();
|
||||
}
|
||||
|
||||
public static function number(): NumberSchema {
|
||||
return new NumberSchema();
|
||||
}
|
||||
|
||||
public static function integer(): IntegerSchema {
|
||||
return new IntegerSchema();
|
||||
}
|
||||
|
||||
public static function boolean(): BooleanSchema {
|
||||
return new BooleanSchema();
|
||||
}
|
||||
|
||||
public static function null(): NullSchema {
|
||||
return new NullSchema();
|
||||
}
|
||||
|
||||
public static function array(Schema $items = null): ArraySchema {
|
||||
$array = new ArraySchema();
|
||||
return $items ? $array->items($items) : $array;
|
||||
}
|
||||
|
||||
/** @param array<string, Schema>|null $properties */
|
||||
public static function object(array $properties = null): ObjectSchema {
|
||||
$object = new ObjectSchema();
|
||||
return $properties === null ? $object : $object->properties($properties);
|
||||
}
|
||||
|
||||
/** @param Schema[] $schemas */
|
||||
public static function oneOf(array $schemas): OneOfSchema {
|
||||
return new OneOfSchema($schemas);
|
||||
}
|
||||
|
||||
/** @param Schema[] $schemas */
|
||||
public static function anyOf(array $schemas): AnyOfSchema {
|
||||
return new AnyOfSchema($schemas);
|
||||
}
|
||||
}
|
97
packages/php/email-editor/src/Validator/Schema.php
Normal file
97
packages/php/email-editor/src/Validator/Schema.php
Normal file
@ -0,0 +1,97 @@
|
||||
<?php declare(strict_types = 1);
|
||||
|
||||
namespace MailPoet\EmailEditor\Validator;
|
||||
|
||||
|
||||
use function json_encode;
|
||||
use function rest_get_allowed_schema_keywords;
|
||||
|
||||
abstract class Schema {
|
||||
protected $schema = [];
|
||||
|
||||
/** @return static */
|
||||
public function nullable() {
|
||||
$type = $this->schema['type'] ?? ['null'];
|
||||
return $this->updateSchemaProperty('type', is_array($type) ? $type : [$type, 'null']);
|
||||
}
|
||||
|
||||
/** @return static */
|
||||
public function nonNullable() {
|
||||
$type = $this->schema['type'] ?? null;
|
||||
return $type === null
|
||||
? $this->unsetSchemaProperty('type')
|
||||
: $this->updateSchemaProperty('type', is_array($type) ? $type[0] : $type);
|
||||
}
|
||||
|
||||
/** @return static */
|
||||
public function required() {
|
||||
return $this->updateSchemaProperty('required', true);
|
||||
}
|
||||
|
||||
/** @return static */
|
||||
public function optional() {
|
||||
return $this->unsetSchemaProperty('required');
|
||||
}
|
||||
|
||||
/** @return static */
|
||||
public function title(string $title) {
|
||||
return $this->updateSchemaProperty('title', $title);
|
||||
}
|
||||
|
||||
/** @return static */
|
||||
public function description(string $description) {
|
||||
return $this->updateSchemaProperty('description', $description);
|
||||
}
|
||||
|
||||
/** @return static */
|
||||
public function default($default) {
|
||||
return $this->updateSchemaProperty('default', $default);
|
||||
}
|
||||
|
||||
/** @return static */
|
||||
public function field(string $name, $value) {
|
||||
if (in_array($name, $this->getReservedKeywords(), true)) {
|
||||
throw new \Exception("Field name '$name' is reserved");
|
||||
}
|
||||
return $this->updateSchemaProperty($name, $value);
|
||||
}
|
||||
|
||||
public function toArray(): array {
|
||||
return $this->schema;
|
||||
}
|
||||
|
||||
public function toString(): string {
|
||||
$json = json_encode($this->schema, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRESERVE_ZERO_FRACTION);
|
||||
$error = json_last_error();
|
||||
if ($error || $json === false) {
|
||||
throw new \Exception(json_last_error_msg(), (string)$error);
|
||||
}
|
||||
return $json;
|
||||
}
|
||||
|
||||
/** @return static */
|
||||
protected function updateSchemaProperty(string $name, $value) {
|
||||
$clone = clone $this;
|
||||
$clone->schema[$name] = $value;
|
||||
return $clone;
|
||||
}
|
||||
|
||||
/** @return static */
|
||||
protected function unsetSchemaProperty(string $name) {
|
||||
$clone = clone $this;
|
||||
unset($clone->schema[$name]);
|
||||
return $clone;
|
||||
}
|
||||
|
||||
protected function getReservedKeywords(): array {
|
||||
return rest_get_allowed_schema_keywords();
|
||||
}
|
||||
|
||||
protected function validatePattern(string $pattern): void {
|
||||
$escaped = str_replace('#', '\\#', $pattern);
|
||||
$regex = "#$escaped#u";
|
||||
if (@preg_match($regex, '') === false) {
|
||||
throw new \Exception("Invalid regular expression '$regex'");
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
<?php declare(strict_types = 1);
|
||||
|
||||
namespace MailPoet\EmailEditor\Validator\Schema;
|
||||
|
||||
use MailPoet\EmailEditor\Validator\Schema;
|
||||
|
||||
// See: https://developer.wordpress.org/rest-api/extending-the-rest-api/schema/#oneof-and-anyof
|
||||
class AnyOfSchema extends Schema {
|
||||
protected $schema = [
|
||||
'anyOf' => [],
|
||||
];
|
||||
|
||||
/** @param Schema[] $schemas */
|
||||
public function __construct(
|
||||
array $schemas
|
||||
) {
|
||||
foreach ($schemas as $schema) {
|
||||
$this->schema['anyOf'][] = $schema->toArray();
|
||||
}
|
||||
}
|
||||
|
||||
public function nullable(): self {
|
||||
$null = ['type' => 'null'];
|
||||
$anyOf = $this->schema['anyOf'];
|
||||
$value = in_array($null, $anyOf, true) ? $anyOf : array_merge($anyOf, [$null]);
|
||||
return $this->updateSchemaProperty('anyOf', $value);
|
||||
}
|
||||
|
||||
public function nonNullable(): self {
|
||||
$null = ['type' => 'null'];
|
||||
$anyOf = $this->schema['anyOf'];
|
||||
$value = array_filter($anyOf, function ($item) use ($null) {
|
||||
return $item !== $null;
|
||||
});
|
||||
return $this->updateSchemaProperty('anyOf', $value);
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
<?php declare(strict_types = 1);
|
||||
|
||||
namespace MailPoet\EmailEditor\Validator\Schema;
|
||||
|
||||
use MailPoet\EmailEditor\Validator\Schema;
|
||||
|
||||
// See: https://developer.wordpress.org/rest-api/extending-the-rest-api/schema/#arrays
|
||||
class ArraySchema extends Schema {
|
||||
protected $schema = [
|
||||
'type' => 'array',
|
||||
];
|
||||
|
||||
public function items(Schema $schema): self {
|
||||
return $this->updateSchemaProperty('items', $schema->toArray());
|
||||
}
|
||||
|
||||
public function minItems(int $value): self {
|
||||
return $this->updateSchemaProperty('minItems', $value);
|
||||
}
|
||||
|
||||
public function maxItems(int $value): self {
|
||||
return $this->updateSchemaProperty('maxItems', $value);
|
||||
}
|
||||
|
||||
public function uniqueItems(): self {
|
||||
return $this->updateSchemaProperty('uniqueItems', true);
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
<?php declare(strict_types = 1);
|
||||
|
||||
namespace MailPoet\EmailEditor\Validator\Schema;
|
||||
|
||||
use MailPoet\EmailEditor\Validator\Schema;
|
||||
|
||||
// See: https://developer.wordpress.org/rest-api/extending-the-rest-api/schema/#primitive-types
|
||||
class BooleanSchema extends Schema {
|
||||
protected $schema = [
|
||||
'type' => 'boolean',
|
||||
];
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
<?php declare(strict_types = 1);
|
||||
|
||||
namespace MailPoet\EmailEditor\Validator\Schema;
|
||||
|
||||
use MailPoet\EmailEditor\Validator\Schema;
|
||||
|
||||
// See: https://developer.wordpress.org/rest-api/extending-the-rest-api/schema/#numbers
|
||||
class IntegerSchema extends Schema {
|
||||
protected $schema = [
|
||||
'type' => 'integer',
|
||||
];
|
||||
|
||||
public function minimum(int $value): self {
|
||||
return $this->updateSchemaProperty('minimum', $value)
|
||||
->unsetSchemaProperty('exclusiveMinimum');
|
||||
}
|
||||
|
||||
public function exclusiveMinimum(int $value): self {
|
||||
return $this->updateSchemaProperty('minimum', $value)
|
||||
->updateSchemaProperty('exclusiveMinimum', true);
|
||||
}
|
||||
|
||||
public function maximum(int $value): self {
|
||||
return $this->updateSchemaProperty('maximum', $value)
|
||||
->unsetSchemaProperty('exclusiveMaximum');
|
||||
}
|
||||
|
||||
public function exclusiveMaximum(int $value): self {
|
||||
return $this->updateSchemaProperty('maximum', $value)
|
||||
->updateSchemaProperty('exclusiveMaximum', true);
|
||||
}
|
||||
|
||||
public function multipleOf(int $value): self {
|
||||
return $this->updateSchemaProperty('multipleOf', $value);
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
<?php declare(strict_types = 1);
|
||||
|
||||
namespace MailPoet\EmailEditor\Validator\Schema;
|
||||
|
||||
use MailPoet\EmailEditor\Validator\Schema;
|
||||
|
||||
// See: https://developer.wordpress.org/rest-api/extending-the-rest-api/schema/#primitive-types
|
||||
class NullSchema extends Schema {
|
||||
protected $schema = [
|
||||
'type' => 'null',
|
||||
];
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
<?php declare(strict_types = 1);
|
||||
|
||||
namespace MailPoet\EmailEditor\Validator\Schema;
|
||||
|
||||
use MailPoet\EmailEditor\Validator\Schema;
|
||||
|
||||
// See: https://developer.wordpress.org/rest-api/extending-the-rest-api/schema/#numbers
|
||||
class NumberSchema extends Schema {
|
||||
protected $schema = [
|
||||
'type' => 'number',
|
||||
];
|
||||
|
||||
public function minimum(float $value): self {
|
||||
return $this->updateSchemaProperty('minimum', $value)
|
||||
->unsetSchemaProperty('exclusiveMinimum');
|
||||
}
|
||||
|
||||
public function exclusiveMinimum(float $value): self {
|
||||
return $this->updateSchemaProperty('minimum', $value)
|
||||
->updateSchemaProperty('exclusiveMinimum', true);
|
||||
}
|
||||
|
||||
public function maximum(float $value): self {
|
||||
return $this->updateSchemaProperty('maximum', $value)
|
||||
->unsetSchemaProperty('exclusiveMaximum');
|
||||
}
|
||||
|
||||
public function exclusiveMaximum(float $value): self {
|
||||
return $this->updateSchemaProperty('maximum', $value)
|
||||
->updateSchemaProperty('exclusiveMaximum', true);
|
||||
}
|
||||
|
||||
public function multipleOf(float $value): self {
|
||||
return $this->updateSchemaProperty('multipleOf', $value);
|
||||
}
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
<?php declare(strict_types = 1);
|
||||
|
||||
namespace MailPoet\EmailEditor\Validator\Schema;
|
||||
|
||||
use MailPoet\EmailEditor\Validator\Schema;
|
||||
|
||||
// See: https://developer.wordpress.org/rest-api/extending-the-rest-api/schema/#objects
|
||||
class ObjectSchema extends Schema {
|
||||
protected $schema = [
|
||||
'type' => 'object',
|
||||
];
|
||||
|
||||
/** @param array<string, Schema> $properties */
|
||||
public function properties(array $properties): self {
|
||||
return $this->updateSchemaProperty('properties', array_map(
|
||||
function (Schema $property) {
|
||||
return $property->toArray();
|
||||
},
|
||||
$properties
|
||||
));
|
||||
}
|
||||
|
||||
public function additionalProperties(Schema $schema): self {
|
||||
return $this->updateSchemaProperty('additionalProperties', $schema->toArray());
|
||||
}
|
||||
|
||||
public function disableAdditionalProperties(): self {
|
||||
return $this->updateSchemaProperty('additionalProperties', false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Keys of $properties are regular expressions without leading/trailing delimiters.
|
||||
* See: https://developer.wordpress.org/rest-api/extending-the-rest-api/schema/#patternproperties
|
||||
*
|
||||
* @param array<string, Schema> $properties
|
||||
*/
|
||||
public function patternProperties(array $properties): self {
|
||||
$patternProperties = [];
|
||||
foreach ($properties as $key => $value) {
|
||||
$this->validatePattern($key);
|
||||
$patternProperties[$key] = $value->toArray();
|
||||
}
|
||||
return $this->updateSchemaProperty('patternProperties', $patternProperties);
|
||||
}
|
||||
|
||||
public function minProperties(int $value): self {
|
||||
return $this->updateSchemaProperty('minProperties', $value);
|
||||
}
|
||||
|
||||
public function maxProperties(int $value): self {
|
||||
return $this->updateSchemaProperty('maxProperties', $value);
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
<?php declare(strict_types = 1);
|
||||
|
||||
namespace MailPoet\EmailEditor\Validator\Schema;
|
||||
|
||||
use MailPoet\EmailEditor\Validator\Schema;
|
||||
|
||||
// See: https://developer.wordpress.org/rest-api/extending-the-rest-api/schema/#oneof-and-anyof
|
||||
class OneOfSchema extends Schema {
|
||||
protected $schema = [
|
||||
'oneOf' => [],
|
||||
];
|
||||
|
||||
/** @param Schema[] $schemas */
|
||||
public function __construct(
|
||||
array $schemas
|
||||
) {
|
||||
foreach ($schemas as $schema) {
|
||||
$this->schema['oneOf'][] = $schema->toArray();
|
||||
}
|
||||
}
|
||||
|
||||
public function nullable(): self {
|
||||
$null = ['type' => 'null'];
|
||||
$oneOf = $this->schema['oneOf'];
|
||||
$value = in_array($null, $oneOf, true) ? $oneOf : array_merge($oneOf, [$null]);
|
||||
return $this->updateSchemaProperty('oneOf', $value);
|
||||
}
|
||||
|
||||
public function nonNullable(): self {
|
||||
$null = ['type' => 'null'];
|
||||
$oneOf = $this->schema['oneOf'];
|
||||
$value = array_filter($oneOf, function ($item) use ($null) {
|
||||
return $item !== $null;
|
||||
});
|
||||
return $this->updateSchemaProperty('oneOf', $value);
|
||||
}
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
<?php declare(strict_types = 1);
|
||||
|
||||
namespace MailPoet\EmailEditor\Validator\Schema;
|
||||
|
||||
use MailPoet\EmailEditor\Validator\Schema;
|
||||
|
||||
// See: https://developer.wordpress.org/rest-api/extending-the-rest-api/schema/#strings
|
||||
class StringSchema extends Schema {
|
||||
protected $schema = [
|
||||
'type' => 'string',
|
||||
];
|
||||
|
||||
public function minLength(int $value): self {
|
||||
return $this->updateSchemaProperty('minLength', $value);
|
||||
}
|
||||
|
||||
public function maxLength(int $value): self {
|
||||
return $this->updateSchemaProperty('maxLength', $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parameter $pattern is a regular expression without leading/trailing delimiters.
|
||||
* See: https://developer.wordpress.org/rest-api/extending-the-rest-api/schema/#pattern
|
||||
*/
|
||||
public function pattern(string $pattern): self {
|
||||
$this->validatePattern($pattern);
|
||||
return $this->updateSchemaProperty('pattern', $pattern);
|
||||
}
|
||||
|
||||
public function formatDateTime(): self {
|
||||
return $this->updateSchemaProperty('format', 'date-time');
|
||||
}
|
||||
|
||||
public function formatEmail(): self {
|
||||
return $this->updateSchemaProperty('format', 'email');
|
||||
}
|
||||
|
||||
public function formatHexColor(): self {
|
||||
return $this->updateSchemaProperty('format', 'hex-color');
|
||||
}
|
||||
|
||||
public function formatIp(): self {
|
||||
return $this->updateSchemaProperty('format', 'ip');
|
||||
}
|
||||
|
||||
public function formatUri(): self {
|
||||
return $this->updateSchemaProperty('format', 'uri');
|
||||
}
|
||||
|
||||
public function formatUuid(): self {
|
||||
return $this->updateSchemaProperty('format', 'uuid');
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
<?php declare(strict_types = 1);
|
||||
|
||||
namespace MailPoet\EmailEditor\Validator;
|
||||
|
||||
use MailPoet\UnexpectedValueException;
|
||||
use WP_Error;
|
||||
|
||||
class ValidationException extends UnexpectedValueException {
|
||||
/** @var WP_Error */
|
||||
protected $wpError;
|
||||
|
||||
public static function createFromWpError(WP_Error $wpError): self {
|
||||
$exception = self::create()
|
||||
->withMessage($wpError->get_error_message());
|
||||
$exception->wpError = $wpError;
|
||||
return $exception;
|
||||
}
|
||||
|
||||
public function getWpError(): WP_Error {
|
||||
return $this->wpError;
|
||||
}
|
||||
}
|
209
packages/php/email-editor/src/Validator/Validator.php
Normal file
209
packages/php/email-editor/src/Validator/Validator.php
Normal file
@ -0,0 +1,209 @@
|
||||
<?php declare(strict_types = 1);
|
||||
|
||||
namespace MailPoet\EmailEditor\Validator;
|
||||
|
||||
use JsonSerializable;
|
||||
use MailPoet\WP\Functions as WPFunctions;
|
||||
use stdClass;
|
||||
use WP_Error;
|
||||
|
||||
class Validator {
|
||||
/** @var WPFunctions */
|
||||
private $wp;
|
||||
|
||||
public function __construct(
|
||||
WPFunctions $wp
|
||||
) {
|
||||
$this->wp = $wp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Strict validation & sanitization implementation.
|
||||
* It only coerces int to float (e.g. 5 to 5.0).
|
||||
*
|
||||
* @param mixed $value
|
||||
* @return mixed
|
||||
*/
|
||||
public function validate(Schema $schema, $value, string $paramName = 'value') {
|
||||
return $this->validateSchemaArray($schema->toArray(), $value, $paramName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Strict validation & sanitization implementation.
|
||||
* It only coerces int to float (e.g. 5 to 5.0).
|
||||
*
|
||||
* @param array $schema. The array must follow the format, which is returned from Schema::toArray().
|
||||
* @param mixed $value
|
||||
* @return mixed
|
||||
*/
|
||||
public function validateSchemaArray(array $schema, $value, string $paramName = 'value') {
|
||||
$result = $this->validateAndSanitizeValueFromSchema($value, $schema, $paramName);
|
||||
if ($result instanceof WP_Error) {
|
||||
throw ValidationException::createFromWpError($result);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mirrors rest_validate_value_from_schema() and rest_sanitize_value_from_schema().
|
||||
*
|
||||
* @param mixed $value
|
||||
* @param array $schema
|
||||
* @param string $paramName
|
||||
* @return mixed|WP_Error
|
||||
*/
|
||||
private function validateAndSanitizeValueFromSchema($value, array $schema, string $paramName) {
|
||||
// nullable
|
||||
$fullType = $schema['type'] ?? null;
|
||||
if (is_array($fullType) && in_array('null', $fullType, true) && $value === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// anyOf, oneOf
|
||||
if (isset($schema['anyOf'])) {
|
||||
return $this->validateAndSanitizeAnyOf($value, $schema, $paramName);
|
||||
} elseif (isset($schema['oneOf'])) {
|
||||
return $this->validateAndSanitizeOneOf($value, $schema, $paramName);
|
||||
}
|
||||
|
||||
// make types strict
|
||||
$type = is_array($fullType) ? $fullType[0] : $fullType;
|
||||
switch ($type) {
|
||||
case 'number':
|
||||
if (!is_float($value) && !is_int($value)) {
|
||||
return $this->getTypeError($paramName, $fullType);
|
||||
}
|
||||
break;
|
||||
case 'integer':
|
||||
if (!is_int($value)) {
|
||||
return $this->getTypeError($paramName, $fullType);
|
||||
}
|
||||
break;
|
||||
case 'boolean':
|
||||
if (!is_bool($value)) {
|
||||
return $this->getTypeError($paramName, $fullType);
|
||||
}
|
||||
break;
|
||||
case 'array':
|
||||
if (!is_array($value)) {
|
||||
return $this->getTypeError($paramName, $fullType);
|
||||
}
|
||||
|
||||
if (isset($schema['items'])) {
|
||||
foreach ($value as $i => $v) {
|
||||
$result = $this->validateAndSanitizeValueFromSchema($v, $schema['items'], $paramName . '[' . $i . ']');
|
||||
if ($this->wp->isWpError($result)) {
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'object':
|
||||
if (!is_array($value) && !$value instanceof stdClass && !$value instanceof JsonSerializable) {
|
||||
return $this->getTypeError($paramName, $fullType);
|
||||
}
|
||||
|
||||
// ensure string keys
|
||||
$value = (array)($value instanceof JsonSerializable ? $value->jsonSerialize() : $value);
|
||||
if (count(array_filter(array_keys($value), 'is_string')) !== count($value)) {
|
||||
return $this->getTypeError($paramName, $fullType);
|
||||
}
|
||||
|
||||
// validate object properties
|
||||
foreach ($value as $k => $v) {
|
||||
if (isset($schema['properties'][$k])) {
|
||||
$result = $this->validateAndSanitizeValueFromSchema($v, $schema['properties'][$k], $paramName . '[' . $k . ']');
|
||||
if ($this->wp->isWpError($result)) {
|
||||
return $result;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
$patternPropertySchema = $this->wp->restFindMatchingPatternPropertySchema($k, $schema);
|
||||
if ($patternPropertySchema) {
|
||||
$result = $this->validateAndSanitizeValueFromSchema($v, $patternPropertySchema, $paramName . '[' . $k . ']');
|
||||
if ($this->wp->isWpError($result)) {
|
||||
return $result;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isset($schema['additionalProperties']) && is_array($schema['additionalProperties'])) {
|
||||
$result = $this->validateAndSanitizeValueFromSchema($v, $schema['additionalProperties'], $paramName . '[' . $k . ']');
|
||||
if ($this->wp->isWpError($result)) {
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
$result = $this->wp->restValidateValueFromSchema($value, $schema, $paramName);
|
||||
if ($this->wp->isWpError($result)) {
|
||||
return $result;
|
||||
}
|
||||
return $this->wp->restSanitizeValueFromSchema($value, $schema, $paramName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mirrors rest_find_any_matching_schema().
|
||||
*
|
||||
* @param mixed $value
|
||||
* @return mixed|WP_Error
|
||||
*/
|
||||
private function validateAndSanitizeAnyOf($value, array $anyOfSchema, string $paramName) {
|
||||
$errors = [];
|
||||
foreach ($anyOfSchema['anyOf'] as $index => $schema) {
|
||||
$result = $this->validateAndSanitizeValueFromSchema($value, $schema, $paramName);
|
||||
if (!$this->wp->isWpError($result)) {
|
||||
return $result;
|
||||
}
|
||||
$errors[] = ['error_object' => $result, 'schema' => $schema, 'index' => $index];
|
||||
}
|
||||
return $this->wp->restGetCombiningOperationError($value, $paramName, $errors);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mirrors rest_find_one_matching_schema().
|
||||
*
|
||||
* @param mixed $value
|
||||
* @return mixed|WP_Error
|
||||
*/
|
||||
private function validateAndSanitizeOneOf($value, array $oneOfSchema, string $paramName) {
|
||||
$matchingSchemas = [];
|
||||
$errors = [];
|
||||
$data = null;
|
||||
foreach ($oneOfSchema['oneOf'] as $index => $schema) {
|
||||
$result = $this->validateAndSanitizeValueFromSchema($value, $schema, $paramName);
|
||||
if ($this->wp->isWpError($result)) {
|
||||
$errors[] = ['error_object' => $result, 'schema' => $schema, 'index' => $index];
|
||||
} else {
|
||||
$data = $result;
|
||||
$matchingSchemas[$index] = $schema;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$matchingSchemas) {
|
||||
return $this->wp->restGetCombiningOperationError($value, $paramName, $errors);
|
||||
}
|
||||
|
||||
if (count($matchingSchemas) > 1) {
|
||||
// reuse WP method to generate detailed error
|
||||
$invalidSchema = ['type' => []];
|
||||
$oneOf = array_replace(array_fill(0, count($oneOfSchema['oneOf']), $invalidSchema), $matchingSchemas);
|
||||
return $this->wp->restFindOneMatchingSchema($value, ['oneOf' => $oneOf], $paramName);
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
/** @param string|string[] $type */
|
||||
private function getTypeError(string $param, $type): WP_Error {
|
||||
$type = is_array($type) ? $type : [$type];
|
||||
return new WP_Error(
|
||||
'rest_invalid_type',
|
||||
// translators: %1$s is the current parameter and %2$s a comma-separated list of the allowed types.
|
||||
sprintf(__('%1$s is not of type %2$s.', 'mailpoet'), $param, implode(',', $type)),
|
||||
['param' => $param]
|
||||
);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user