clean install

This commit is contained in:
2024-12-10 15:08:16 +01:00
commit e14eb2d8fd
31193 changed files with 3555714 additions and 0 deletions

3
vendor/galbar/jsonpath/.coveralls.yml vendored Normal file
View File

@@ -0,0 +1,3 @@
service_name: travis-ci
coverage_clover: ./clover.xml
json_path: ./coveralls-upload.json

4
vendor/galbar/jsonpath/.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
vendor
docs/*
cache
composer.lock

3
vendor/galbar/jsonpath/.gitpod.yml vendored Normal file
View File

@@ -0,0 +1,3 @@
tasks:
- init: 'composer update .'
command: php app/test.php "$"

19
vendor/galbar/jsonpath/.travis.yml vendored Normal file
View File

@@ -0,0 +1,19 @@
language: php
php:
- '5.6'
- '7.0'
- '7.1'
- '7.2'
- '7.3'
before_script:
- if [[ $TRAVIS_PHP_VERSION = '5.4' ]]; then PHPUNIT_FLAGS="--coverage-clover ./clover.xml"; else PHPUNIT_FLAGS=""; fi
- composer self-update
- composer install --prefer-source
script:
- ./vendor/bin/phpunit -v $PHPUNIT_FLAGS
after_script:
- php vendor/bin/coveralls -v

80
vendor/galbar/jsonpath/CHANGELOG.md vendored Normal file
View File

@@ -0,0 +1,80 @@
Changelog
=========
1.3
---
* Expose internal language parsing and querying functions as part of the public API
1.2
---
* Add `!` as synonym of `not`
* Add `&&` as synonym of `and`
* Add `||` as synonym of `or`
1.1
---
* Drop support for PHP 5.4 and 5.5
* Add support for PHP 7.2 and 7.3
* Add utf-8 support (#33)
* Ability to use .length outside of [] (#28)
1.0
---
* Drop support for PHP 5.3
* Adding json\_encode options bitmask (#7)
0.8
---
* Allows minus character within property name (by jaimelopez)
0.7.3
-----
* Bug fix in `.length` regex.
* Minor code cleanup.
0.7.2
-----
* Documentation now properly defines what a variable name is.
* Dependencies are now properly defined for older PHP versions.
0.7.1
-----
* Bug fix when accessing an array with a negative index. It now behaves as expected.
0.7
---
* set now creates non-existent intermediate objects.
(p.e. if quering '$.a' results in false, when setting
'$.a.b' to a value '$.a' will be created as a result of this).
0.6
---
* Added custom Exception classes:
* `InvalidJsonException` is thrown when an invalid values is given to the
JsonObject constructor.
* `InvalidJsonPathException` is thrown when an invalid JSONPath is given.
0.5
---
* Added getJsonObjects to get child JsonObjects that reference the original JsonObject contents.
This is also affected by _smartGet_.
0.4
---
* Added support for json objects with fields with names that are not valid javascript variable
names.
* Fixed error in smart get when accessing a list of names or list of indices and only one existed in the object.
0.3
---
* Added smart get
0.2
---
* Added errors when invalid json type is passed to construct
* Efficiency improvements
* All tokens are constants
0.1
---
* Basic JsonPath functionality

30
vendor/galbar/jsonpath/CONTRIBUTING.md vendored Normal file
View File

@@ -0,0 +1,30 @@
# Contributing to JsonPath
I'm glad you want to make a contribution!
Fork this repository and send in a pull request when you're finished with your
changes. Link any relevant issues in too.
Take note of the build status of your pull request, only builds that pass will
be accepted. Please also keep to our conventions and style so we can keep this
repository as clean as possible.
## License
By contributing your code, you agree to license your contribution under the
terms of the APLv2: (see `LICENSE` file)
All files are released with the Apache 2.0 license.
If you are adding a new file it should have a header like this:
```
/**
* Copyright [current year] Alessio Linares
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
```

176
vendor/galbar/jsonpath/LICENSE vendored Normal file
View File

@@ -0,0 +1,176 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS

16
vendor/galbar/jsonpath/NOTICE vendored Normal file
View File

@@ -0,0 +1,16 @@
JsonPath-PHP
Copyright 2015-2018 Skyscanner Limited
Copyright 2018 Alessio Linares
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

236
vendor/galbar/jsonpath/README.md vendored Normal file
View File

@@ -0,0 +1,236 @@
JsonPath
========
[![Build Status](https://travis-ci.org/Galbar/JsonPath-PHP.svg)](https://travis-ci.org/Galbar/JsonPath-PHP)
[![Coverage Status](https://coveralls.io/repos/Galbar/JsonPath-PHP/badge.svg?branch=master&service=github)](https://coveralls.io/github/Galbar/JsonPath-PHP?branch=master)
[![Latest Stable Version](https://poser.pugx.org/galbar/jsonpath/v/stable)](https://packagist.org/packages/galbar/jsonpath)
[![License](https://poser.pugx.org/galbar/jsonpath/license)](https://packagist.org/packages/galbar/jsonpath)
This is a [JSONPath](http://goessner.net/articles/JsonPath/) implementation for PHP.
This implementation features all elements in the specification except the `()` operator (in the spcecification there is the `$..a[(@.length-1)]`, but this can be achieved with `$..a[-1]` and the latter is simpler).
On top of this it implements some extended features:
* Regex match comparisons (p.e. `$.store.book[?(@.author =~ /.*Tolkien/)]`)
* For the child operator `[]` there is no need to surround child names with quotes (p.e. `$.[store][book, bicycle]`) except if the name of the field is a non-valid javascript variable name.
* `.length` can be used to get the length of a string, get the length of an array and to check if a node has children.
Features
========
This implementation has the following features:
* Object oriented implementation.
* __Get__, __set__ and __add__ operations.
* Magic methods implemented:
* `__get`: `$obj->{'$...'}`.
* `__set`: `$obj->{'$...'} = $val`.
* `__toString`: `echo $obj` prints the json representation of the JsonObject.
* Not using `eval()`.
Installation
=====
To install JsonPath you will need to be using Composer in your project. To install it please see the [docs](https://getcomposer.org/download/).
```bash
composer require galbar/jsonpath
```
Usage
=====
In every file you use it add:
```php
use JsonPath\JsonObject;
```
Now you can create an instance of JsonObject and use it:
```php
// $json can be a string containing json, a PHP array, a PHP object or null.
// If $json is null (or not present) the JsonObject will be empty.
$jsonObject = new JsonObject();
// or
$jsonObject = new JsonObject($json);
// get
$obj->get($jsonPath);
$obj->{'$.json.path'};
// set
$obj->set($jsonPath, $value);
$obj->{'$.json.path'} = $value;
// get the json representation
$obj->getJson();
$str = (string)$obj;
echo $obj;
// get the PHP array representation
$obj->getValue();
// add values
$obj->add($jsonPath, $value[, $field]);
// remove values
$obj->remove($jsonPath, $field);
```
SmartGet
--------
When creating a new instance of JsonObject, you can pass a second parameter to the constructor.
This sets the behaviour of the instance to use SmartGet.
What SmartGet does is to determine if the given JsonPath branches at some point, if it does it behaves as usual;
otherwise, it will directly return the value pointed by the given path (not the array containing it).
GetJsonObjects
--------------
Sometimes you need to access multiple values of a subobject that has a long prefix (p.e. `$.a.very.long.prefix.for.[*].object`), in this case you would first get said object
and make a JsonObject of it and then access its properties.
Now if you want to edit the object (set or add values) and want these changes to affect the original object, the way of doing this is by using
`JsonObject::getJsonObjects($jsonpath)`. This method works the same way get does, but it will return the results as JsonObject instances containing a reference to the value in the source JsonObject.
JsonPath Language
=================
This library implements the following specification:
```
var_name = [\w\_\$^\d][\w\-\$]*
number = ([0-9]+(\.[0-9]*) | ([0-9]*\.[0-9]+))
string = ('\''.*?'\'' | '"'.*?'"')
boolean = ('true' | 'false')
regpattern = '/'.*?'/'
null = 'null'
index = -?[0-9]+
jsonpath = '$' operator*
childpath = '@' operator*
operator = (childname | childfilter | recursive) operator*
childname = '.' (var_name | '*')
recursive = '..' (var_name | '*')
childfilter = '[' ('*' | namelist | indexlist | arrayslice | filterexpr) ']'
namelist = var_name (',' (var_name | '\'' .*? '\'' | '"' .*? '"'))*
indexlist = index (',' index)*
arrayslice = index? ':' index? ':' index?
filterexpr = '?(' ors ')'
ors = ands (' ' ( 'or' | '\|\|' ) ' ' ands)*
ands = expr (' ' ( 'and' | '&&' ) ' ' expr)*
expr = ( 'not ' | '! ' )? (value | comp)
comp = value ('==' | '!=' | '<' | '>' | '<=' | '>=' | '=~') value
value = (jsonpath | childpath | number | string | boolean | regpattern | null | length)
length = (jsonpath | childpath) '.length'
```
### Limitations on the specification:
* The jsonpath inside _value_ cannot contain `or`, `and` or any comparator.
* Jsonpaths in _value_ return the first element of the set or false if no result.
* Boolean operations can't be grouped with parethesis.
* `and`s are run before `or`s. That means that `a and 1 = b or c != d` is the same
as `(a and 1) or (c != d)`
__The `.length` operator__ can be used to:
* Get the number of childs a node in the JsonObject has: `$..*[?(@.length > 3)]`
* Filter for nodes that have childs: `$..*[?(@.length)]`
* Or filter for nodes that don't have childs (leaves): `$..*[?(not @.length)]`
* Check the length of a string: `$.path.to[?(@.a.string.length > 10)]`
* Get the length of a string: `$.path.to.field.length`
* Get the length of an array: `$.path.to.array.length`
* Get the length of each array inside an array of arrays: `$.path.to.array[*].array[*].length`
* Get the length of each string inside an array of strings: `$.path.to.array[*].array[*].key.length`
__The comparators__:
`==`, `!=`, `<`, `>`, `<=`, `>=` do what expected (compare by type and value).
`=~` is a regex comparator, matches the left operand with the pattern in the right operand. The value on the left must be a _string_ and on
the right _regpattern_. Other wise returns `false`.
JsonPath Example
================
Consider the following json:
```json
{ "store": {
"book": [
{ "category": "reference",
"author": "Nigel Rees",
"title": "Sayings of the Century",
"price": 8.95,
"available": true
},
{ "category": "fiction",
"author": "Evelyn Waugh",
"title": "Sword of Honour",
"price": 12.99,
"available": false
},
{ "category": "fiction",
"author": "Herman Melville",
"title": "Moby Dick",
"isbn": "0-553-21311-3",
"price": 8.99,
"available": true
},
{ "category": "fiction",
"author": "J. R. R. Tolkien",
"title": "The Lord of the Rings",
"isbn": "0-395-19395-8",
"price": 22.99,
"available": false
}
],
"bicycle": {
"color": "red",
"price": 19.95,
"available": true
}
},
"authors": [
"Nigel Rees",
"Evelyn Waugh",
"Herman Melville",
"J. R. R. Tolkien"
]
}
```
JsonPath | Result
---------|--------
`$.store.bicycle.price` | The price of the bicycle.
`$.store.book[*]` | All books.
`$.store.book[1,3]` | The second and fourth book.
`$.store.book[1:3]` | From the second book to the third.
`$.store.book[:3]` | From the first book to the third.
`$.store.book[x:y:z]` | Books from x to y with a step of z.
`$..book[?(@.category == 'fiction')]` | All books with category == 'fiction'.
`$..*[?(@.available == true)].price` | All prices of available products.
`$..book[?(@.price < 10)].title` | The title of all books with price lower than 10.
`$..book[?(@.author==$.authors[3])]` | All books by "J. R. R. Tolkien"
`$[store]` | The store.
`$['store']` | The store.
`$..book[*][title, 'category', "author"]` | title, category and author of all books.
Test
====
To run tests, from the project root folder:
`php app/test.php <jsonpath> [<file to json file>]`
If no json file is given it defaults to the json object described previously in this file.
For example:
`php app/test.php "$..*[?(@.category == 'fiction' and @.price < 10 or @.color == \"red\")].price"`
Result should be:
`[19.95,8.99]`
Ready to code
=============
you can open the project in your browser and can start coding
[![Gitpod ready-to-code](https://img.shields.io/badge/Gitpod-ready--to--code-blue?logo=gitpod)](https://gitpod.io/#https://github.com/Galbar/JsonPath-PHP)
Docs
====
To generate the docs, from the project root folder:
`php vendor/bin/sami.php update app/docgen.php`

33
vendor/galbar/jsonpath/app/docgen.php vendored Normal file
View File

@@ -0,0 +1,33 @@
<?php
/**
* Copyright 2018 Alessio Linares
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
use Sami\Sami;
use Symfony\Component\Finder\Finder;
$iterator = Finder::create()
->files()
->name('*.php')
->exclude('Resources')
->exclude('Tests')
->in(__DIR__ . '/../src/')
;
return new Sami($iterator, array(
'theme' => 'default',
'title' => 'JsonPath',
'build_dir' => __DIR__ . './../docs',
));

100
vendor/galbar/jsonpath/app/test.php vendored Normal file
View File

@@ -0,0 +1,100 @@
<?php
/**
* Copyright 2018 Alessio Linares
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
include __DIR__ . '/../vendor/autoload.php';
use JsonPath\JsonObject;
use JsonPath\InvalidJsonException;
use JsonPath\InvalidJsonPathException;
$json = '
{ "store": {
"book": [
{ "category": "reference",
"author": "Nigel Rees",
"title": "Sayings of the Century",
"price": 8.95,
"available": true
},
{ "category": "fiction",
"author": "Evelyn Waugh",
"title": "Sword of Honour",
"price": 12.99,
"available": false
},
{ "category": "fiction",
"author": "Herman Melville",
"title": "Moby Dick",
"isbn": "0-553-21311-3",
"price": 8.99,
"available": true
},
{ "category": "fiction",
"author": "J. R. R. Tolkien",
"title": "The Lord of the Rings",
"isbn": "0-395-19395-8",
"price": 22.99,
"available": false
}
],
"bicycle": {
"color": "red",
"price": 19.95,
"available": true
}
},
"authors": [
"Nigel Rees",
"Evelyn Waugh",
"Herman Melville",
"J. R. R. Tolkien"
]
}
';
switch (count($argv)) {
case 1:
print "Usage: $argv[0] <jsonpath> [<file to json>]\n";
print "If no json file is given it defaults to the json specified in http://goessner.net/articles/JsonPath/index.html#e3\n";
die();
break;
case 3:
$json = file_get_contents($argv[2]);
default:
$jsonPath = $argv[1];
}
try {
$jsonObject = new JsonObject($json);
} catch (InvalidJsonException $e) {
print "Invalid JSON error: '" . $e->getMessage() . "'\r\n";
die();
}
try {
$r = $jsonObject->get($jsonPath);
} catch (InvalidJsonPathException $e) {
print "Invalid JSONPath error: '" . $e->getMessage() . "'\r\n";
die();
}
if ($r === false) {
print "false";
} else {
print json_encode($r);
}
print "\r\n";

33
vendor/galbar/jsonpath/composer.json vendored Normal file
View File

@@ -0,0 +1,33 @@
{
"name": "galbar/jsonpath",
"description": "JSONPath implementation for querying and updating JSON objects",
"type": "library",
"keywords": ["jsonpath", "json", "path"],
"license": "Apache-2.0",
"authors": [
{
"name": "Alessio Linares",
"email": "alessio@alessio.cc",
"role": "Software Engineer"
}
],
"require": {
"php": ">=5.4"
},
"require-dev": {
"phpunit/phpunit": "~4.0",
"sami/sami": ">=3.3.0",
"satooshi/php-coveralls": ">=1.0.1"
},
"autoload": {
"psr-4": {
"JsonPath\\": "src/Galbar/JsonPath",
"Utilities\\": "src/Galbar/Utilities"
}
},
"autoload-dev": {
"psr-4": {
"Tests\\": "tests/Galbar/"
}
}
}

39
vendor/galbar/jsonpath/phpunit.xml.dist vendored Normal file
View File

@@ -0,0 +1,39 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/4.2/phpunit.xsd"
backupGlobals="true"
backupStaticAttributes="true"
verbose="true"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
stopOnError="false"
stopOnFailure="false"
stopOnIncomplete="false"
stopOnSkipped="false"
syntaxCheck="true"
bootstrap="tests/bootstrap.php"
>
<testsuites>
<testsuite name="Galbar\JsonPath" phpVersion="5.4.0" phpVersionOperator=">=">
<directory suffix=".php">./tests/</directory>
</testsuite>
</testsuites>
<filter>
<blacklist>
<directory suffix=".php">./vendor/</directory>
</blacklist>
<whitelist processUncoveredFilesFromWhitelist="true">
<directory suffix=".php">./src/</directory>
</whitelist>
</filter>
</phpunit>

View File

@@ -0,0 +1,47 @@
<?php
/**
* Copyright 2021 Alessio Linares
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace JsonPath\Expression;
use Utilities\ArraySlice;
use JsonPath\Language;
class ArrayInterval
{
public static function evaluate(&$partial, $numbers) {
$begin = null;
$step = null;
$end = null;
// $numbers has the different numbers of the interval
// depending on if there are 2 (begin:end) or 3 (begin:end:step)
// numbers $begin, $step, $end are reassigned
if (count($numbers) === 3) {
$step = ($numbers[2] !== '' ? intval($numbers[2]) : $step);
}
$end = ($numbers[1] !== '' ? intval($numbers[1]) : $end);
$begin = ($numbers[0] !== '' ? intval($numbers[0]) : $begin);
$slice = ArraySlice::slice($partial, $begin, $end, $step, true);
$result = array();
foreach ($slice as $i => $x) {
if ($x !== null) {
$result[] = &$slice[$i];
}
}
return $result;
}
}

View File

@@ -0,0 +1,65 @@
<?php
/**
* Copyright 2021 Alessio Linares
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace JsonPath\Expression;
use JsonPath\Language;
class BooleanExpression
{
public static function evaluate(&$root, &$partial, $expression)
{
$ands = preg_split(Language\Regex::BINOP_OR, $expression);
foreach ($ands as $subexpr) {
if (BooleanExpression::booleanExpressionAnds($root, $partial, $subexpr)) {
return true;
}
}
return false;
}
private static function booleanExpressionAnds(&$root, &$partial, $expression)
{
$values = preg_split(Language\Regex::BINOP_AND, $expression);
$match = array();
foreach ($values as $subexpr) {
$not = false;
if (preg_match(Language\Regex::OP_NOT, $subexpr, $match)) {
$subexpr = $match[2];
$not = true;
}
$result = false;
if (preg_match(Language\Regex::BINOP_COMP, $subexpr, $match)) {
$result = Comparison::evaluate($root, $partial, $match[1], $match[2], $match[3]);
}
else {
$result = Value::evaluate($root, $partial, $subexpr);
}
if ($not) {
if ($result !== false) {
return false;
}
} else {
if ($result === false) {
return false;
}
}
}
return true;
}
}

View File

@@ -0,0 +1,40 @@
<?php
/**
* Copyright 2021 Alessio Linares
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace JsonPath\Expression;
use JsonPath\Language;
class ChildNameList
{
public static function evaluate(&$partial, $names, $createInexistent = false) {
$names = array_filter(
$names,
function($x) use ($createInexistent, $partial) {
return $createInexistent || array_key_exists($x, $partial);
}
);
$result = array();
foreach ($names as $name) {
if (!array_key_exists($name, $partial)) {
$partial[$name] = array();
}
$result[] = &$partial[$name];
}
return $result;
}
}

View File

@@ -0,0 +1,47 @@
<?php
/**
* Copyright 2021 Alessio Linares
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace JsonPath\Expression;
use JsonPath\Language;
class Comparison
{
public static function evaluate(&$root, &$partial, $leftExpr, $comparator, $rightExpr)
{
$left = Value::evaluate($root, $partial, trim($leftExpr));
$right = Value::evaluate($root, $partial, trim($rightExpr));
if ($comparator === Language\Token::COMP_EQ) {
return $left === $right;
} else if ($comparator === Language\Token::COMP_NEQ) {
return $left !== $right;
} else if ($comparator === Language\Token::COMP_LT) {
return $left < $right;
} else if ($comparator === Language\Token::COMP_GT) {
return $left > $right;
} else if ($comparator === Language\Token::COMP_LTE) {
return $left <= $right;
} else if ($comparator === Language\Token::COMP_GTE) {
return $left >= $right;
} else { // $comparator === Language\Token::COMP_RE_MATCH
if (is_string($right) && is_string($left)) {
return (bool) preg_match($right, $left);
}
return false;
}
}
}

View File

@@ -0,0 +1,54 @@
<?php
/**
* Copyright 2021 Alessio Linares
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace JsonPath\Expression;
use JsonPath\Language;
class IndexList
{
public static function evaluate(&$partial, $indexes, $createInexistent = false) {
$indexes = array_map(
function($i) use ($partial) {
if ($i < 0) {
$n = count($partial);
$i = $i % $n;
if ($i < 0) {
$i += $n;
}
}
return $i;
},
$indexes
);
$indexes = array_filter(
$indexes,
function($x) use ($createInexistent, $partial) {
return $createInexistent || array_key_exists($x, $partial);
}
);
$result = array();
foreach ($indexes as $i) {
if (!array_key_exists($i, $partial)) {
$partial[$i] = array();
}
$result[] = &$partial[$i];
}
return $result;
}
}

View File

@@ -0,0 +1,71 @@
<?php
/**
* Copyright 2021 Alessio Linares
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace JsonPath\Expression;
use JsonPath\Language;
use JsonPath\Operation;
class Value
{
public static function evaluate(&$root, &$partial, $expression)
{
if ($expression === Language\Token::VAL_NULL) {
return null;
} else if ($expression === Language\Token::VAL_TRUE) {
return true;
} else if ($expression === Language\Token::VAL_FALSE) {
return false;
} else if (is_numeric($expression)) {
return floatval($expression);
} else if (preg_match(Language\Regex::EXPR_STRING, $expression)) {
return substr($expression, 1, strlen($expression) - 2);
} else if (preg_match(Language\Regex::EXPR_REGEX, $expression)) {
return $expression;
} else {
$match = array();
$length = preg_match(Language\Regex::LENGTH, $expression, $match);
if ($length) {
$expression = $match[1];
}
$result = false;
if ($expression[0] === Language\Token::ROOT){
list($result, $_) = \JsonPath\JsonPath::subtreeGet($root, $root, $expression);
}
else if ($expression[0] === Language\Token::CHILD) {
$expression[0] = Language\Token::ROOT;
list($result, $_) = \JsonPath\JsonPath::subtreeGet($root, $partial, $expression);
}
if ($result !== false) {
if ($length) {
if (is_array($result[0])) {
return (float) count($result[0]);
}
if (is_string($result[0])) {
return (float) strlen($result[0]);
}
return false;
}
if (is_float($result[0]) || is_int($result[0])) {
$result[0] = (float) $result[0];
}
return $result[0];
}
return $result;
}
}
}

View File

@@ -0,0 +1,28 @@
<?php
/**
* Copyright 2018 Alessio Linares
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace JsonPath;
/**
* Exception that is raised when a invalid value is given to the JsonObject
* constructor.
*
* @uses Exception
*/
class InvalidJsonException extends \Exception
{
}

