Making WordPress.org

Ticket #5303: 5303.diff

File 5303.diff, 8.9 KB (added by ryelle, 4 years ago)

Update apiVersion to number, use rest_validate_value_from_schema to validate json object

  • block-json/class-validator.php

     
    3737                        'type'                 => 'object',
    3838                        'properties'           => array(
    3939                                'apiVersion'   => array(
    40                                         'type' => 'string',
     40                                        'type' => 'integer',
    4141                                ),
    4242                                'attributes'   => array(
    4343                                        'type'                 => 'object',
     
    200200
    201201                $schema = self::schema();
    202202
    203                 $this->validate_object( $block_json, 'block.json', $schema );
     203                $result = rest_validate_value_from_schema( $block_json, $schema );
     204
     205                if ( is_wp_error( $result ) ) {
     206                        $this->messages = $result;
     207                }
     208
    204209                $this->check_conditional_properties( $block_json );
    205210
    206211                if ( $this->messages->has_errors() ) {
     
    222227                        return;
    223228                }
    224229
     230                // phpcs:ignore WordPress.NamingConventions.ValidVariableName
    225231                if ( ! isset( $block_json->script ) && ! isset( $block_json->editorScript ) ) {
    226232                        $this->messages->add(
    227233                                'error',
     
    237243        }
    238244
    239245        /**
    240          * Validate an object and its properties.
    241          *
    242          * @param object $object The value to validate as an object.
    243          * @param string $prop   The name of the property, used in error reporting.
    244          * @param array  $schema The schema for the property, used for validation.
    245          *
    246          * @return bool
    247          */
    248         protected function validate_object( $object, $prop, $schema ) {
    249                 if ( ! is_object( $object ) ) {
    250                         $this->messages->add(
    251                                 'error',
    252                                 sprintf(
    253                                         __( 'The %s property must contain an object value.', 'wporg-plugins' ),
    254                                         '<code>' . $prop . '</code>'
    255                                 )
    256                         );
    257                         $this->append_error_data( $prop, 'error' );
    258 
    259                         return false;
    260                 }
    261 
    262                 $results = array();
    263 
    264                 if ( isset( $schema['required'] ) ) {
    265                         foreach ( $schema['required'] as $required_prop ) {
    266                                 if ( ! property_exists( $object, $required_prop ) ) {
    267                                         $this->messages->add(
    268                                                 'error',
    269                                                 sprintf(
    270                                                         __( 'The %1$s property is required in the %2$s object.', 'wporg-plugins' ),
    271                                                         '<code>' . $required_prop . '</code>',
    272                                                         '<code>' . $prop . '</code>'
    273                                                 )
    274                                         );
    275                                         $this->append_error_data( "$prop:$required_prop", 'error' );
    276                                         $results[] = false;
    277                                 }
    278                         }
    279                 }
    280 
    281                 if ( isset( $schema['properties'] ) ) {
    282                         foreach ( $schema['properties'] as $subprop => $subschema ) {
    283                                 if ( ! isset( $object->$subprop ) ) {
    284                                         continue;
    285                                 }
    286 
    287                                 if ( isset( $subschema['type'] ) ) {
    288                                         $results[] = $this->route_validation_for_type(
    289                                                 $subschema['type'],
    290                                                 $object->$subprop,
    291                                                 "$prop:$subprop",
    292                                                 $subschema
    293                                         );
    294                                 }
    295                         }
    296                 }
    297 
    298                 if ( isset( $schema['additionalProperties'] ) ) {
    299                         if ( false === $schema['additionalProperties'] ) {
    300                                 foreach ( array_keys( get_object_vars( $object ) ) as $key ) {
    301                                         if ( ! isset( $schema['properties'][ $key ] ) ) {
    302                                                 $this->messages->add(
    303                                                         'warning',
    304                                                         sprintf(
    305                                                                 __( '%1$s is not a valid property in the %2$s object.', 'wporg-plugins' ),
    306                                                                 '<code>' . $key . '</code>',
    307                                                                 '<code>' . $prop . '</code>'
    308                                                         )
    309                                                 );
    310                                                 $this->append_error_data( "$prop:$key", 'warning' );
    311                                                 $results[] = false;
    312                                                 continue;
    313                                         }
    314                                 }
    315                         } elseif ( isset( $schema['additionalProperties']['type'] ) ) {
    316                                 foreach ( $object as $subprop => $subvalue ) {
    317                                         $results[] = $this->route_validation_for_type(
    318                                                 $schema['additionalProperties']['type'],
    319                                                 $subvalue,
    320                                                 "$prop:$subprop",
    321                                                 $schema['additionalProperties']
    322                                         );
    323                                 }
    324                         }
    325                 }
    326 
    327                 return ! in_array( false, $results, true );
    328         }
    329 
    330         /**
    331          * Validate an array and its items.
    332          *
    333          * @param array  $array  The value to validate as an array.
    334          * @param string $prop   The name of the property, used in error reporting.
    335          * @param array  $schema The schema for the property, used for validation.
    336          *
    337          * @return bool
    338          */
    339         protected function validate_array( $array, $prop, $schema ) {
    340                 if ( ! is_array( $array ) ) {
    341                         $this->messages->add(
    342                                 'error',
    343                                 sprintf(
    344                                         __( 'The %s property must contain an array value.', 'wporg-plugins' ),
    345                                         '<code>' . $prop . '</code>'
    346                                 )
    347                         );
    348                         $this->append_error_data( $prop, 'error' );
    349 
    350                         return false;
    351                 }
    352 
    353                 if ( isset( $schema['items']['type'] ) ) {
    354                         $results = array();
    355                         $index   = 0;
    356 
    357                         foreach ( $array as $item ) {
    358                                 $results[] = $this->route_validation_for_type(
    359                                         $schema['items']['type'],
    360                                         $item,
    361                                         $prop . "[$index]",
    362                                         $schema['items']
    363                                 );
    364                                 $index ++;
    365                         }
    366 
    367                         return ! in_array( false, $results, true );
    368                 }
    369 
    370                 return true;
    371         }
    372 
    373         /**
    374          * Validate a string.
    375          *
    376          * @param string $string The value to validate as a string.
    377          * @param string $prop   The name of the property, used in error reporting.
    378          * @param array  $schema The schema for the property, used for validation.
    379          *
    380          * @return bool
    381          */
    382         protected function validate_string( $string, $prop, $schema ) {
    383                 if ( ! is_string( $string ) ) {
    384                         $this->messages->add(
    385                                 'error',
    386                                 sprintf(
    387                                         __( 'The %s property must contain a string value.', 'wporg-plugins' ),
    388                                         '<code>' . $prop . '</code>'
    389                                 )
    390                         );
    391                         $this->append_error_data( $prop, 'error' );
    392 
    393                         return false;
    394                 }
    395 
    396                 if ( isset( $schema['enum'] ) ) {
    397                         if ( ! in_array( $string, $schema['enum'], true ) ) {
    398                                 $this->messages->add(
    399                                         'warning',
    400                                         sprintf(
    401                                                 __( '"%1$s" is not a valid value for the %2$s property.', 'wporg-plugins' ),
    402                                                 esc_html( $string ),
    403                                                 '<code>' . $prop . '</code>'
    404                                         )
    405                                 );
    406                                 $this->append_error_data( $prop, 'warning' );
    407                         }
    408                 }
    409 
    410                 if ( isset( $schema['pattern'] ) ) {
    411                         if ( ! preg_match( '#' . $schema['pattern'] . '#', $string ) ) {
    412                                 $pattern_description = $this->get_human_readable_pattern_description( $schema['pattern'] );
    413                                 if ( $pattern_description ) {
    414                                         $message = sprintf(
    415                                                 $pattern_description,
    416                                                 '<code>' . $prop . '</code>'
    417                                         );
    418                                 } else {
    419                                         $message = sprintf(
    420                                                 __( 'The value of %s does not match the required pattern.', 'wporg-plugins' ),
    421                                                 '<code>' . $prop . '</code>'
    422                                         );
    423                                 }
    424 
    425                                 $this->messages->add( 'warning', $message );
    426                                 $this->append_error_data( $prop, 'warning' );
    427                         }
    428                 }
    429 
    430                 return true;
    431         }
    432 
    433         /**
    434          * Validate a boolean.
    435          *
    436          * @param bool   $boolean The value to validate as a boolean.
    437          * @param string $prop    The name of the property, used in error reporting.
    438          *
    439          * @return bool
    440          */
    441         protected function validate_boolean( $boolean, $prop ) {
    442                 if ( ! is_bool( $boolean ) ) {
    443                         $this->messages->add(
    444                                 'error',
    445                                 sprintf(
    446                                         __( 'The %s property must contain a boolean value.', 'wporg-plugins' ),
    447                                         '<code>' . $prop . '</code>'
    448                                 )
    449                         );
    450                         $this->append_error_data( $prop, 'error' );
    451 
    452                         return false;
    453                 }
    454 
    455                 return true;
    456         }
    457 
    458         /**
    459          * Send a property value to the correct validator depending on which type(s) it can be.
    460          *
    461          * @param string|array $valid_types
    462          * @param mixed        $value
    463          * @param string       $prop
    464          * @param array        $schema
    465          *
    466          * @return bool
    467          */
    468         protected function route_validation_for_type( $valid_types, $value, $prop, $schema ) {
    469                 // There is a single valid type.
    470                 if ( is_string( $valid_types ) ) {
    471                         $method = "validate_$valid_types";
    472                         return $this->$method( $value, $prop, $schema );
    473                 }
    474 
    475                 // There are multiple valid types in an array.
    476                 foreach ( $valid_types as $type ) {
    477                         switch ( $type ) {
    478                                 case 'boolean':
    479                                         $check = 'is_bool';
    480                                         break;
    481                                 default:
    482                                         $check = "is_$type";
    483                                         break;
    484                         }
    485 
    486                         if ( $check( $value ) ) {
    487                                 $method = "validate_$type";
    488                                 return $this->$method( $value, $prop, $schema );
    489                         }
    490                 }
    491 
    492                 // Made it this far, it's none of the valid types.
    493                 $this->messages->add(
    494                         'error',
    495                         sprintf(
    496                                 __( 'The %1$s property must contain a value that is one of these types: %2$s', 'wporg-plugins' ),
    497                                 '<code>' . $prop . '</code>',
    498                                 // translators: used between list items, there is a space after the comma.
    499                                 '<code>' . implode( '</code>' . __( ', ', 'wporg-plugins' ) . '<code>', $valid_types ) . '</code>'
    500                         )
    501                 );
    502                 $this->append_error_data( $prop, 'error' );
    503 
    504                 return false;
    505         }
    506 
    507         /**
    508246         * Add more data to an error code.
    509247         *
    510248         * The `add_data` method in WP_Error replaces data with each subsequent call with the same error code.
     
    519257                $data[] = $new_data;
    520258                $this->messages->add_data( $data, $error_code );
    521259        }
    522 
    523         /**
    524          * Get a description of a regex pattern that can be understood by humans.
    525          *
    526          * @param string $pattern A regex pattern.
    527          *
    528          * @return string
    529          */
    530         protected function get_human_readable_pattern_description( $pattern ) {
    531                 $description = '';
    532 
    533                 switch ( $pattern ) {
    534                         case '\.css$':
    535                                 $description = __( 'The value of %s must end in ".css".', 'wporg-plugins' );
    536                                 break;
    537                         case '\.js$':
    538                                 $description = __( 'The value of %s must end in ".js".', 'wporg-plugins' );
    539                                 break;
    540                 }
    541 
    542                 return $description;
    543         }
    544260}