Skip to content

Commit bc396df

Browse files
[JsonPath] Add FrameworkBundle integration
1 parent 29da4f5 commit bc396df

File tree

9 files changed

+212
-74
lines changed

9 files changed

+212
-74
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;
@@ -184,6 +185,7 @@ public function getConfigTreeBuilder(): TreeBuilder
184185
$this->addWebhookSection($rootNode, $enableIfStandalone);
185186
$this->addRemoteEventSection($rootNode, $enableIfStandalone);
186187
$this->addJsonStreamerSection($rootNode, $enableIfStandalone);
188+
$this->addJsonPathSection($rootNode, $enableIfStandalone);
187189

188190
return $treeBuilder;
189191
}
@@ -2742,4 +2744,16 @@ private function addJsonStreamerSection(ArrayNodeDefinition $rootNode, callable
27422744
->end()
27432745
;
27442746
}
2747+
2748+
private function addJsonPathSection(ArrayNodeDefinition $rootNode, callable $enableIfStandalone): void
2749+
{
2750+
$rootNode
2751+
->children()
2752+
->arrayNode('json_path')
2753+
->info('JsonPath configuration')
2754+
->{$enableIfStandalone('symfony/json-path', JsonPath::class)}()
2755+
->end()
2756+
->end()
2757+
;
2758+
}
27452759
}

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@
106106
use Symfony\Component\HttpKernel\DataCollector\DataCollectorInterface;
107107
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
108108
use Symfony\Component\HttpKernel\Log\DebugLoggerConfigurator;
109+
use Symfony\Component\JsonPath\JsonPath;
109110
use Symfony\Component\JsonStreamer\Attribute\JsonStreamable;
110111
use Symfony\Component\JsonStreamer\JsonStreamWriter;
111112
use Symfony\Component\JsonStreamer\StreamReaderInterface;
@@ -474,6 +475,10 @@ public function load(array $configs, ContainerBuilder $container): void
474475
$this->registerJsonStreamerConfiguration($config['json_streamer'], $container, $loader);
475476
}
476477

478+
if ($this->readConfigEnabled('json_path', $container, $config['json_path'])) {
479+
$this->registerJsonPathConfiguration($config['json_streamer'], $container, $loader);
480+
}
481+
477482
if ($this->readConfigEnabled('lock', $container, $config['lock'])) {
478483
$this->registerLockConfiguration($config['lock'], $container, $loader);
479484
}
@@ -2119,6 +2124,15 @@ private function registerJsonStreamerConfiguration(array $config, ContainerBuild
21192124
}
21202125
}
21212126

2127+
private function registerJsonPathConfiguration(array $config, ContainerBuilder $container, PhpFileLoader $loader): void
2128+
{
2129+
if (class_exists(JsonPath::class)) {
2130+
throw new LogicException('JsonPath support cannot be enabled as the JsonPath component is not installed. Try running "composer require symfony/json-path".');
2131+
}
2132+
2133+
$loader->load('json_path.php');
2134+
}
2135+
21222136
private function registerPropertyInfoConfiguration(array $config, ContainerBuilder $container, PhpFileLoader $loader): void
21232137
{
21242138
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": "^6.4|^7.0",
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 JSON string 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: 28 additions & 13 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,14 +39,25 @@ final class JsonCrawler implements JsonCrawlerInterface
3939
];
4040

4141
/**
42-
* @param resource|string $raw
42+
* @var resource|string|array|null
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+
private mixed $raw;
45+
46+
/**
47+
* @param resource|string|array|null $data
48+
*/
49+
public function __construct(mixed $data = [])
50+
{
51+
if (!\is_string($data) && !\is_resource($data) && !\is_array($data)) {
52+
throw new \TypeError(\sprintf('Argument #1 ($data) must be of type string, array or resource, %s given.', get_debug_type($data)));
4953
}
54+
55+
$this->raw = $data;
56+
}
57+
58+
public function fromJson(mixed $data): CrawlerInterface
59+
{
60+
return new self($data);
5061
}
5162

5263
public function find(string|JsonPath $query): array
@@ -74,13 +85,17 @@ private function evaluate(JsonPath $query): array
7485
$json = $simplified['json'];
7586
}
7687

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-
}
88+
if (\is_array($json)) {
89+
$current = [$json];
90+
} else {
91+
try {
92+
$data = json_decode($json, true, 512, \JSON_THROW_ON_ERROR);
93+
} catch (\JsonException $e) {
94+
throw new InvalidJsonStringInputException($e->getMessage(), $e);
95+
}
8296

83-
$current = [$data];
97+
$current = [$data];
98+
}
8499

85100
foreach ($tokens as $token) {
86101
$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)