View File

@@ -0,0 +1,40 @@
<?php
/**
* Copyright 2018 Alessio Linares
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace JsonPath;
/**
* Exception that is raised when a error is found in the given JSONPath
*
* @uses Exception
*/
class InvalidJsonPathException extends \Exception
{
private $token;
/**
* Class constructor
*
* @param string $token token related to the JSONPath error
*
* @return void
*/
public function __construct($token)
{
parent::__construct("Error in JSONPath near '" . $token . "'", 0, null);
}
}

View File

@@ -0,0 +1,338 @@
<?php
/**
* Copyright 2018 Alessio Linares
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace JsonPath;
use JsonPath\InvalidJsonException;
use JsonPath\Operation;
/**
* This is a [JSONPath](http://goessner.net/articles/JsonPath/) implementation for PHP.
*
* This implementation features all elements in the specification except the `()` operator (in the spcecification there is the `$..a[(@.length-1)]`, but this can be achieved with `$..a[-1]` and the latter is simpler).
*
* On top of this it implements some extended features:
*
* * Regex match comparisons (p.e. `$.store.book[?(@.author =~ /.*Tolkien/)]`)
* * For the child operator `[]` there is no need to surround child names with quotes (p.e. `$.[store][book, bicycle]`) except if the name of the field is a non-valid javascript variable name.
* * `.length` can be used to get the length of a string, get the length of an array and to check if a node has children.
*
* Features
* ========
* This implementation has the following features:
*
* * Object oriented implementation.
* * __Get__, __set__ and __add__ operations.
* * Magic methods implemented:
* * `__get`: `$obj->{'$.json.path'}`.
* * `__set`: `$obj->{'$.json.path'} = $val`.
* * `__toString`: `echo $obj` prints the json representation of the JsonObject.
* * Not using `eval()`.
*
* Usage
* =====
* // $json can be a string containing json, a PHP array, a PHP object or null.
* // If $json is null (or not present) the JsonObject will be empty.
* $jsonObject = new JsonObject();
* // or
* $jsonObject = new JsonObject($json);
*
* // get
* $obj->get($jsonPath);
* $obj->{'$.json.path'};
*
* // set
* $obj->set($jsonPath, $value);
* $obj->{'$.json.path'} = $value;
*
* // get the json representation
* $obj->getJson();
* $str = (string)$obj;
* echo $obj;
*
* // get the PHP array representation
* $obj->getArray();
*
* // add values
* $obj->add($jsonPath, $value[, $field]);
*
* // remove values
* $obj->remove($jsonPath, $field);
*
* SmartGet
* --------
*
* When creating a new instance of JsonObject, you can pass a second parameter to the constructor.
* This sets the behaviour of the instance to use SmartGet.
*
* What SmartGet does is to determine if the given JsonPath branches at some point, if it does it behaves as usual;
* otherwise, it will directly return the value pointed to by the given path (not the array containing it).
*
* $json = array(
* "a" => array(
* "b" => 3,
* "c" => 4
* )
* );
* $obj = new JsonObject($json, true);
* $obj->get('$.a.b'); // Returns int(3)
* $obj->get('$.a.*'); // Returns array(int(3), int(4))
*
*
* GetJsonObjects
* --------------
*
* Sometimes you need to access multiple values of a subobject that has a long prefix (p.e. `$.a.very.long.prefix.for.[*].object`), in this case you would first get said object
* and make a JsonObject of it and then access its properties.
*
* Now if you want to edit the object (set or add values) and want these changes to affect the original object, the way of doing this is by using
* `JsonObject::getJsonObjects($jsonpath)`. This method works the same way get does, but it will return the results as JsonObject instances containing a reference to the value in the source JsonObject.
*/
class JsonObject
{
private $jsonObject = null;
private $smartGet = false;
/**
* Class constructor.
* If $json is null the json object contained
* will be initialized empty.
*
* @param mixed $json json
* @param bool $smartGet enable smart get
*
* @return void
*/
function __construct($json = null, $smartGet = false)
{
if ($json === null) {
$this->jsonObject = array();
} else if (is_string($json)) {
$this->jsonObject = json_decode($json, true);
if ($this->jsonObject === null) {
throw new InvalidJsonException("string does not contain a valid JSON object.");
}
} else if (is_array($json)) {
$this->jsonObject = $json;
} else if (is_object($json)){
$this->jsonObject = json_decode(json_encode($json), true);
} else {
throw new InvalidJsonException("value does not encode a JSON object.");
}
$this->smartGet = $smartGet;
}
/**
* Syntactic sugar for toJson() method.
* Usage:
* $json = (string)$instance;
* or
* echo $instance;
*
* @param string $jsonPath jsonPath
*
* @return (false|array)
*/
function __toString()
{
return $this->getJson();
}
/**
* Syntactic sugar for get() method. The starting '$' is not needed (implicit)
* Usage: $obj->{'.json.path'};
*
* @param string $jsonPath jsonPath
*
* @return (false|array)
*/
function __get($jsonPath)
{
return $this->get($jsonPath);
}
/**
* Syntactic sugar for set() method. The starting '$' is not needed (implicit)
* Usage: $obj->{'.json.path'} = $value;
*
* @param string $jsonPath jsonPath
* @param mixed $value value
*
* @return JsonObject
*/
function __set($jsonPath, $value)
{
return $this->set($jsonPath, $value);
}
/**
* Returns the value of the json object as a PHP array.
*
*
* @return array
*/
public function &getValue()
{
return $this->jsonObject;
}
/**
* Returns the json object encoded as string.
* See http://php.net/manual/en/json.constants.php for more information on the $options bitmask.
*
* @param int $options json_encode options bitmask
*
* @return string
*/
public function getJson($options=0)
{
return json_encode($this->jsonObject, $options);
}
/**
* Returns an array containing references to the
* objects that match the JsonPath. If the result is
* empty returns false.
*
* If smartGet was set to true when creating the instance and
* the JsonPath given does not branch, it will return the value
* instead of an array of one element.
*
* @param string $jsonPath jsonPath
*
* @return mixed
*/
public function get($jsonPath)
{
list($result, $hasDiverged) = JsonPath::get($this->jsonObject, $jsonPath);
if ($this->smartGet && $result !== false && !$hasDiverged && is_array($result)) {
return $result[0];
}
return $result;
}
/**
* Return an array of new JsonObjects representing the results of the
* given JsonPath. These objects contain references to the elements in the
* original JsonObject.
*
* This is affected by smartGet the same way JsonObject::get is affected
* This can cause JsonObject to have actual values (not object/array) as root.
*
* This is useful when you want to work with a subelement of the root
* object and you want to edit (add, set, remove) values in that subelement
* and that these changes also affect the root object.
*
* @param string $jsonPath jsonPath
*
* @return mixed
*/
public function getJsonObjects($jsonPath)
{
list($result, $hasDiverged) = JsonPath::get($this->jsonObject, $jsonPath);
if ($result !== false) {
$objs = array();
foreach($result as &$value) {
$jsonObject = new JsonObject(null, $this->smartGet);
$jsonObject->jsonObject = &$value;
$objs[] = $jsonObject;
}
if ($this->smartGet && !$hasDiverged && is_array($result)) {
return $objs[0];
}
return $objs;
}
return $result;
}
/**
* Sets all elements that result from the $jsonPath query
* to $value. This method will create previously non-existent
* JSON objects if the path contains them (p.e. if quering '$.a'
* results in false, when setting '$.a.b' to a value '$.a' will be created
* as a result of this).
*
* This method returns $this to enable fluent
* interface.
*
*
* @param string $jsonPath jsonPath
* @param mixed $value value
*
* @return JsonObject
*/
public function set($jsonPath, $value)
{
list($result, $_) = JsonPath::get($this->jsonObject, $jsonPath, true);
if ($result !== false) {
foreach ($result as &$element) {
$element = $value;
}
}
return $this;
}
/**
* Append a new value to all json objects/arrays that match
* the $jsonPath path. If $field is not null, the new value
* will be added with $field as key (this will transform
* json arrays into objects). This method returns $this to
* enable fluent interface.
*
* @param string $jsonPath jsonPath
* @param mixed $value value
* @param string $field field
*
* @return JsonObject
*/
public function add($jsonPath, $value, $field=null)
{
list($result, $_) = JsonPath::get($this->jsonObject, $jsonPath, true);
foreach ($result as &$element) {
if (is_array($element)) {
if ($field == null) {
$element[] = $value;
}
else {
$element[$field] = $value;
}
}
}
return $this;
}
/**
* Remove $field from json objects/arrays that match
* $jsonPath path. This method returns $this to enable
* fluent interface.
*
* @param mixed $jsonPath jsonPath
* @param mixed $field field
*
* @return JsonObject
*/
public function remove($jsonPath, $field)
{
list($result, $_) = JsonPath::get($this->jsonObject, $jsonPath);
foreach ($result as &$element) {
if (is_array($element)) {
unset($element[$field]);
}
}
return $this;
}
}

