Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions 1 src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ CHANGELOG
* Add support for union types with `Symfony\Component\EventDispatcher\Attribute\AsEventListener`
* Add `framework.allowed_http_method_override` option
* Initialize `router.request_context`'s `_locale` parameter to `%kernel.default_locale%`
* Add JsonPath integration to register custom JsonPath functions

7.3
---
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ class UnusedTagsPass implements CompilerPassInterface
'form.type_guesser',
'html_sanitizer',
'http_client.client',
'json_path.function',
'json_streamer.value_transformer',
'kernel.cache_clearer',
'kernel.cache_warmer',
Expand All @@ -70,6 +71,8 @@ class UnusedTagsPass implements CompilerPassInterface
'mime.mime_type_guesser',
'monolog.logger',
'notifier.channel',
'object_mapper.condition_callable',
'object_mapper.transform_callable',
'property_info.access_extractor',
'property_info.constructor_extractor',
'property_info.initializable_extractor',
Expand Down Expand Up @@ -108,8 +111,6 @@ class UnusedTagsPass implements CompilerPassInterface
'validator.group_provider',
'validator.initializer',
'workflow',
'object_mapper.transform_callable',
'object_mapper.condition_callable',
];

public function process(ContainerBuilder $container): void
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
use Symfony\Component\HttpClient\HttpClient;
use Symfony\Component\HttpFoundation\Cookie;
use Symfony\Component\HttpFoundation\IpUtils;
use Symfony\Component\JsonPath\JsonPath;
use Symfony\Component\JsonStreamer\StreamWriterInterface;
use Symfony\Component\Lock\Lock;
use Symfony\Component\Lock\Store\SemaphoreStore;
Expand Down Expand Up @@ -195,6 +196,7 @@ public function getConfigTreeBuilder(): TreeBuilder
$this->addWebhookSection($rootNode, $enableIfStandalone);
$this->addRemoteEventSection($rootNode, $enableIfStandalone);
$this->addJsonStreamerSection($rootNode, $enableIfStandalone);
$this->addJsonPathSection($rootNode, $enableIfStandalone);

return $treeBuilder;
}
Expand Down Expand Up @@ -2792,4 +2794,16 @@ private function addJsonStreamerSection(ArrayNodeDefinition $rootNode, callable
->end()
;
}

private function addJsonPathSection(ArrayNodeDefinition $rootNode, callable $enableIfStandalone): void
{
$rootNode
->children()
->arrayNode('json_path')
->info('JsonPath configuration')
->{$enableIfStandalone('symfony/json-path', JsonPath::class)}()
->end()
->end()
;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,8 @@
use Symfony\Component\HttpKernel\EventListener\IsSignatureValidAttributeListener;
use Symfony\Component\HttpKernel\Log\DebugLoggerConfigurator;
use Symfony\Component\HttpKernel\Profiler\ProfilerStateChecker;
use Symfony\Component\JsonPath\Functions\AsJsonPathFunction;
use Symfony\Component\JsonPath\JsonPath;
use Symfony\Component\JsonStreamer\Attribute\JsonStreamable;
use Symfony\Component\JsonStreamer\JsonStreamWriter;
use Symfony\Component\JsonStreamer\StreamReaderInterface;
Expand Down Expand Up @@ -503,6 +505,10 @@ public function load(array $configs, ContainerBuilder $container): void
$this->registerJsonStreamerConfiguration($config['json_streamer'], $container, $loader);
}

if ($this->readConfigEnabled('json_path', $container, $config['json_path'])) {
$this->registerJsonPathConfiguration($loader);
}

if ($this->readConfigEnabled('lock', $container, $config['lock'])) {
$this->registerLockConfiguration($config['lock'], $container, $loader);
}
Expand Down Expand Up @@ -881,6 +887,12 @@ static function (ChildDefinition $definition, AsPeriodicTask|AsCronTask $attribu
])->addTag('container.excluded', ['source' => 'because it\'s a streamable JSON']);
});

