Skip to content

Commit b927fe3

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

File tree

10 files changed

+179
-78
lines changed

10 files changed

+179
-78
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: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,19 +38,34 @@ final class JsonCrawler implements JsonCrawlerInterface
3838
'value' => true,
3939
];
4040

41+
/**
42+
* @var resource|string|null
43+
*/
44+
private mixed $raw = null;
45+
4146
/**
4247
* @param resource|string $raw
48+
*
49+
* @throws \TypeError When the input is not a string or a resource
4350
*/
44-
public function __construct(
45-
private readonly mixed $raw,
46-
) {
51+
public function fromJsonString(mixed $raw): static
52+
{
4753
if (!\is_string($raw) && !\is_resource($raw)) {
48-
throw new InvalidArgumentException(\sprintf('Expected string or resource, got "%s".', get_debug_type($raw)));
54+
throw new \TypeError(\sprintf('Expected string or resource, got "%s".', get_debug_type($raw)));
4955
}
56+
57+
$clone = clone $this;
58+
$clone->raw = $raw;
59+
60+
return $clone;
5061
}
5162

5263
public function find(string|JsonPath $query): array
5364
{
65+
if (null === $this->raw) {
66+
throw new \LogicException('The crawler has no data to evaluate. Use the "withData()" method to set the JSON string or resource.');
67+
}
68+
5469
return $this->evaluate(\is_string($query) ? new JsonPath($query) : $query);
5570
}
5671

src/Symfony/Component/JsonPath/JsonCrawlerInterface.php

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,21 +11,12 @@
1111

1212
namespace Symfony\Component\JsonPath;
1313

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 JsonCrawlerInterface
14+
interface JsonCrawlerInterface extends CrawlerInterface
2315
{
2416
/**
25-
* @return list<array|string|float|int|bool|null>
17+
* @param resource|string $raw
2618
*
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
19+
* @throws \TypeError When the input is not a string or a resource
2920
*/
30-
public function find(string|JsonPath $query): array;
21+
public function fromJsonString(mixed $raw): static;
3122
}

src/Symfony/Component/JsonPath/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ $json = <<<'JSON'
2525
]}}
2626
JSON;
2727

28-
$crawler = new JsonCrawler($json);
28+
$crawler = (new JsonCrawler())->fromJsonString($json);
2929

3030
$result = $crawler->find('$.store.book[0].title');
3131
$result = $crawler->find('$.store.book[?match(@.author, "[A-Z].*el.+")]');

0 commit comments

Comments
 (0)