Skip to content
Commits on Source (10)
# v0.1.75
* The logging context now includes the active symfony route name
# v0.1.59
* api-docs: compatibility fixes for relay-auth-bundle v0.1.12
......
......@@ -6082,16 +6082,16 @@
},
{
"name": "twig/twig",
"version": "v3.5.0",
"version": "v3.5.1",
"source": {
"type": "git",
"url": "https://github.com/twigphp/Twig.git",
"reference": "3ffcf4b7d890770466da3b2666f82ac054e7ec72"
"reference": "a6e0510cc793912b451fd40ab983a1d28f611c15"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/twigphp/Twig/zipball/3ffcf4b7d890770466da3b2666f82ac054e7ec72",
"reference": "3ffcf4b7d890770466da3b2666f82ac054e7ec72",
"url": "https://api.github.com/repos/twigphp/Twig/zipball/a6e0510cc793912b451fd40ab983a1d28f611c15",
"reference": "a6e0510cc793912b451fd40ab983a1d28f611c15",
"shasum": ""
},
"require": {
......@@ -6142,7 +6142,7 @@
],
"support": {
"issues": "https://github.com/twigphp/Twig/issues",
"source": "https://github.com/twigphp/Twig/tree/v3.5.0"
"source": "https://github.com/twigphp/Twig/tree/v3.5.1"
},
"funding": [
{
......@@ -6154,7 +6154,7 @@
"type": "tidelift"
}
],
"time": "2022-12-27T12:28:18+00:00"
"time": "2023-02-08T07:49:20+00:00"
},
{
"name": "webmozart/assert",
......@@ -7484,16 +7484,16 @@
},
{
"name": "phpstan/phpstan",
"version": "1.9.14",
"version": "1.9.17",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan.git",
"reference": "e5fcc96289cf737304286a9b505fbed091f02e58"
"reference": "204e459e7822f2c586463029f5ecec31bb45a1f2"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/e5fcc96289cf737304286a9b505fbed091f02e58",
"reference": "e5fcc96289cf737304286a9b505fbed091f02e58",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/204e459e7822f2c586463029f5ecec31bb45a1f2",
"reference": "204e459e7822f2c586463029f5ecec31bb45a1f2",
"shasum": ""
},
"require": {
......@@ -7523,7 +7523,7 @@
],
"support": {
"issues": "https://github.com/phpstan/phpstan/issues",
"source": "https://github.com/phpstan/phpstan/tree/1.9.14"
"source": "https://github.com/phpstan/phpstan/tree/1.9.17"
},
"funding": [
{
......@@ -7539,20 +7539,20 @@
"type": "tidelift"
}
],
"time": "2023-01-19T10:47:09+00:00"
"time": "2023-02-08T12:25:00+00:00"
},
{
"name": "phpstan/phpstan-phpunit",
"version": "1.3.3",
"version": "1.3.4",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan-phpunit.git",
"reference": "54a24bd23e9e80ee918cdc24f909d376c2e273f7"
"reference": "d77af96c1aaec28f7c0293677132eaaad079e01b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/54a24bd23e9e80ee918cdc24f909d376c2e273f7",
"reference": "54a24bd23e9e80ee918cdc24f909d376c2e273f7",
"url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/d77af96c1aaec28f7c0293677132eaaad079e01b",
"reference": "d77af96c1aaec28f7c0293677132eaaad079e01b",
"shasum": ""
},
"require": {
......@@ -7589,22 +7589,22 @@
"description": "PHPUnit extensions and rules for PHPStan",
"support": {
"issues": "https://github.com/phpstan/phpstan-phpunit/issues",
"source": "https://github.com/phpstan/phpstan-phpunit/tree/1.3.3"
"source": "https://github.com/phpstan/phpstan-phpunit/tree/1.3.4"
},
"time": "2022-12-21T15:25:00+00:00"
"time": "2023-02-09T08:05:29+00:00"
},
{
"name": "phpstan/phpstan-symfony",
"version": "1.2.22",
"version": "1.2.23",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan-symfony.git",
"reference": "cbf5b9ceadab8365ed46db42dcd23db1a4c26c93"
"reference": "8a8d0538ca943b20beda7e9799e14fb3683262d4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan-symfony/zipball/cbf5b9ceadab8365ed46db42dcd23db1a4c26c93",
"reference": "cbf5b9ceadab8365ed46db42dcd23db1a4c26c93",
"url": "https://api.github.com/repos/phpstan/phpstan-symfony/zipball/8a8d0538ca943b20beda7e9799e14fb3683262d4",
"reference": "8a8d0538ca943b20beda7e9799e14fb3683262d4",
"shasum": ""
},
"require": {
......@@ -7660,9 +7660,9 @@
"description": "Symfony Framework extensions and rules for PHPStan",
"support": {
"issues": "https://github.com/phpstan/phpstan-symfony/issues",
"source": "https://github.com/phpstan/phpstan-symfony/tree/1.2.22"
"source": "https://github.com/phpstan/phpstan-symfony/tree/1.2.23"
},
"time": "2023-02-01T13:26:41+00:00"
"time": "2023-02-06T10:42:02+00:00"
},
{
"name": "phpunit/php-code-coverage",
......
......@@ -16,10 +16,10 @@ class AuthorizationDataMuxer
/** @var iterable<AuthorizationDataProviderInterface> */
private $authorizationDataProviders;
/** @var array<string, array> */
/** @var array<int, array> */
private $providerCache;
/** @var array<string, string[]> */
/** @var array<int, string[]> */
private $availableCache;
/** @var EventDispatcherInterface */
......@@ -73,7 +73,7 @@ class AuthorizationDataMuxer
private function getProviderAvailableAttributes(AuthorizationDataProviderInterface $prov): array
{
// Caches getAvailableAttributes for each provider
$provKey = get_class($prov);
$provKey = spl_object_id($prov);
if (!array_key_exists($provKey, $this->availableCache)) {
$this->availableCache[$provKey] = $prov->getAvailableAttributes();
}
......@@ -89,7 +89,7 @@ class AuthorizationDataMuxer
private function getProviderUserAttributes(AuthorizationDataProviderInterface $prov, ?string $userIdentifier): array
{
// We cache the attributes for each provider, but only for the last userIdentifier
$provKey = get_class($prov);
$provKey = spl_object_id($prov);
if (!array_key_exists($provKey, $this->providerCache) || $this->providerCache[$provKey][0] !== $userIdentifier) {
$this->providerCache[$provKey] = [$userIdentifier, $prov->getUserAttributes($userIdentifier)];
}
......@@ -112,7 +112,7 @@ class AuthorizationDataMuxer
throw new AuthorizationException(sprintf('attribute \'%s\' undefined', $attributeName), AuthorizationException::ATTRIBUTE_UNDEFINED);
}
$value = $defaultValue;
$value = null;
foreach ($this->authorizationDataProviders as $authorizationDataProvider) {
$availableAttributes = $this->getProviderAvailableAttributes($authorizationDataProvider);
if (!in_array($attributeName, $availableAttributes, true)) {
......@@ -140,6 +140,6 @@ class AuthorizationDataMuxer
array_pop($this->attributeStack);
}
return $event->getAttributeValue();
return $event->getAttributeValue() ?? $defaultValue;
}
}
<?php
declare(strict_types=1);
namespace Dbp\Relay\CoreBundle\Authorization\Serializer;
use Dbp\Relay\CoreBundle\Authorization\AbstractAuthorizationService;
use Dbp\Relay\CoreBundle\Helpers\ApiPlatformHelperFunctions;
use Symfony\Component\Config\Definition\Builder\NodeDefinition;
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\Serializer\Normalizer\ContextAwareNormalizerInterface;
use Symfony\Component\Serializer\Normalizer\NormalizerAwareInterface;
use Symfony\Component\Serializer\Normalizer\NormalizerAwareTrait;
abstract class AbstractEntityNormalizer extends AbstractAuthorizationService implements ContextAwareNormalizerInterface, NormalizerAwareInterface
{
use NormalizerAwareTrait;
private const ROOT_CONFIG_NODE = 'attribute_access';
private const ENTITY_SHORT_NAME_KEY = 'short_name';
private const ATTRIBUTE_NAMES_KEY = 'attribute_names';
private const ENTITY_OBJECT_ALIAS = 'entity';
/** @var Security */
private $security;
/** @var array */
private $entityClassNames;
/** @var array */
private $entityClassNameToAttributeNamesMapping;
public static function getAttributeAccessConfigNodeDefinition(array $entityShortNameToAttributeNamesMapping): NodeDefinition
{
$treeBuilder = new TreeBuilder(self::ROOT_CONFIG_NODE);
foreach ($entityShortNameToAttributeNamesMapping as $entityShortName => $attributeNames) {
$attributeNodeBuilder = $treeBuilder->getRootNode()->children()->arrayNode($entityShortName)
->addDefaultsIfNotSet()
->children();
foreach ($attributeNames as $attributeName) {
$attributeNodeBuilder->scalarNode($attributeName)
->defaultValue('false')
->info(sprintf('viewer role expression for attribute \'%s\' under entity \'%s\'', $attributeName, $entityShortName))
->end();
}
}
return $treeBuilder->getRootNode();
}
private static function toAttributeId(string $entityShortName, string $attributeName): string
{
return $entityShortName.':'.$attributeName;
}
private static function getUniqueAlreadyCalledKeyForEntity(string $entityClassName): string
{
return self::class.$entityClassName;
}
protected function __construct(array $entityClassNames)
{
$this->entityClassNames = $entityClassNames;
$this->entityClassNameToAttributeNamesMapping = [];
}
public function setConfig(array $config)
{
$configNode = $config[self::ROOT_CONFIG_NODE] ?? [];
$rightExpressions = [];
foreach ($this->entityClassNames as $entityClassName) {
$entityShortName = ApiPlatformHelperFunctions::getShortNameForResource($entityClassName);
$entityNode = $configNode[$entityShortName] ?? null;
if ($entityNode !== null) {
$attributeNames = [];
foreach ($entityNode as $attributeName => $attributeAuthorizationExpression) {
$rightExpressions[self::toAttributeId($entityShortName, $attributeName)] = $attributeAuthorizationExpression;
$attributeNames[] = $attributeName;
}
$this->entityClassNameToAttributeNamesMapping[$entityClassName] = [
self::ENTITY_SHORT_NAME_KEY => $entityShortName,
self::ATTRIBUTE_NAMES_KEY => $attributeNames,
];
}
}
parent::setConfig(parent::createConfig($rightExpressions));
}
/**
* @required
*/
public function __inject(Security $security)
{
$this->security = $security;
}
/**
* {@inheritDoc}
*/
public function normalize($object, $format = null, array $context = [])
{
$entityClassName = get_class($object);
$mapEntry = $this->entityClassNameToAttributeNamesMapping[$entityClassName] ?? null;
if ($mapEntry !== null) {
$entityShortName = $mapEntry[self::ENTITY_SHORT_NAME_KEY];
foreach ($mapEntry[self::ATTRIBUTE_NAMES_KEY] as $attributeName) {
$attributeId = self::toAttributeId($entityShortName, $attributeName);
if ($this->isGranted($attributeId, $object, self::ENTITY_OBJECT_ALIAS)) {
$context['groups'][] = $attributeId;
}
}
}
$context[self::getUniqueAlreadyCalledKeyForEntity($entityClassName)] = true;
return $this->normalizer->normalize($object, $format, $context);
}
/**
* {@inheritDoc}
*/
public function supportsNormalization($data, $format = null, array $context = []): bool
{
if (!is_object($data)) {
return false;
}
$entityClassName = get_class($data);
// Make sure we're not called twice
if (isset($context[self::getUniqueAlreadyCalledKeyForEntity($entityClassName)])) {
return false;
}
return array_key_exists($entityClassName, $this->entityClassNameToAttributeNamesMapping);
}
}
<?php
declare(strict_types=1);
namespace Dbp\Relay\CoreBundle\Helpers;
use ApiPlatform\Core\Exception\ResourceClassNotFoundException;
use ApiPlatform\Core\Metadata\Resource\Factory\AnnotationResourceMetadataFactory;
use Dbp\Relay\CoreBundle\Exception\ApiError;
use Doctrine\Common\Annotations\AnnotationReader;
class ApiPlatformHelperFunctions
{
/**
* Returns the 'shortName' attribute of the ApiResource annotation of the entity with the given class name.
*
* @throws ApiError if the ApiResource annotation of $resourceClass is not found or doesn't have a non-empty 'shortName' attribute
*/
public static function getShortNameForResource(string $resourceClass): string
{
$resourceMetadataFactory = new AnnotationResourceMetadataFactory(new AnnotationReader());
try {
$resourceMetadata = $resourceMetadataFactory->create($resourceClass);
} catch (ResourceClassNotFoundException $exc) {
throw new ApiError(500, $exc->getMessage());
}
$uniqueName = $resourceMetadata->getShortName() ?? '';
if (Tools::isNullOrEmpty($uniqueName)) {
throw new ApiError(500, sprintf("'shortName' attribute missing in ApiResource annotation of resource class '%s'", $resourceClass));
} elseif (str_contains($uniqueName, '.') || str_contains($uniqueName, ',')) {
throw new ApiError(500, sprintf("'shortName' attribute of resource class '%s' must not contain '.' or ',' characters: '%s'", $resourceClass, $uniqueName));
}
return $uniqueName;
}
}
......@@ -4,11 +4,9 @@ declare(strict_types=1);
namespace Dbp\Relay\CoreBundle\LocalData;
use ApiPlatform\Core\Exception\ResourceClassNotFoundException;
use ApiPlatform\Core\Metadata\Resource\Factory\AnnotationResourceMetadataFactory;
use Dbp\Relay\CoreBundle\Exception\ApiError;
use Dbp\Relay\CoreBundle\Helpers\ApiPlatformHelperFunctions;
use Dbp\Relay\CoreBundle\Helpers\Tools;
use Doctrine\Common\Annotations\AnnotationReader;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Contracts\EventDispatcher\Event;
......@@ -111,21 +109,7 @@ class LocalDataEventDispatcher
*/
public static function getUniqueEntityName(string $resourceClass): string
{
$resourceMetadataFactory = new AnnotationResourceMetadataFactory(new AnnotationReader());
try {
$resourceMetadata = $resourceMetadataFactory->create($resourceClass);
} catch (ResourceClassNotFoundException $exc) {
throw new ApiError(500, $exc->getMessage());
}
$uniqueName = $resourceMetadata->getShortName() ?? '';
if (Tools::isNullOrEmpty($uniqueName)) {
throw new ApiError(500, sprintf("'shortName' attribute missing in ApiResource annotation of resource class '%s'", $resourceClass));
} elseif (str_contains($uniqueName, '.') || str_contains($uniqueName, ',')) {
throw new ApiError(500, sprintf("'shortName' attribute of resource class '%s' must not contain '.' or ',' characters: '%s'", $resourceClass, $uniqueName));
}
return $uniqueName;
return ApiPlatformHelperFunctions::getShortNameForResource($resourceClass);
}
/**
......
......@@ -55,6 +55,11 @@ final class LoggingProcessor
$request->attributes->set($requestAttributeKey, $requestId);
}
$record['context']['relay-request-id'] = $requestId;
$route = $request->attributes->get('_route');
if ($route !== null) {
$record['context']['relay-route'] = $route;
}
}
return $record;
......
<?php
declare(strict_types=1);
namespace Dbp\Relay\CoreBundle\Tests\Authorization;
use Dbp\Relay\CoreBundle\Authorization\AuthorizationDataMuxer;
use Dbp\Relay\CoreBundle\Authorization\AuthorizationDataProviderProvider;
use Dbp\Relay\CoreBundle\Authorization\Event\GetAttributeEvent;
use Dbp\Relay\CoreBundle\Authorization\Event\GetAvailableAttributesEvent;
use PHPUnit\Framework\TestCase;
use Symfony\Component\EventDispatcher\EventDispatcher;
class AuthorizationDataMuxerTest extends TestCase
{
public function testBasics()
{
$dummy = new DummyAuthorizationDataProvider(['foo' => 42], ['foo', 'bar']);
$mux = new AuthorizationDataMuxer(new AuthorizationDataProviderProvider([$dummy]), new EventDispatcher());
$this->assertSame(['foo', 'bar'], $mux->getAvailableAttributes());
$this->assertSame(42, $mux->getAttribute(null, 'foo'));
$this->assertSame(24, $mux->getAttribute(null, 'bar', 24));
}
public function testMultiple()
{
$dummy = new DummyAuthorizationDataProvider(['foo' => 42], ['foo', 'qux']);
$dummy2 = new DummyAuthorizationDataProvider(['bar' => 24], ['bar', 'baz']);
$mux = new AuthorizationDataMuxer(new AuthorizationDataProviderProvider([$dummy, $dummy2]), new EventDispatcher());
$this->assertSame(['foo', 'qux', 'bar', 'baz'], $mux->getAvailableAttributes());
$this->assertSame(42, $mux->getAttribute(null, 'foo'));
$this->assertSame('default', $mux->getAttribute(null, 'qux', 'default'));
$this->assertSame(24, $mux->getAttribute(null, 'bar'));
$this->assertSame(12, $mux->getAttribute(null, 'baz', 12));
$this->assertNull($mux->getAttribute(null, 'baz'));
}
public function testAvailEvent()
{
$dummy = new DummyAuthorizationDataProvider(['foo' => 42], ['foo', 'bar']);
$dispatched = new EventDispatcher();
$getAvail = function (GetAvailableAttributesEvent $event) {
$this->assertSame(['foo', 'bar'], $event->getAttributes());
$event->addAttributes(['new']);
};
$dispatched->addListener(GetAvailableAttributesEvent::class, $getAvail);
$getAvail2 = function (GetAvailableAttributesEvent $event) {
$event->addAttributes(['new2']);
};
$dispatched->addListener(GetAvailableAttributesEvent::class, $getAvail2);
$mux = new AuthorizationDataMuxer(new AuthorizationDataProviderProvider([$dummy]), $dispatched);
$this->assertSame(['foo', 'bar', 'new', 'new2'], $mux->getAvailableAttributes());
}
public function testGetAttrEvent()
{
$dummy = new DummyAuthorizationDataProvider(['foo' => 42], ['foo', 'bar']);
$dispatched = new EventDispatcher();
$getAttr = function (GetAttributeEvent $event) {
$this->assertSame('myuser', $event->getUserIdentifier());
$this->assertSame('bar', $event->getAttributeName());
$this->assertNull($event->getAttributeValue());
$event->setAttributeValue('OK');
};
$dispatched->addListener(GetAttributeEvent::class, $getAttr);
$mux = new AuthorizationDataMuxer(new AuthorizationDataProviderProvider([$dummy]), $dispatched);
$this->assertSame('OK', $mux->getAttribute('myuser', 'bar'));
}
public function testGetAttrEventDefault()
{
$dummy = new DummyAuthorizationDataProvider([], []);
$dispatched = new EventDispatcher();
$getAvail = function (GetAvailableAttributesEvent $event) {
$event->addAttributes(['bar']);
};
$dispatched->addListener(GetAvailableAttributesEvent::class, $getAvail);
$getAttr = function (GetAttributeEvent $event) {
$this->assertNull($event->getAttributeValue());
};
$dispatched->addListener(GetAttributeEvent::class, $getAttr);
$mux = new AuthorizationDataMuxer(new AuthorizationDataProviderProvider([$dummy]), $dispatched);
$this->assertSame('Default', $mux->getAttribute('myuser', 'bar', 'Default'));
}
public function testGetAttrMultipleEvents()
{
$dummy = new DummyAuthorizationDataProvider(['foo' => 42], ['foo', 'bar']);
$dispatched = new EventDispatcher();
$getAttr = function (GetAttributeEvent $event) {
$event->setAttributeValue('OK');
};
$dispatched->addListener(GetAttributeEvent::class, $getAttr);
$getAttr2 = function (GetAttributeEvent $event) {
$this->assertSame('OK', $event->getAttributeValue());
$event->setAttributeValue('OK2');
};
$dispatched->addListener(GetAttributeEvent::class, $getAttr2);
$mux = new AuthorizationDataMuxer(new AuthorizationDataProviderProvider([$dummy]), $dispatched);
$this->assertSame('OK2', $mux->getAttribute('myuser', 'bar'));
}
}
<?php
declare(strict_types=1);
namespace Dbp\Relay\CoreBundle\Tests\Authorization;
use Dbp\Relay\CoreBundle\Authorization\AuthorizationDataProviderInterface;
class DummyAuthorizationDataProvider implements AuthorizationDataProviderInterface
{
/**
* @var array
*/
private $attributes;
/**
* @var array
*/
private $available;
public function __construct(array $attributes, array $available = null)
{
$this->attributes = $attributes;
$this->available = $available ?? array_keys($attributes);
}
/**
* @return string[]
*/
public function getAvailableAttributes(): array
{
return $this->available;
}
public function getUserAttributes(?string $userIdentifier): array
{
return $this->attributes;
}
}
<?php
declare(strict_types=1);
namespace Dbp\Relay\CoreBundle\Tests;
use Dbp\Relay\CoreBundle\ExpressionLanguage\ExpressionLanguage;
use PHPUnit\Framework\TestCase;
class ExpressionLanguageTest extends TestCase
{
public function testBasics()
{
$lang = new ExpressionLanguage();
$this->assertTrue($lang->evaluate('true'));
$this->assertFalse($lang->evaluate('false'));
}
public function testFilter()
{
$lang = new ExpressionLanguage();
$this->assertSame([], $lang->evaluate('filter([], "true")'));
$this->assertSame([], $lang->evaluate('filter([1, 5, 2, 4], "false")'));
$this->assertSame([1, 5, 2, 4], $lang->evaluate('filter([1, 5, 2, 4], "true")'));
$this->assertSame([1, 5, 2, 4], $lang->evaluate('filter([1, 5, 2, 4], "42")'));
$this->assertSame([5, 4], $lang->evaluate('filter([1, 5, 2, 4], "value > 2")'));
$this->assertSame([2, 4], $lang->evaluate('filter({1: 2, 3: 4}, "true")'));
}
public function testMap()
{
$lang = new ExpressionLanguage();
$this->assertSame([], $lang->evaluate('map([], "true")'));
$this->assertSame([false], $lang->evaluate('map([1], "false")'));
$this->assertSame([2, 6, 3, 5], $lang->evaluate('map([1, 5, 2, 4], "value + 1")'));
$this->assertSame([1 => 3, 3 => 7], $lang->evaluate('map({1: 2, 3: 4}, "key + value")'));
$this->assertSame([1 => 42, 3 => 42], $lang->evaluate('map({1: 2, 3: 4}, "42")'));
}
public function testEmpty()
{
$lang = new ExpressionLanguage();
$this->assertTrue($lang->evaluate('empty([])'));
$this->assertTrue($lang->evaluate('empty(0)'));
$this->assertTrue($lang->evaluate('empty("0")'));
$this->assertFalse($lang->evaluate('empty(42)'));
$this->assertFalse($lang->evaluate('empty([42])'));
}
public function testPhp()
{
$lang = new ExpressionLanguage();
$this->assertSame(2, $lang->evaluate('count([1, 2])'));
$this->assertSame('1-2', $lang->evaluate('implode("-", ["1", "2"])'));
$this->assertSame(['1', '2'], $lang->evaluate('explode("-", "1-2")'));
}
public function testNumeric()
{
$lang = new ExpressionLanguage();
$this->assertSame(2.0, $lang->evaluate('ceil(1.2)'));
$this->assertSame(1.0, $lang->evaluate('floor(1.9)'));
$this->assertSame(1.0, $lang->evaluate('round(0.5)'));
$this->assertSame(42, $lang->evaluate('max([2, 42])'));
$this->assertSame(2, $lang->evaluate('min([2, 42])'));
}
public function testString()
{
$lang = new ExpressionLanguage();
$this->assertTrue($lang->evaluate('str_starts_with("foo", "fo")'));
$this->assertFalse($lang->evaluate('str_starts_with("foo", "xo")'));
$this->assertTrue($lang->evaluate('str_ends_with("foo", "oo")'));
$this->assertFalse($lang->evaluate('str_ends_with("foo", "of")'));
$this->assertSame('foo', $lang->evaluate('substr("foobar", 0, 3)'));
$this->assertSame(1, $lang->evaluate('strpos("foobar", "oo")'));
$this->assertSame(6, $lang->evaluate('strlen("foobar")'));
}
}
......@@ -42,6 +42,18 @@ class LoggingProcessorTest extends WebTestCase
$this->assertSame(['message' => 'foobar', 'context' => ['relay-session-id' => 'logging-id']], $record);
}
public function testRoute()
{
$stack = new RequestStack();
$request = new Request();
$request->attributes->set('_route', 'some_route');
$stack->push($request);
$processor = new LoggingProcessor(new TestUserSession('log'), $stack);
$record = ['message' => 'foobar'];
$record = $processor->__invoke($record);
$this->assertSame('some_route', $record['context']['relay-route']);
}
public function testMaskUserId()
{
$processor = new LoggingProcessor(new TestUserSession('some-random-user-id'), new RequestStack());
......