View File

@@ -0,0 +1,94 @@
<?php
/**
* Copyright 2021 Alessio Linares
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace JsonPath;
use JsonPath\Expression;
use JsonPath\Language;
use JsonPath\Operation;
class JsonPath
{
public static function get(&$root, $jsonPath, $createInexistent = false)
{
return JsonPath::subtreeGet($root, $root, $jsonPath, $createInexistent);
}
public static function subtreeGet(&$root, &$partial, $jsonPath, $createInexistent = false)
{
$match = array();
if (preg_match(Language\Regex::ROOT_OBJECT, $jsonPath, $match) === 0) {
throw new \JsonPath\InvalidJsonPathException($jsonPath);
}
$hasDiverged = false;
$jsonPath = $match[1];
$selection = array(&$partial);
while (strlen($jsonPath) > 0 and count($selection) > 0) {
$newSelection = array();
$newHasDiverged = false;
if (preg_match(Language\Regex::CHILD_NAME, $jsonPath, $match)) {
$childName = $match[1];
foreach ($selection as &$partial) {
list($result, $newHasDiverged) = Operation\GetChild::apply($partial, $childName, $createInexistent);
$newSelection = array_merge($newSelection, $result);
}
if (empty($newSelection) && Language\Token::LENGTH === $childName) {
if (count($selection) > 1) {
foreach ($selection as $item) {
$newSelection[] = is_array($item) ? count($item) : strlen($item);
}
} else if (count($selection) == 1) {
$newSelection = is_array($selection[0]) ? count($selection[0]) : strlen($selection[0]);
}
}
if (empty($newSelection)) {
$selection = false;
break;
} else {
$jsonPath = $match[2];
}
} else if (Language\ChildSelector::match($jsonPath, $match)) {
$contents = $match[0];
foreach ($selection as &$partial) {
list($result, $newHasDiverged) = Operation\SelectChildren::apply($root, $partial, $contents, $createInexistent);
$newSelection = array_merge($newSelection, $result);
}
if (empty($newSelection)) {
$selection = false;
break;
} else {
$jsonPath = $match[1];
}
} else if (preg_match(Language\Regex::RECURSIVE_SELECTOR, $jsonPath, $match)) {
list($result, $newHasDiverged) = Operation\GetRecursive::apply($partial, $match[1]);
$newSelection = array_merge($newSelection, $result);
if (empty($newSelection)) {
$selection = false;
break;
} else {
$jsonPath = $match[2];
}
} else {
throw new \JsonPath\InvalidJsonPathException($jsonPath);
}
$selection = $newSelection;
$hasDiverged = $hasDiverged || $newHasDiverged;
}
return array($selection, $hasDiverged);
}
}

View File

@@ -0,0 +1,60 @@
<?php
/**
* Copyright 2021 Alessio Linares
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace JsonPath\Language;
class ChildSelector
{
public static function match($jsonPath, &$match, $offset=0)
{
if ($jsonPath[$offset] != Token::SELECTOR_BEGIN) {
return false;
}
$initialOffset = $offset;
$offset += 1;
$parenCount = 0;
$bracesCount = 1;
// $count is a reference to the counter of the $startChar type
$match = array();
while ($bracesCount > 0 and $parenCount >= 0) {
if (preg_match(Regex::NEXT_SUBEXPR, $jsonPath, $match, PREG_OFFSET_CAPTURE, $offset)) {
$c = $match[1][0];
if ($c === Token::EXPRESSION_BEGIN) {
$parenCount += 1;
} else if ($c === Token::EXPRESSION_END) {
$parenCount -= 1;
} else if ($c === Token::SELECTOR_BEGIN) {
$bracesCount += 1;
} else if ($c === Token::SELECTOR_END) {
$bracesCount -= 1;
}
$offset = $match[1][1] + 1;
} else {
break;
}
}
if ($bracesCount == 0 && $parenCount == 0) {
$match = array(
substr($jsonPath, $initialOffset + 1, $offset - $initialOffset - 2),
substr($jsonPath, $offset - $initialOffset)
);
return 1;
}
$match = array();
return 0;
}
}

View File

@@ -0,0 +1,45 @@
<?php
/**
* Copyright 2021 Alessio Linares
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace JsonPath\Language;
class Regex
{
// Root regex
const ROOT_OBJECT = '/^\$(.*)/';
// Child regex
const CHILD_NAME = '/^\.([\w\_\$^\d][\w\-\$]*|\*)(.*)/u';
const RECURSIVE_SELECTOR = '/^\.\.([\w\_\$^\d][\w\-\$]*|\*)(.*)/u';
// Array expressions
const ARRAY_INTERVAL = '/^(?:(-?\d*:-?\d*)|(-?\d*:-?\d*:-?\d*))$/';
const INDEX_LIST = '/^(-?\d+)(\s*,\s*-?\d+)*$/';
const LENGTH = '/^(.*)\.length$/';
// Object expression
const CHILD_NAME_LIST = '/^(?:([\w\_\$^\d][\w\-\$]*?|".*?"|\'.*?\')(\s*,\s*([\w\_\$^\d][\w\-\$]*|".*?"|\'.*?\'))*)$/u';
// Conditional expressions
const EXPR_STRING = '/^(?:\'(.*)\'|"(.*)")$/';
const EXPR_REGEX = '/^\/.*\/$/';
const BINOP_COMP = '/^(.+)\s*(==|!=|<=|>=|<|>|=\~)\s*(.+)$/';
const BINOP_OR = '/\s+(or|\|\|)\s+/';
const BINOP_AND = '/\s+(and|&&)\s+/';
const OP_NOT = '/^(not|!)\s+(.*)/';
const NEXT_SUBEXPR = '/.*?(\(|\)|\[|\])/';
}

View File

@@ -0,0 +1,43 @@
<?php
/**
* Copyright 2021 Alessio Linares
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace JsonPath\Language;
class Token
{
const ROOT = '$';
const CHILD = '@';
const SELECTOR_BEGIN = '[';
const SELECTOR_END = ']';
const BOOL_EXPR = '?';
const EXPRESSION_BEGIN = '(';
const EXPRESSION_END = ')';
const ALL = '*';
const COMA = ',';
const COLON = ':';
const COMP_EQ = '==';
const COMP_NEQ = '!=';
const COMP_LT = '<';
const COMP_GT = '>';
const COMP_LTE = '<=';
const COMP_GTE = '>=';
const COMP_RE_MATCH = '=~';
const VAL_TRUE = 'true';
const VAL_FALSE = 'false';
const VAL_NULL = 'null';
const LENGTH = 'length';
}

View File

@@ -0,0 +1,44 @@
<?php
/**
* Copyright 2021 Alessio Linares
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace JsonPath\Operation;
use JsonPath\Language;
class GetChild
{
public static function apply(&$jsonObject, $childName, $createInexistent = false)
{
if (!is_array($jsonObject)) {
return array(array(), false);
}
$result = array();
$hasDiverged = false;
if ($childName === Language\Token::ALL) {
$hasDiverged = true;
foreach ($jsonObject as $key => $_) {
$result[] = &$jsonObject[$key];
}
} else if (array_key_exists($childName, $jsonObject)) {
$result[] = &$jsonObject[$childName];
} else if ($createInexistent) {
$jsonObject[$childName] = array();
$result[] = &$jsonObject[$childName];
}
return array($result, $hasDiverged);
}
}

View File

@@ -0,0 +1,35 @@
<?php
/**
* Copyright 2021 Alessio Linares
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace JsonPath\Operation;
use JsonPath\Language;
class GetRecursive
{
public static function apply(&$jsonObject, $childName)
{
list($result, $_) = GetChild::apply($jsonObject, $childName);
if (is_array($jsonObject)) {
foreach ($jsonObject as &$item) {
list($localResult, $_) = GetRecursive::apply($item, $childName);
$result = array_merge($result, $localResult);
}
}
return array($result, true);
}
}

View File

@@ -0,0 +1,79 @@
<?php
/**
* Copyright 2021 Alessio Linares
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace JsonPath\Operation;
use JsonPath\Language;
use JsonPath\Expression;
class SelectChildren
{
public static function apply(&$root, &$partial, $contents, $createInexistent = false)
{
if (!is_array($partial)) {
return array(array(), false);
}
$result = array();
$hasDiverged = false;
$match = array();
$contentsLen = strlen($contents);
if ($contents === Language\Token::ALL) {
$hasDiverged = true;
foreach ($partial as $key => $item) {
$result[] = &$partial[$key];
}
} else if (preg_match(Language\Regex::CHILD_NAME_LIST, $contents, $match)) {
$names = array_map(
function($x) { return trim($x, " \t\n\r\0\x0B'\""); },
explode(Language\Token::COMA, $contents)
);
if (count($names) > 1) {
$hasDiverged = true;
}
$result = Expression\ChildNameList::evaluate($partial, $names, $createInexistent);
} else if (preg_match(Language\Regex::INDEX_LIST, $contents)) {
$indexes = array_map(
function($x) { return intval(trim($x)); },
explode(Language\Token::COMA, $contents)
);
if (count($indexes) > 1) {
$hasDiverged = true;
}
$result = Expression\IndexList::evaluate($partial, $indexes, $createInexistent);
} else if (preg_match(Language\Regex::ARRAY_INTERVAL, $contents, $match)) {
// end($match) has the matched group with the interval
$numbers = explode(Language\Token::COLON, end($match));
$hasDiverged = true;
$result = Expression\ArrayInterval::evaluate($partial, $numbers);
} else if ($contents[0] === Language\Token::BOOL_EXPR
&& $contents[1] === Language\Token::EXPRESSION_BEGIN
&& $contents[$contentsLen - 1] === Language\Token::EXPRESSION_END
) {
$hasDiverged = true;
$subexpr = substr($contents, 2, $contentsLen - 3);
foreach ($partial as &$child) {
if (Expression\BooleanExpression::evaluate($root, $child, $subexpr)) {
$result[] = &$child;
}
}
} else {
throw new \JsonPath\InvalidJsonPathException($contents);
}
return array($result, $hasDiverged);
}
}

View File

@@ -0,0 +1,102 @@
<?php
/**
* Copyright 2018 Alessio Linares
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace Utilities;
class ArraySlice
{
/**
* Implements the Python slice behaviour
*
* * a[1:2:3] => slice($a, 1, 2, 3)
* * a[1:4] => slice($a, 1, 4)
* * a[3::2] => slice($a, 3, null, 2)
*
* If $byReference is true, then the elements of
* the resulting array will be references to the initial
* array.
*
* @param array $array array
* @param int|null $start start
* @param int|null $stop stop
* @param int|null $step step
* @param bool $byReference byReference
*
* @return void
*/
public static function slice(&$array, $start = null, $stop = null, $step = null, $byReference = false)
{
$result = array();
$indexes = self::sliceIndices(count($array), $start, $stop, $step);
if ($byReference) {
foreach ($indexes as $i) {
$result[] = &$array[$i];
}
} else {
foreach ($indexes as $i) {
$result[] = $array[$i];
}
}
return $result;
}
private static function adjustEndpoint($length, $endpoint, $step)
{
if ($endpoint < 0) {
$endpoint += $length;
if ($endpoint < 0) {
$endpoint = ($step < 0 ? -1 : 0);
}
} else if ($endpoint >= $length) {
$endpoint = ($step < 0 ? $length - 1 : $length);
}
return $endpoint;
}
private static function adjustSlice($length, &$start, &$stop, &$step)
{
if ($step === null) {
$step = 1;
} else if ($step === 0) {
throw new \Exception("Step cannot be 0");
}
if ($start === null) {
$start = ($step < 0 ? $length - 1 : 0);
} else {
$start = self::adjustEndpoint($length, $start, $step);
}
if ($stop === null) {
$stop = ($step < 0 ? -1 : $length);
} else {
$stop = self::adjustEndpoint($length, $stop, $step);
}
}
private static function sliceIndices($length, $start, $stop, $step)
{
$result = array();
self::adjustSlice($length, $start, $stop, $step);
$i = $start;
while ($step < 0 ? ($i > $stop) : ($i < $stop)) {
$result[] = $i;
$i += $step;
}
return $result;
}
}

