Make WordPress Core

Changeset 47758


Ignore:
Timestamp:
05/04/2020 02:44:44 AM (5 years ago)
Author:
TimothyBlynJacobs
Message:

REST API: Support more JSON Schemas when filtering a response by context.

The array type, multi-types, and the additional properties keyword are now supported. Additionally, the filter recurses to an infinite depth.

Fixes #48819.

Location:
trunk
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/rest-api.php

    r47753 r47758  
    16591659    return $rels;
    16601660}
     1661
     1662/**
     1663 * Filters the response to remove any fields not available in the given context.
     1664 *
     1665 * @since 5.5.0
     1666 *
     1667 * @param array|object $data    The response data to modify.
     1668 * @param array        $schema  The schema for the endpoint used to filter the response.
     1669 * @param string       $context The requested context.
     1670 * @return array|object The filtered response data.
     1671 */
     1672function rest_filter_response_by_context( $data, $schema, $context ) {
     1673    if ( ! is_array( $data ) && ! is_object( $data ) ) {
     1674        return $data;
     1675    }
     1676
     1677    if ( isset( $schema['type'] ) ) {
     1678        $type = $schema['type'];
     1679    } elseif ( isset( $schema['properties'] ) ) {
     1680        $type = 'object'; // Back compat if a developer accidentally omitted the type.
     1681    } else {
     1682        return $data;
     1683    }
     1684
     1685    foreach ( $data as $key => $value ) {
     1686        $check = array();
     1687
     1688        if ( 'array' === $type || ( is_array( $type ) && in_array( 'array', $type, true ) ) ) {
     1689            $check = isset( $schema['items'] ) ? $schema['items'] : array();
     1690        } elseif ( 'object' === $type || ( is_array( $type ) && in_array( 'object', $type, true ) ) ) {
     1691            if ( isset( $schema['properties'][ $key ] ) ) {
     1692                $check = $schema['properties'][ $key ];
     1693            } elseif ( isset( $schema['additionalProperties'] ) && is_array( $schema['additionalProperties'] ) ) {
     1694                $check = $schema['additionalProperties'];
     1695            }
     1696        }
     1697
     1698        if ( ! isset( $check['context'] ) ) {
     1699            continue;
     1700        }
     1701
     1702        if ( ! in_array( $context, $check['context'], true ) ) {
     1703            if ( is_object( $data ) ) {
     1704                unset( $data->$key );
     1705            } else {
     1706                unset( $data[ $key ] );
     1707            }
     1708        } elseif ( is_array( $value ) || is_object( $value ) ) {
     1709            $new_value = rest_filter_response_by_context( $value, $check, $context );
     1710
     1711            if ( is_object( $data ) ) {
     1712                $data->$key = $new_value;
     1713            } else {
     1714                $data[ $key ] = $new_value;
     1715            }
     1716        }
     1717    }
     1718
     1719    return $data;
     1720}
  • trunk/src/wp-includes/rest-api/endpoints/class-wp-rest-controller.php

    r47511 r47758  
    289289     * @since 4.7.0
    290290     *
    291      * @param array  $data    Response data to fiter.
     291     * @param array  $data    Response data to filter.
    292292     * @param string $context Context defined in the schema.
    293293     * @return array Filtered response.
     
    297297        $schema = $this->get_item_schema();
    298298
    299         foreach ( $data as $key => $value ) {
    300             if ( empty( $schema['properties'][ $key ] ) || empty( $schema['properties'][ $key ]['context'] ) ) {
    301                 continue;
    302             }
    303 
    304             if ( ! in_array( $context, $schema['properties'][ $key ]['context'], true ) ) {
    305                 unset( $data[ $key ] );
    306                 continue;
    307             }
    308 
    309             if ( 'object' === $schema['properties'][ $key ]['type'] && ! empty( $schema['properties'][ $key ]['properties'] ) ) {
    310                 foreach ( $schema['properties'][ $key ]['properties'] as $attribute => $details ) {
    311                     if ( empty( $details['context'] ) ) {
    312                         continue;
    313                     }
    314 
    315                     if ( ! in_array( $context, $details['context'], true ) ) {
    316                         if ( isset( $data[ $key ][ $attribute ] ) ) {
    317                             unset( $data[ $key ][ $attribute ] );
    318                         }
    319                     }
    320                 }
    321             }
    322         }
    323 
    324         return $data;
     299        return rest_filter_response_by_context( $data, $schema, $context );
    325300    }
    326301
  • trunk/tests/phpunit/tests/rest-api.php

    r47511 r47758  
    976976        );
    977977    }
     978
     979    /**
     980     * @ticket 48819
     981     *
     982     * @dataProvider _dp_rest_filter_response_by_context
     983     */
     984    public function test_rest_filter_response_by_context( $schema, $data, $expected ) {
     985        $this->assertEquals( $expected, rest_filter_response_by_context( $data, $schema, 'view' ) );
     986    }
     987
     988    public function _dp_rest_filter_response_by_context() {
     989        return array(
     990            'default'                => array(
     991                array(
     992                    '$schema'    => 'http://json-schema.org/draft-04/schema#',
     993                    'type'       => 'object',
     994                    'properties' => array(
     995                        'first'  => array(
     996                            'type'    => 'string',
     997                            'context' => array( 'view', 'edit' ),
     998                        ),
     999                        'second' => array(
     1000                            'type'    => 'string',
     1001                            'context' => array( 'edit' ),
     1002                        ),
     1003                    ),
     1004                ),
     1005                array(
     1006                    'first'  => 'a',
     1007                    'second' => 'b',
     1008                ),
     1009                array( 'first' => 'a' ),
     1010            ),
     1011            'keeps missing context'  => array(
     1012                array(
     1013                    '$schema'    => 'http://json-schema.org/draft-04/schema#',
     1014                    'type'       => 'object',
     1015                    'properties' => array(
     1016                        'first'  => array(
     1017                            'type'    => 'string',
     1018                            'context' => array( 'view', 'edit' ),
     1019                        ),
     1020                        'second' => array(
     1021                            'type' => 'string',
     1022                        ),
     1023                    ),
     1024                ),
     1025                array(
     1026                    'first'  => 'a',
     1027                    'second' => 'b',
     1028                ),
     1029                array(
     1030                    'first'  => 'a',
     1031                    'second' => 'b',
     1032                ),
     1033            ),
     1034            'removes empty context'  => array(
     1035                array(
     1036                    '$schema'    => 'http://json-schema.org/draft-04/schema#',
     1037                    'type'       => 'object',
     1038                    'properties' => array(
     1039                        'first'  => array(
     1040                            'type'    => 'string',
     1041                            'context' => array( 'view', 'edit' ),
     1042                        ),
     1043                        'second' => array(
     1044                            'type'    => 'string',
     1045                            'context' => array(),
     1046                        ),
     1047                    ),
     1048                ),
     1049                array(
     1050                    'first'  => 'a',
     1051                    'second' => 'b',
     1052                ),
     1053                array( 'first' => 'a' ),
     1054            ),
     1055            'nested properties'      => array(
     1056                array(
     1057                    '$schema'    => 'http://json-schema.org/draft-04/schema#',
     1058                    'type'       => 'object',
     1059                    'properties' => array(
     1060                        'parent' => array(
     1061                            'type'       => 'object',
     1062                            'context'    => array( 'view', 'edit' ),
     1063                            'properties' => array(
     1064                                'child'  => array(
     1065                                    'type'    => 'string',
     1066                                    'context' => array( 'view', 'edit' ),
     1067                                ),
     1068                                'hidden' => array(
     1069                                    'type'    => 'string',
     1070                                    'context' => array( 'edit' ),
     1071                                ),
     1072                            ),
     1073                        ),
     1074                    ),
     1075                ),
     1076                array(
     1077                    'parent' => array(
     1078                        'child'  => 'hi',
     1079                        'hidden' => 'there',
     1080                    ),
     1081                ),
     1082                array( 'parent' => array( 'child' => 'hi' ) ),
     1083            ),
     1084            'grand child properties' => array(
     1085                array(
     1086                    '$schema'    => 'http://json-schema.org/draft-04/schema#',
     1087                    'type'       => 'object',
     1088                    'properties' => array(
     1089                        'parent' => array(
     1090                            'type'       => 'object',
     1091                            'context'    => array( 'view', 'edit' ),
     1092                            'properties' => array(
     1093                                'child' => array(
     1094                                    'type'       => 'object',
     1095                                    'context'    => array( 'view', 'edit' ),
     1096                                    'properties' => array(
     1097                                        'grand'  => array(
     1098                                            'type'    => 'string',
     1099                                            'context' => array( 'view', 'edit' ),
     1100                                        ),
     1101                                        'hidden' => array(
     1102                                            'type'    => 'string',
     1103                                            'context' => array( 'edit' ),
     1104                                        ),
     1105                                    ),
     1106                                ),
     1107                            ),
     1108                        ),
     1109                    ),
     1110                ),
     1111                array(
     1112                    'parent' => array(
     1113                        'child' => array(
     1114                            'grand' => 'hi',
     1115                        ),
     1116                    ),
     1117                ),
     1118                array( 'parent' => array( 'child' => array( 'grand' => 'hi' ) ) ),
     1119            ),
     1120            'array'                  => array(
     1121                array(
     1122                    '$schema'    => 'http://json-schema.org/draft-04/schema#',
     1123                    'type'       => 'object',
     1124                    'properties' => array(
     1125                        'arr' => array(
     1126                            'type'    => 'array',
     1127                            'context' => array( 'view', 'edit' ),
     1128                            'items'   => array(
     1129                                'type'       => 'object',
     1130                                'context'    => array( 'view', 'edit' ),
     1131                                'properties' => array(
     1132                                    'visible' => array(
     1133                                        'type'    => 'string',
     1134                                        'context' => array( 'view', 'edit' ),
     1135                                    ),
     1136                                    'hidden'  => array(
     1137                                        'type'    => 'string',
     1138                                        'context' => array( 'edit' ),
     1139                                    ),
     1140                                ),
     1141                            ),
     1142                        ),
     1143                    ),
     1144                ),
     1145                array(
     1146                    'arr' => array(
     1147                        array(
     1148                            'visible' => 'hi',
     1149                            'hidden'  => 'there',
     1150                        ),
     1151                    ),
     1152                ),
     1153                array( 'arr' => array( array( 'visible' => 'hi' ) ) ),
     1154            ),
     1155            'additional properties'  => array(
     1156                array(
     1157                    '$schema'    => 'http://json-schema.org/draft-04/schema#',
     1158                    'type'       => 'object',
     1159                    'properties' => array(
     1160                        'additional' => array(
     1161                            'type'                 => 'object',
     1162                            'context'              => array( 'view', 'edit' ),
     1163                            'properties'           => array(
     1164                                'a' => array(
     1165                                    'type'    => 'string',
     1166                                    'context' => array( 'view', 'edit' ),
     1167                                ),
     1168                                'b' => array(
     1169                                    'type'    => 'string',
     1170                                    'context' => array( 'edit' ),
     1171                                ),
     1172                            ),
     1173                            'additionalProperties' => array(
     1174                                'type'    => 'string',
     1175                                'context' => array( 'edit' ),
     1176                            ),
     1177                        ),
     1178                    ),
     1179                ),
     1180                array(
     1181                    'additional' => array(
     1182                        'a' => '1',
     1183                        'b' => '2',
     1184                        'c' => '3',
     1185                    ),
     1186                ),
     1187                array( 'additional' => array( 'a' => '1' ) ),
     1188            ),
     1189            'multiple types object'  => array(
     1190                array(
     1191                    '$schema'    => 'http://json-schema.org/draft-04/schema#',
     1192                    'type'       => 'object',
     1193                    'properties' => array(
     1194                        'multi' => array(
     1195                            'type'       => array( 'object', 'string' ),
     1196                            'context'    => array( 'view', 'edit' ),
     1197                            'properties' => array(
     1198                                'a' => array(
     1199                                    'type'    => 'string',
     1200                                    'context' => array( 'view', 'edit' ),
     1201                                ),
     1202                                'b' => array(
     1203                                    'type'    => 'string',
     1204                                    'context' => array( 'edit' ),
     1205                                ),
     1206                            ),
     1207                        ),
     1208                    ),
     1209                ),
     1210                array(
     1211                    'multi' => array(
     1212                        'a' => '1',
     1213                        'b' => '2',
     1214                    ),
     1215                ),
     1216                array( 'multi' => array( 'a' => '1' ) ),
     1217            ),
     1218            'multiple types array'   => array(
     1219                array(
     1220                    '$schema'    => 'http://json-schema.org/draft-04/schema#',
     1221                    'type'       => 'object',
     1222                    'properties' => array(
     1223                        'multi' => array(
     1224                            'type'    => array( 'array', 'string' ),
     1225                            'context' => array( 'view', 'edit' ),
     1226                            'items'   => array(
     1227                                'type'       => 'object',
     1228                                'context'    => array( 'view', 'edit' ),
     1229                                'properties' => array(
     1230                                    'visible' => array(
     1231                                        'type'    => 'string',
     1232                                        'context' => array( 'view', 'edit' ),
     1233                                    ),
     1234                                    'hidden'  => array(
     1235                                        'type'    => 'string',
     1236                                        'context' => array( 'edit' ),
     1237                                    ),
     1238                                ),
     1239                            ),
     1240                        ),
     1241                    ),
     1242                ),
     1243                array(
     1244                    'multi' => array(
     1245                        array(
     1246                            'visible' => '1',
     1247                            'hidden'  => '2',
     1248                        ),
     1249                    ),
     1250                ),
     1251                array( 'multi' => array( array( 'visible' => '1' ) ) ),
     1252            ),
     1253            'grand child properties does not traverses missing context' => array(
     1254                array(
     1255                    '$schema'    => 'http://json-schema.org/draft-04/schema#',
     1256                    'type'       => 'object',
     1257                    'properties' => array(
     1258                        'parent' => array(
     1259                            'type'       => 'object',
     1260                            'context'    => array( 'view', 'edit' ),
     1261                            'properties' => array(
     1262                                'child' => array(
     1263                                    'type'       => 'object',
     1264                                    'properties' => array(
     1265                                        'grand'  => array(
     1266                                            'type'    => 'string',
     1267                                            'context' => array( 'view', 'edit' ),
     1268                                        ),
     1269                                        'hidden' => array(
     1270                                            'type'    => 'string',
     1271                                            'context' => array( 'edit' ),
     1272                                        ),
     1273                                    ),
     1274                                ),
     1275                            ),
     1276                        ),
     1277                    ),
     1278                ),
     1279                array(
     1280                    'parent' => array(
     1281                        'child' => array(
     1282                            'grand'  => 'hi',
     1283                            'hidden' => 'there',
     1284                        ),
     1285                    ),
     1286                ),
     1287                array(
     1288                    'parent' => array(
     1289                        'child' => array(
     1290                            'grand'  => 'hi',
     1291                            'hidden' => 'there',
     1292                        ),
     1293                    ),
     1294                ),
     1295            ),
     1296        );
     1297    }
    9781298}
Note: See TracChangeset for help on using the changeset viewer.