messere / php-value-mask
extract subset of array / object values
Installs: 32 199
Dependents: 1
Suggesters: 0
Security: 0
Stars: 9
Watchers: 2
Forks: 1
Open Issues: 0
Requires
- php: ^7.1 || ^8.0
- ext-json: *
Requires (Dev)
- phpmd/phpmd: ^2.6
- phpunit/phpunit: ^7.0 || ^8.0
- squizlabs/php_codesniffer: ^3.3
This package is auto-updated.
Last update: 2024-11-11 20:26:27 UTC
README
Purpose
Google in their Performance Tips for
APIs, suggest to limit required bandwidth by filtering out unused fields in response. Their APIs
support additional URL parameter fields
which asks API to include only specific fields in response.
fields
parameter follows a simple syntax, which allows to query for nested keys, multiple keys
or use wildcard to include all fields (see Syntax and Grammar sections below).
This library implements parsing of fields
parameter and filtering of arrays / objects.
See also: PSR-15 compatible middleware based on this library: Partial Response PSR-15 Middleware
Usage example
<?php require_once 'vendor/autoload.php'; use messere\phpValueMask\Parser\Parser; use messere\phpValueMask\Parser\ParserException; $parser = new Parser(); $input = [ 'id' => 1, 'resource' => 'book', 'title' => 'Good Omens', 'identifiers' => (object)[ 'isbn' => 'ISBN 83-85100-63-6', 'amazon' => '0060853980', ], 'authors' => [ [ 'firstName' => 'Terry', 'lastName' => 'Pratchett' ], [ 'firstName' => 'Neil', 'lastName' => 'Gaiman' ], ], 'year' => [ 'us' => 1990, 'uk' => 1990, 'pl' => 1992, ], 'publisher' => [ 'us' => 'Workman', 'uk' => 'Gollancz', 'pl' => 'CIA-Books-SVARO', ], ]; $filter = 'title,identifiers/isbn,authors/firstName,*(us,uk),keywords'; try { $filteredInput = $parser->parse($filter)->filter($input); print_r($filteredInput); } catch (ParserException $e) { echo 'Parser error: ' . $e->getMessage(); }
Let's analyze elements of used filter:
title
matches top level element with key title ('Good Omens')identifiers/isbn
matches top level elementidentifiers
and then includesisbn
element from matched object ('ISBN 83-85100-63-6')authors/firstName
finds an array of elements (list) under the keyauthors
and examines all elements, extractingfirstName
from each. ('Terry' and 'Neil')*(us,uk)
examines all properties and extracts fieldsus
anduk
. ('1990' and '1990' fromyear
element, 'Workman', 'Gollancz' frompublisher
)keywords
does not match anything and is silently ignored.
As a result we expect the following output:
Array
(
[title] => Good Omens
[identifiers] => Array
(
[isbn] => ISBN 83-85100-63-6
)
[authors] => Array
(
[0] => Array
(
[firstName] => Terry
)
[1] => Array
(
[firstName] => Neil
)
)
[year] => Array
(
[us] => 1990
[uk] => 1999
)
[publisher] => Array
(
[us] => Workman
[uk] => Gollancz
)
)
ready to serialize to JSON
, etc.
Note that library does preserve the structure/nesting of values, but not necessarily types of values - all objects are converted to associative arrays with object's public properties as keys.
Syntax
a
selects keya
from inputa,b,c
comma separated list of elements: selects keysa
andb
andc
a/b/c
nested elements: selects keyc
from parent elementb
which in turn has parent elementa
a(b,c)
multiple elements: selects elementsb
andc
from parent elementa
a(b,c/d)
multiple elements: from parenta
select elementb
and elementd
nested inc
a/*/c
wildcard: selects elementc
from all children of elementa
*(b,c)
wildcard: selects elementsb
andc
from any parent
Etc. See tests for more examples as well as examples of invalid filters.
Grammar
Since Google does not provide detailed grammar for their "fields" language, this package uses the following arbitrarily selected rules, that in author's opinion closely resamble intent of original authors.
In EBNF notation:
Mask = MaskElement | MaskElement , "," , Mask ;
MaskElement = ArrayOfMasks | NestedKeys ;
ArrayOfMasks = Key , "(" , Mask , ")" ;
NestedKeys = Key , [ "/" , NestedKeys ] ;
Key = Wildcard | Identifier ;
Identifier = Letter , { Letter | Digit }
Wildcard = "*" ;
Letter = "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" | "J" | "K" | "L" | "M" |
"N" | "O" | "P" | "Q" | "R" | "S" | "T" | "U" | "V" | "W" | "X" | "Y" | "Z" |
"a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" | "j" | "k" | "l" | "m" |
"n" | "o" | "p" | "q" | "r" | "s" | "t" | "u" | "v" | "w" | "x" | "y" | "z" |
"_";
Digit = "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "0" ;
Acknowledgements
Library is inspired by:
- Google's API performance tips.
- Similar JavaScript library: nemtsov/json-mask.