Skip to content

Commit 8c7997b

Browse files
authored
Throw when if expression returns non-boolean (#105)
1 parent 49f8d76 commit 8c7997b

3 files changed

Lines changed: 68 additions & 2 deletions

File tree

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Sofascore\PurgatoryBundle\Exception;
6+
7+
final class InvalidIfExpressionResultException extends \TypeError implements PurgatoryException
8+
{
9+
private const MESSAGE = 'Expected return value of "if" expression (%s) to be boolean, got %s.';
10+
11+
public function __construct(
12+
public readonly string $expression,
13+
public readonly mixed $result,
14+
) {
15+
parent::__construct(\sprintf(self::MESSAGE, $expression, get_debug_type($result)));
16+
}
17+
}

src/RouteProvider/AbstractEntityRouteProvider.php

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use Sofascore\PurgatoryBundle\Cache\Configuration\Configuration;
99
use Sofascore\PurgatoryBundle\Cache\Configuration\ConfigurationLoaderInterface;
1010
use Sofascore\PurgatoryBundle\Cache\Configuration\Subscriptions;
11+
use Sofascore\PurgatoryBundle\Exception\InvalidIfExpressionResultException;
1112
use Sofascore\PurgatoryBundle\Exception\LogicException;
1213
use Sofascore\PurgatoryBundle\Listener\Enum\Action;
1314
use Sofascore\PurgatoryBundle\RouteParamValueResolver\ValuesResolverInterface;
@@ -71,8 +72,15 @@ private function processValidSubscriptions(Subscriptions $subscriptions, array $
7172
continue;
7273
}
7374

74-
if (isset($subscription['if']) && false === $this->getExpressionLanguage()->evaluate($subscription['if'], ['obj' => $entity])) {
75-
continue;
75+
if (isset($subscription['if'])) {
76+
$result = $this->getExpressionLanguage()->evaluate($subscription['if'], ['obj' => $entity]);
77+
if (!\is_bool($result)) {
78+
throw new InvalidIfExpressionResultException($subscription['if'], $result);
79+
}
80+
81+
if (!$result) {
82+
continue;
83+
}
7684
}
7785

7886
$routeParamConfigs = $subscription['routeParams'] ?? [];

tests/RouteProvider/UpdatedEntityRouteProviderTest.php

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,16 @@
66

77
use PHPUnit\Framework\Attributes\CoversClass;
88
use PHPUnit\Framework\Attributes\RequiresMethod;
9+
use PHPUnit\Framework\Attributes\TestWith;
910
use PHPUnit\Framework\TestCase;
11+
use Psr\Container\ContainerInterface;
1012
use Sofascore\PurgatoryBundle\Attribute\RouteParamValue\CompoundValues;
1113
use Sofascore\PurgatoryBundle\Attribute\RouteParamValue\EnumValues;
1214
use Sofascore\PurgatoryBundle\Attribute\RouteParamValue\PropertyValues;
1315
use Sofascore\PurgatoryBundle\Attribute\RouteParamValue\RawValues;
1416
use Sofascore\PurgatoryBundle\Cache\Configuration\Configuration;
1517
use Sofascore\PurgatoryBundle\Cache\Configuration\ConfigurationLoaderInterface;
18+
use Sofascore\PurgatoryBundle\Exception\InvalidIfExpressionResultException;
1619
use Sofascore\PurgatoryBundle\Exception\LogicException;
1720
use Sofascore\PurgatoryBundle\Listener\Enum\Action;
1821
use Sofascore\PurgatoryBundle\RouteParamValueResolver\CompoundValuesResolver;
@@ -27,6 +30,7 @@
2730
use Symfony\Component\DependencyInjection\ServiceLocator;
2831
use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
2932
use Symfony\Component\PropertyAccess\PropertyAccess;
33+
use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
3034
use Symfony\Component\PropertyAccess\PropertyPath;
3135

3236
#[CoversClass(AbstractEntityRouteProvider::class)]
@@ -361,6 +365,43 @@ public function testRouteParamsWithRawValuesAndEnumValues(): void
361365
self::assertSame(['name' => 'foo_route', 'params' => ['foo' => 'case3']], (array) $routes[5]);
362366
}
363367

368+
#[TestWith([null, 'Expected return value of "if" expression (obj.val) to be boolean, got null.'])]
369+
#[TestWith([1, 'Expected return value of "if" expression (obj.val) to be boolean, got int.'])]
370+
#[TestWith([0.0, 'Expected return value of "if" expression (obj.val) to be boolean, got float.'])]
371+
#[TestWith(['false', 'Expected return value of "if" expression (obj.val) to be boolean, got string.'])]
372+
#[TestWith([[true], 'Expected return value of "if" expression (obj.val) to be boolean, got array.'])]
373+
#[TestWith([new \stdClass(), 'Expected return value of "if" expression (obj.val) to be boolean, got stdClass.'])]
374+
public function testExceptionIsThrownOnInvalidIfReturnType(mixed $ifResult, string $expectedMessage): void
375+
{
376+
$configurationLoader = $this->createMock(ConfigurationLoaderInterface::class);
377+
$configurationLoader->expects(self::once())
378+
->method('load')
379+
->willReturn(new Configuration([
380+
'stdClass' => [
381+
[
382+
'routeName' => 'foo_route',
383+
'if' => 'obj.val',
384+
],
385+
],
386+
]));
387+
388+
$expressionLanguage = $this->createMock(ExpressionLanguage::class);
389+
$expressionLanguage->expects(self::once())
390+
->method('evaluate')
391+
->willReturn($ifResult);
392+
393+
$routeProvider = new UpdatedEntityRouteProvider(
394+
configurationLoader: $configurationLoader,
395+
expressionLanguage: $expressionLanguage,
396+
routeParamValueResolverLocator: $this->createMock(ContainerInterface::class),
397+
propertyAccessor: $this->createMock(PropertyAccessorInterface::class),
398+
);
399+
400+
$this->expectException(InvalidIfExpressionResultException::class);
401+
$this->expectExceptionMessage($expectedMessage);
402+
[...$routeProvider->provideRoutesFor(Action::Update, new \stdClass(), [])];
403+
}
404+
364405
private function createRouteProvider(array $configuration, bool $withExpressionLang): UpdatedEntityRouteProvider
365406
{
366407
$configurationLoader = $this->createMock(ConfigurationLoaderInterface::class);

0 commit comments

Comments
 (0)