Skip to content

Commit 59de533

Browse files
[JsonPath] Add FrameworkBundle integration
1 parent 298e56a commit 59de533

File tree

9 files changed

+211
-77
lines changed

9 files changed

+211
-77
lines changed

src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
use Symfony\Component\HttpClient\HttpClient;
3232
use Symfony\Component\HttpFoundation\Cookie;
3333
use Symfony\Component\HttpFoundation\IpUtils;
34+
use Symfony\Component\JsonPath\JsonPath;
3435
use Symfony\Component\JsonStreamer\StreamWriterInterface;
3536
use Symfony\Component\Lock\Lock;
3637
use Symfony\Component\Lock\Store\SemaphoreStore;
@@ -186,6 +187,7 @@ public function getConfigTreeBuilder(): TreeBuilder
186187
$this->addWebhookSection($rootNode, $enableIfStandalone);
187188
$this->addRemoteEventSection($rootNode, $enableIfStandalone);
188189
$this->addJsonStreamerSection($rootNode, $enableIfStandalone);
190+
$this->addJsonPathSection($rootNode, $enableIfStandalone);
189191

190192
return $treeBuilder;
191193
}
@@ -2763,4 +2765,16 @@ private function addJsonStreamerSection(ArrayNodeDefinition $rootNode, callable
27632765
->end()
27642766
;
27652767
}
2768+
2769+
private function addJsonPathSection(ArrayNodeDefinition $rootNode, callable $enableIfStandalone): void
2770+
{
2771+
$rootNode
2772+
->children()
2773+
->arrayNode('json_path')
2774+
->info('JsonPath configuration')
2775+
->{$enableIfStandalone('symfony/json-path', JsonPath::class)}()
2776+
->end()
2777+
->end()
2778+
;
2779+
}
27662780
}

src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@
107107
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
108108
use Symfony\Component\HttpKernel\Log\DebugLoggerConfigurator;
109109
use Symfony\Component\HttpKernel\Profiler\ProfilerStateChecker;
110+
use Symfony\Component\JsonPath\JsonPath;
110111
use Symfony\Component\JsonStreamer\Attribute\JsonStreamable;
111112
use Symfony\Component\JsonStreamer\JsonStreamWriter;
112113
use Symfony\Component\JsonStreamer\StreamReaderInterface;
@@ -476,6 +477,10 @@ public function load(array $configs, ContainerBuilder $container): void
476477
$this->registerJsonStreamerConfiguration($config['json_streamer'], $container, $loader);
477478
}
478479

480+
if ($this->readConfigEnabled('json_path', $container, $config['json_path'])) {
481+
$this->registerJsonPathConfiguration($config['json_path'], $container, $loader);
482+
}
483+
479484
if ($this->readConfigEnabled('lock', $container, $config['lock'])) {
480485
$this->registerLockConfiguration($config['lock'], $container, $loader);
481486
}
@@ -2134,6 +2139,15 @@ private function registerJsonStreamerConfiguration(array $config, ContainerBuild
21342139
}
21352140
}
21362141

2142+
private function registerJsonPathConfiguration(array $config, ContainerBuilder $container, PhpFileLoader $loader): void
2143+
{
2144+
if (class_exists(JsonPath::class)) {
2145+
throw new LogicException('JsonPath support cannot be enabled as the JsonPath component is not installed. Try running "composer require symfony/json-path".');
2146+
}
2147+
2148+
$loader->load('json_path.php');
2149+
}
2150+
21372151
private function registerPropertyInfoConfiguration(array $config, ContainerBuilder $container, PhpFileLoader $loader): void
21382152
{
21392153
if (!interface_exists(PropertyInfoExtractorInterface::class)) {
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\DependencyInjection\Loader\Configurator;
13+
14+
use Symfony\Component\JsonPath\JsonCrawler;
15+
use Symfony\Component\JsonPath\JsonCrawlerInterface;
16+
17+
return static function (ContainerConfigurator $container) {
18+
$container->services()
19+
->set('json_path.crawler', JsonCrawler::class)
20+
->alias(JsonCrawlerInterface::class, 'json_path.crawler');
21+
};

src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
use Symfony\Component\DependencyInjection\ContainerBuilder;
2323
use Symfony\Component\HtmlSanitizer\HtmlSanitizer;
2424
use Symfony\Component\HttpClient\HttpClient;
25+
use Symfony\Component\JsonPath\JsonPath;
2526
use Symfony\Component\JsonStreamer\JsonStreamWriter;
2627
use Symfony\Component\Lock\Store\SemaphoreStore;
2728
use Symfony\Component\Mailer\Mailer;
@@ -1014,6 +1015,9 @@ class_exists(SemaphoreStore::class) && SemaphoreStore::isSupported() ? 'semaphor
10141015
'json_streamer' => [
10151016
'enabled' => !class_exists(FullStack::class) && class_exists(JsonStreamWriter::class),
10161017
],
1018+
'json_path' => [
1019+
'enabled' => !class_exists(FullStack::class) && class_exists(JsonPath::class),
1020+
]
10171021
];
10181022
}
10191023