View File

@@ -0,0 +1,263 @@
<?php
/**
* Copyright 2019 Sergey Nikolaev
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace Tests;
use JsonPath\JsonObject;
use JsonPath\InvalidJsonException;
/**
* Class JsonObjectLengthOperatorTest
* @author Sergey Nikolaev
*/
class JsonObjectLengthOperatorTest extends \PHPUnit_Framework_TestCase
{
private $json = '{
"music": {
"bands": [
{
"title": "Godzilla",
"genre": "Heavy Metal",
"albums": [
{
"title": "First",
"release_date": "2017.01.13",
"length": "46:35"
},
{
"title": "Second",
"release_date": "2018.02.13",
"length": "56:35"
},
{
"title": "Third",
"release_date": "2019.03.13",
"length": "106:35"
}
]
},
{
"title": "Blue Velvet",
"genre": "Hard Rock",
"albums": [
{
"title": "One",
"release_date": "2011.07.26",
"length": "116:19"
},
{
"title": "Two",
"release_date": "2012.08.26",
"length": "126:19"
},
{
"title": "Three",
"release_date": "2013.09.26",
"length": "146:19"
}
]
}
],
"length":[
{
"track": "Simple Thing",
"stack": 80
},
{
"track": "Nobody",
"stack": 90
}
]
}
}';
/**
* @throws InvalidJsonException
*/
public function testObjectHasField()
{
$jsonPath = '$.music.length';
$jsonObject = new JsonObject($this->json);
$result = $jsonObject->get($jsonPath);
$this->assertEquals([
[
[
'track' => 'Simple Thing',
'stack' => 80
],
[
'track' => 'Nobody',
'stack' => 90
]
]
],
$result
);
$jsonPath = '$.music.bands[0].albums[0].length';
$result = $jsonObject->get($jsonPath);
$this->assertEquals(
[
'46:35'
],
$result
);
}
/**
* @throws InvalidJsonException
*/
public function testIntermediateLength()
{
$jsonPath = '$.music.length[0].track';
$jsonObject = new JsonObject($this->json);
$result = $jsonObject->get($jsonPath);
$this->assertEquals(
[
'Simple Thing'
],
$result
);
$jsonPath = '$.music.length[1].stack';
$result = $jsonObject->get($jsonPath);
$this->assertEquals(
[
90
],
$result
);
}
/**
* @throws InvalidJsonException
*/
public function testLength()
{
/** Array Length Test */
$jsonPath = '$.music.bands[0].albums.length';
$jsonObject = new JsonObject($this->json);
$result = $jsonObject->get($jsonPath);
$this->assertEquals(
3,
$result
);
/** String Length Test */
$jsonPath = '$.music.bands[0].albums[0].length.length';
$result = $jsonObject->get($jsonPath);
$this->assertEquals(
5,
$result
);
$jsonPath = '$.music.bands[0].albums[1].title.length';
$result = $jsonObject->get($jsonPath);
$this->assertEquals(
6,
$result
);
}
/**
* @throws InvalidJsonException
*/
public function testLengthSmartGet()
{
/** Array Length Test */
$jsonPath = '$.music.bands[0].albums.length';
$jsonObject = new JsonObject($this->json, true);
$result = $jsonObject->get($jsonPath);
$this->assertEquals(
3,
$result
);
/** String Length Test */
$jsonPath = '$.music.bands[0].albums[0].length.length';
$result = $jsonObject->get($jsonPath, true);
$this->assertEquals(
5,
$result
);
$jsonPath = '$.music.bands[0].albums[1].title.length';
$result = $jsonObject->get($jsonPath, true);
$this->assertEquals(
6,
$result
);
}
/**
* @throws InvalidJsonException
*/
public function testArrayLength()
{
/** Arrays Count Length Test */
$jsonPath = '$.music.bands[*].albums.length';
$jsonObject = new JsonObject($this->json);
$result = $jsonObject->get($jsonPath);
$this->assertEquals(
[
3,
3
],
$result
);
/** String Length Test */
$jsonPath = '$.music.bands[0].albums[*].length.length';
$result = $jsonObject->get($jsonPath);
$this->assertEquals(
[
5,
5,
6
],
$result
);
$jsonPath = '$.music.bands[0].albums[*].title.length';
$result = $jsonObject->get($jsonPath);
$this->assertEquals(
[
5,
6,
5
],
$result
);
$jsonPath = '$.music.bands[*].albums[*].length.length';
$result = $jsonObject->get($jsonPath);
$this->assertEquals(
[
5,
5,
6,
6,
6,
6
],
$result
);
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,124 @@
<?php
/**
* Copyright 2018 Alessio Linares
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace Tests\Utilities;
use Utilities\ArraySlice;
/**
* Class ArraySliceTest
* @author Alessio Linares
*/
class ArraySliceTestrraySliceTest extends \PHPUnit_Framework_TestCase
{
/**
* testSlice
*
* @param array $expected expected
* @param array $array array
* @param mixed $start start
* @param mixed $stop stop
* @param mixed $step step
* @param boolean $byReference byReference
*
* @return void
*
* @dataProvider testSliceProvider
*/
public function testSlice($expected, $array, $start=null, $stop=null, $step=null)
{
$this->assertEquals($expected, ArraySlice::slice($array, $start, $stop, $step));
}
public function testSliceProvider()
{
return array(
array(
array(1, 2, 3, 4, 5),
array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9),
1,
6
),
array(
array(1, 2, 3, 4, 5, 6, 7, 8),
array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9),
1,
-1
),
array(
array(),
array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9),
1,
-12
),
array(
array(1, 0),
array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9),
1,
-12,
-1
),
array(
array(),
array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9),
12,
5
),
array(
array(9, 8, 7, 6),
array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9),
12,
5,
-1
),
array(
array(1, 2, 3, 4, 5, 6, 7, 8, 9),
array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9),
1,
),
array(
array(0, 1, 2, 3, 4),
array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9),
null,
5
)
);
}
public function testSliceByReference()
{
$original = array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
$result = ArraySlice::slice($original, 1, 8, 2);
$result[2] = -1;
$this->assertEquals(5, $original[5]);
$result = ArraySlice::slice($original, 1, 8, 2, true);
$result[2] = -1;
$this->assertEquals(-1, $original[5]);
}
public function testSliceException()
{
$exception = null;
$array = array(0, 1, 2, 3);
try {
ArraySlice::slice($array, 1, 4, 0);
} catch (\Exception $e) {
$exception = $e;
}
$this->assertEquals("Step cannot be 0", $exception->getMessage());
}
}

View File

@@ -0,0 +1,28 @@
<?php
/**
* Copyright 2018 Alessio Linares
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Bootstrap the tests - file only used when running tests with
* phpunit
*
* @see ../phpunit.xml.dist
*/
// composer autoloader
require __DIR__ . '/../vendor/autoload.php';
ini_set('error_reporting', E_ALL | E_STRICT);