$container->registerAttributeForAutoconfiguration(AsJsonPathFunction::class, static function (ChildDefinition $definition, AsJsonPathFunction $attribute) {
$definition->addTag('json_path.function', [
'name' => $attribute->name,
]);
});

if (!$container->getParameter('kernel.debug')) {
// remove tagged iterator argument for resource checkers
$container->getDefinition('config_cache_factory')->setArguments([]);
Expand Down Expand Up @@ -2315,6 +2327,15 @@ private function registerTypeInfoConfiguration(array $config, ContainerBuilder $
}
}

private function registerJsonPathConfiguration(PhpFileLoader $loader): void
{
if (!class_exists(JsonPath::class)) {
throw new LogicException('JsonPath support cannot be enabled as the JsonPath component is not installed. Try running "composer require symfony/json-path".');
}

$loader->load('json_path.php');
}

private function registerLockConfiguration(array $config, ContainerBuilder $container, PhpFileLoader $loader): void
{
$loader->load('lock.php');
Expand Down
24 changes: 24 additions & 0 deletions 24 src/Symfony/Bundle/FrameworkBundle/Resources/config/json_path.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Component\DependencyInjection\Loader\Configurator;

use Symfony\Component\JsonPath\Functions\JsonPathFunctionsProvider;
use Symfony\Component\JsonPath\Functions\JsonPathFunctionsProviderInterface;

return static function (ContainerConfigurator $container) {
$container->services()
->set('json_path.functions_provider', JsonPathFunctionsProvider::class)
->args([
tagged_locator('json_path.function', 'name'),
])
->alias(JsonPathFunctionsProviderInterface::class, 'json_path.functions_provider');
};
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HtmlSanitizer\HtmlSanitizer;
use Symfony\Component\HttpClient\HttpClient;
use Symfony\Component\JsonPath\JsonPath;
use Symfony\Component\JsonStreamer\JsonStreamWriter;
use Symfony\Component\Lock\Store\SemaphoreStore;
use Symfony\Component\Mailer\Mailer;
Expand Down Expand Up @@ -1068,6 +1069,9 @@ class_exists(SemaphoreStore::class) && SemaphoreStore::isSupported() ? 'semaphor
'json_streamer' => [
'enabled' => !class_exists(FullStack::class) && class_exists(JsonStreamWriter::class),
],
'json_path' => [
'enabled' => !class_exists(FullStack::class) && class_exists(JsonPath::class),
],
];
}

Expand Down
1 change: 1 addition & 0 deletions 1 src/Symfony/Bundle/FrameworkBundle/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@
"symfony/workflow": "^7.4|^8.0",
"symfony/yaml": "^7.3|^8.0",
"symfony/property-info": "^6.4|^7.0|^8.0",
"symfony/json-path": "^7.4|^8.0",
"symfony/json-streamer": "^7.3|^8.0",
"symfony/uid": "^6.4|^7.0|^8.0",
"symfony/web-link": "^6.4|^7.0|^8.0",
Expand Down
2 changes: 2 additions & 0 deletions 2 src/Symfony/Component/JsonPath/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ CHANGELOG
---

* The component is not marked as `@experimental` anymore
* Add `JsonPathFunctionsProviderInterface`, `JsonPathFunctionInterface` and `JsonPathFunctionArgumentTrait` to allow registering custom JsonPath functions
* Add the `#[AsJsonPathFunction]` attribute to declare custom JsonPath functions

