Make WordPress Core

Changeset 47758


Ignore:
Timestamp:
05/04/2020 02:44:44 AM (6 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.