From d5c2c86bd8428b2405a534c642fbbf98dd4ac7df Mon Sep 17 00:00:00 2001 From: Timothy Jacobs Date: Sat, 26 Sep 2020 18:18:53 +0000 Subject: [PATCH] REST API: Support the minProperties and maxProperties JSON Schema keywords. Props yakimun. Fixes #51023. git-svn-id: https://develop.svn.wordpress.org/trunk@49053 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-includes/rest-api.php | 13 +++++ .../tests/rest-api/rest-controller.php | 2 +- .../tests/rest-api/rest-schema-validation.php | 55 +++++++++++++++++++ .../tests/rest-api/rest-test-controller.php | 2 + 4 files changed, 71 insertions(+), 1 deletion(-) diff --git a/src/wp-includes/rest-api.php b/src/wp-includes/rest-api.php index cbad102bbe..28f2ad6b73 100644 --- a/src/wp-includes/rest-api.php +++ b/src/wp-includes/rest-api.php @@ -1551,6 +1551,7 @@ function rest_stabilize_value( $value ) { * Support the "minLength", "maxLength" and "pattern" keywords for strings. * Support the "minItems", "maxItems" and "uniqueItems" keywords for arrays. * Validate required properties. + * @since 5.7.0 Support the "minProperties" and "maxProperties" keywords for objects. * * @param mixed $value The value to validate. * @param array $args Schema array to use for validation. @@ -1662,6 +1663,16 @@ function rest_validate_value_from_schema( $value, $args, $param = '' ) { } } } + + if ( isset( $args['minProperties'] ) && count( $value ) < $args['minProperties'] ) { + /* translators: 1: Parameter, 2: Number. */ + return new WP_Error( 'rest_invalid_param', sprintf( __( '%1$s must contain at least %2$s properties.' ), $param, number_format_i18n( $args['minProperties'] ) ) ); + } + + if ( isset( $args['maxProperties'] ) && count( $value ) > $args['maxProperties'] ) { + /* translators: 1: Parameter, 2: Number. */ + return new WP_Error( 'rest_invalid_param', sprintf( __( '%1$s must contain at most %2$s properties.' ), $param, number_format_i18n( $args['maxProperties'] ) ) ); + } } if ( 'null' === $args['type'] ) { @@ -2281,6 +2292,8 @@ function rest_get_endpoint_args_for_schema( $schema, $method = WP_REST_Server::C 'items', 'properties', 'additionalProperties', + 'minProperties', + 'maxProperties', 'minimum', 'maximum', 'exclusiveMinimum', diff --git a/tests/phpunit/tests/rest-api/rest-controller.php b/tests/phpunit/tests/rest-api/rest-controller.php index c98e8045e4..74364064e6 100644 --- a/tests/phpunit/tests/rest-api/rest-controller.php +++ b/tests/phpunit/tests/rest-api/rest-controller.php @@ -291,7 +291,7 @@ class WP_Test_REST_Controller extends WP_Test_REST_TestCase { $this->assertArrayHasKey( $property, $args['somearray'] ); } - foreach ( array( 'properties', 'additionalProperties' ) as $property ) { + foreach ( array( 'properties', 'additionalProperties', 'minProperties', 'maxProperties' ) as $property ) { $this->assertArrayHasKey( $property, $args['someobject'] ); } diff --git a/tests/phpunit/tests/rest-api/rest-schema-validation.php b/tests/phpunit/tests/rest-api/rest-schema-validation.php index 7304ca7d25..5889341c7b 100644 --- a/tests/phpunit/tests/rest-api/rest-schema-validation.php +++ b/tests/phpunit/tests/rest-api/rest-schema-validation.php @@ -836,6 +836,61 @@ class WP_Test_REST_Schema_Validation extends WP_UnitTestCase { ); } + /** + * @ticket 51023 + */ + public function test_object_min_properties() { + $schema = array( + 'type' => 'object', + 'minProperties' => 1, + ); + + $this->assertTrue( + rest_validate_value_from_schema( + array( + 'propA' => 'a', + 'propB' => 'b', + ), + $schema + ) + ); + $this->assertTrue( rest_validate_value_from_schema( array( 'propA' => 'a' ), $schema ) ); + $this->assertWPError( rest_validate_value_from_schema( array(), $schema ) ); + $this->assertWPError( rest_validate_value_from_schema( '', $schema ) ); + } + + /** + * @ticket 51023 + */ + public function test_object_max_properties() { + $schema = array( + 'type' => 'object', + 'maxProperties' => 2, + ); + + $this->assertTrue( rest_validate_value_from_schema( array( 'propA' => 'a' ), $schema ) ); + $this->assertTrue( + rest_validate_value_from_schema( + array( + 'propA' => 'a', + 'propB' => 'b', + ), + $schema + ) + ); + $this->assertWPError( + rest_validate_value_from_schema( + array( + 'propA' => 'a', + 'propB' => 'b', + 'propC' => 'c', + ), + $schema + ) + ); + $this->assertWPError( rest_validate_value_from_schema( 'foobar', $schema ) ); + } + /** * @ticket 44949 */ diff --git a/tests/phpunit/tests/rest-api/rest-test-controller.php b/tests/phpunit/tests/rest-api/rest-test-controller.php index 35175f35b1..88c0ce7779 100644 --- a/tests/phpunit/tests/rest-api/rest-test-controller.php +++ b/tests/phpunit/tests/rest-api/rest-test-controller.php @@ -120,6 +120,8 @@ class WP_REST_Test_Controller extends WP_REST_Controller { 'type' => 'integer', ), ), + 'minProperties' => 1, + 'maxProperties' => 10, 'ignored_prop' => 'ignored_prop', 'context' => array( 'view' ), ),