7.3
---
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
*/
class InvalidJsonPathException extends \LogicException implements ExceptionInterface
{
public function __construct(string $message, ?int $position = null)
public function __construct(string $message, ?int $position = null, ?\Throwable $previous = null)
{
parent::__construct(\sprintf('JSONPath syntax error%s: %s', $position ? ' at position '.$position : '', $message));
parent::__construct(\sprintf('JSONPath syntax error%s: %s', $position ? ' at position '.$position : '', $message), previous: $previous);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Component\JsonPath\Exception;

/**
* @author Alexandre Daubois <alex.daubois@gmail.com>
*/
class UnknownJsonPathFunctionException extends \RuntimeException implements ExceptionInterface
{
public function __construct(string $name, ?\Throwable $previous = null)
{
parent::__construct(\sprintf('Unknown JSONPath function "%s".', $name), previous: $previous);
}
}
26 changes: 26 additions & 0 deletions 26 src/Symfony/Component/JsonPath/Functions/AsJsonPathFunction.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Component\JsonPath\Functions;

/**
* Declares a service as a JsonPath function, usable in JSONPath expressions.
*
* @author Alexandre Daubois <alex.daubois@gmail.com>
*/
#[\Attribute(\Attribute::TARGET_CLASS)]
class AsJsonPathFunction
{
public function __construct(
public readonly string $name,
) {
}
}
35 changes: 35 additions & 0 deletions 35 src/Symfony/Component/JsonPath/Functions/CountFunction.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Component\JsonPath\Functions;

/**
* @author Alexandre Daubois <alex.daubois@gmail.com>
*
* @internal
*/
final class CountFunction implements JsonPathComparableFunctionInterface
{
use JsonPathFunctionArgumentTrait;

public function __invoke(array $args, mixed $context): int
{
$results = $args[0] ?? [];

return \is_array($results) ? \count($results) : 0;
}

public function validate(string $name, array $args): void
{
$this->assertArgumentsCount($name, $args, 1);
$this->assertIsQuery($name, trim($args[0]));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Component\JsonPath\Functions;

/**
* Interface for functions that return values that must be compared (not used as
* standalone boolean expressions). These functions will be validated to ensure they are used in
* comparison expressions, such as `==`, `!=`, `<`, `<=`, `>`, or `>=`.
*
* @author Alexandre Daubois <alex.daubois@gmail.com>
*/
interface JsonPathComparableFunctionInterface extends JsonPathFunctionInterface
{
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Component\JsonPath\Functions;

use Symfony\Component\JsonPath\Exception\InvalidArgumentException;

/**
* @author Alexandre Daubois <alex.daubois@gmail.com>
*/
trait JsonPathFunctionArgumentTrait
{
/**
* @param list<string> $args
*/
public function assertArgumentsCount(string $name, array $args, int $expectedCount): void
{
if (\count($args) !== $expectedCount) {
throw new InvalidArgumentException(\sprintf('the JsonPath function "%s" requires exactly %d argument(s).', $name, $expectedCount));
}
}

public function assertIsSingularQuery(string $name, string $arg): void
{
if (preg_match('/@\.\*/', trim($arg))) {
throw new InvalidArgumentException(\sprintf('the JsonPath function "%s" argument must be a singular query.', $name));
}
}

public function assertIsQuery(string $name, string $arg): void
{
if (preg_match('/^(true|false|null|\d+(\.\d+)?([eE][+-]?\d+)?|\'[^\']*\'|"[^"]*")$/', $arg)) {
throw new InvalidArgumentException(\sprintf('the JsonPath function "%s" requires a query argument, not a literal.', $name));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Component\JsonPath\Functions;

use Symfony\Component\JsonPath\Exception\InvalidArgumentException;

/**
* @author Alexandre Daubois <alex.daubois@gmail.com>
*/
interface JsonPathFunctionInterface
{
/**
* @param list<string> $args List of argument strings as they appear in the expression
* @param mixed $context The current node to which the function is applied
*/
public function __invoke(array $args, mixed $context): mixed;

/**
* Validates the arguments during tokenization/parsing phase.
*
* @param list<string> $args List of argument strings as they appear in the expression
*
* @throws InvalidArgumentException When arguments are invalid
*/
public function validate(string $name, array $args): void;
}
Loading
Loading
Morty Proxy This is a proxified and sanitized view of the page, visit original site.