src/Symfony/Bundle/FrameworkBundle/composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@
4949
"symfony/expression-language": "^6.4|^7.0",
5050
"symfony/html-sanitizer": "^6.4|^7.0",
5151
"symfony/http-client": "^6.4|^7.0",
52+
"symfony/json-path": "7.3.*",
53+
"symfony/json-streamer": "7.3.*",
5254
"symfony/lock": "^6.4|^7.0",
5355
"symfony/mailer": "^6.4|^7.0",
5456
"symfony/messenger": "^6.4|^7.0",
@@ -70,7 +72,6 @@
7072
"symfony/workflow": "^7.3",
7173
"symfony/yaml": "^6.4|^7.0",
7274
"symfony/property-info": "^6.4|^7.0",
73-
"symfony/json-streamer": "7.3.*",
7475
"symfony/uid": "^6.4|^7.0",
7576
"symfony/web-link": "^6.4|^7.0",
7677
"symfony/webhook": "^7.2",
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\JsonPath;
13+
14+
use Symfony\Component\JsonPath\Exception\InvalidArgumentException;
15+
use Symfony\Component\JsonPath\Exception\JsonCrawlerException;
16+
17+
/**
18+
* @author Alexandre Daubois <alex.daubois@gmail.com>
19+
*
20+
* @experimental
21+
*/
22+
interface CrawlerInterface
23+
{
24+
/**
25+
* @return list<array|string|float|int|bool|null>
26+
*
27+
* @throws InvalidArgumentException When the data source provided to the crawler cannot be decoded
28+
* @throws JsonCrawlerException When a syntax error occurs in the provided JSON path
29+
*/
30+
public function find(string|JsonPath $query): array;
31+
}

src/Symfony/Component/JsonPath/JsonCrawler.php

Lines changed: 27 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
*
2929
* @experimental
3030
*/
31-
final class JsonCrawler implements JsonCrawlerInterface
31+
final class JsonCrawler implements CrawlerInterface, JsonCrawlerInterface
3232
{
3333
private const RFC9535_FUNCTIONS = [
3434
'length' => true,
@@ -39,16 +39,23 @@ final class JsonCrawler implements JsonCrawlerInterface
3939
];
4040

4141
/**
42-
* @param resource|string $raw
42+
* @param resource|string|array $data
4343
*/
44-
public function __construct(
45-
private readonly mixed $raw,
46-
) {
47-
if (!\is_string($raw) && !\is_resource($raw)) {
48-
throw new InvalidArgumentException(\sprintf('Expected string or resource, got "%s".', get_debug_type($raw)));
44+
public function __construct(private mixed $data = [])
45+
{
46+
if (!\is_string($data) && !\is_resource($data) && !\is_array($data)) {
47+
throw new \TypeError(\sprintf('Argument #1 ($data) must be of type string, array or resource, %s given.', get_debug_type($data)));
4948
}
5049
}
5150

51+
/**
52+
* @param resource|string|array $data
53+
*/
54+
public function fromJson(mixed $data): CrawlerInterface
55+
{
56+
return new self($data);
57+
}
58+
5259
public function find(string|JsonPath $query): array
5360
{
5461
return $this->evaluate(\is_string($query) ? new JsonPath($query) : $query);
@@ -58,29 +65,33 @@ private function evaluate(JsonPath $query): array
5865
{
5966
try {
6067
$tokens = JsonPathTokenizer::tokenize($query);
61-
$json = $this->raw;
68+
$json = $this->data;
6269

63-
if (\is_resource($this->raw)) {
70+
if (\is_resource($this->data)) {
6471
if (!class_exists(Splitter::class)) {
6572
throw new \LogicException('The JsonStreamer package is required to evaluate a path against a resource. Try running "composer require symfony/json-streamer".');
6673
}
6774

6875
$simplified = JsonPathUtils::findSmallestDeserializableStringAndPath(
6976
$tokens,
70-
$this->raw,
77+
$this->data,
7178
);
7279

7380
$tokens = $simplified['tokens'];
7481
$json = $simplified['json'];
7582
}
7683

77-
try {
78-
$data = json_decode($json, true, 512, \JSON_THROW_ON_ERROR);
79-
} catch (\JsonException $e) {
80-
throw new InvalidJsonStringInputException($e->getMessage(), $e);
81-
}
84+
if (\is_array($json)) {
85+
$current = [$json];
86+
} else {
87+
try {
88+
$data = json_decode($json, true, 512, \JSON_THROW_ON_ERROR);
89+
} catch (\JsonException $e) {
90+
throw new InvalidJsonStringInputException($e->getMessage(), $e);
91+
}
8292

83-
$current = [$data];
93+
$current = [$data];
94+
}
8495

8596
foreach ($tokens as $token) {
8697
$next = [];

src/Symfony/Component/JsonPath/JsonCrawlerInterface.php

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,6 @@
1111

1212
namespace Symfony\Component\JsonPath;
1313

14-
use Symfony\Component\JsonPath\Exception\InvalidArgumentException;
15-
use Symfony\Component\JsonPath\Exception\JsonCrawlerException;
16-
1714
/**
1815
* @author Alexandre Daubois <alex.daubois@gmail.com>
1916
*
@@ -22,10 +19,7 @@
2219
interface JsonCrawlerInterface
2320
{
2421
/**
25-
* @return list<array|string|float|int|bool|null>
26-
*
27-
* @throws InvalidArgumentException When the JSON string provided to the crawler cannot be decoded
28-
* @throws JsonCrawlerException When a syntax error occurs in the provided JSON path
22+
* @param resource|string|array $data
2923
*/
30-
public function find(string|JsonPath $query): array;
24+
public function fromJson(mixed $data): CrawlerInterface;
3125
}

0 commit comments

Comments
 (0)