Skip to content

Commit b1b4620

Browse files
committed
[RequestMapper]: Added type extractors, remove unused code
1 parent 6e42c7c commit b1b4620

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+270
-215
lines changed

.github/workflows/ci.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -61,4 +61,4 @@ jobs:
6161
run: mkdir -p var/tests
6262

6363
- name: Unit Tests
64-
run: ./vendor/bin/phpunit --colors=always --configuration phpunit.xml.dist --log-junit var/tests/.phpunit.output.xml
64+
run: ./vendor/bin/phpunit --colors=always --configuration phpunit.xml.dist

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
.phpunit
1818
.phpunit.result.cache
1919
/phpunit.xml
20+
/.phpunit.cache
2021
bin/phpunit
2122
###< symfony/phpunit-bridge ###
2223

.scrutinizer.yml

+3-5
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,10 @@ build:
77
coverage:
88
tests:
99
override:
10-
- command: mkdir -p var/tests/coverage && php -n -dzend_extension=xdebug -dxdebug.mode=coverage vendor/bin/phpunit --colors=always --configuration phpunit.xml.dist --log-junit var/tests/.phpunit.output.xml --coverage-clover var/tests/coverage/coverage.xml
11-
coverage:
12-
file: var/tests/coverage/coverage.xml
13-
format: clover
10+
- command: composer test
11+
1412
environment:
15-
php: 8.1
13+
php: 8.1.9
1614

1715
filter:
1816
excluded_paths:

.travis.yml

-17
This file was deleted.

Attribute/ParamConverter.php

-15
This file was deleted.

CHANGELOG.md

-20
This file was deleted.

Event/ListenerExceptionEvent.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
use FRZB\Component\RequestMapper\Data\ErrorContract;
88
use Symfony\Contracts\EventDispatcher\Event;
99

10-
final class ListenerExceptionEvent extends Event
10+
class ListenerExceptionEvent extends Event
1111
{
1212
public function __construct(
1313
private readonly Event $event,

EventListener/ExceptionListener.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface as EventDispatcher;
1414

1515
#[AsEventListener(event: KernelEvents::EXCEPTION, method: 'onKernelException', priority: 20)]
16-
final class ExceptionListener
16+
class ExceptionListener
1717
{
1818
private const ALLOWED_CONTENT_TYPE = 'application/json';
1919

EventListener/JsonRequestListener.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface as EventDispatcher;
1717

1818
#[AsEventListener(event: KernelEvents::REQUEST, method: 'onKernelRequest', priority: 20)]
19-
final class JsonRequestListener
19+
class JsonRequestListener
2020
{
2121
private const ALLOWED_CONTENT_TYPES = ['application/json'];
2222

EventListener/MergeRequestListener.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
use Symfony\Component\HttpKernel\KernelEvents;
1111

1212
#[AsEventListener(event: KernelEvents::REQUEST, method: 'onKernelRequest', priority: 10)]
13-
final class MergeRequestListener
13+
class MergeRequestListener
1414
{
1515
private const ROUTE_PARAMS_KEY = '_route_params';
1616

EventListener/RequestMapperListener.php

+10-10
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,17 @@
77
use FRZB\Component\RequestMapper\Attribute\RequestBody;
88
use FRZB\Component\RequestMapper\Data\HasHeaders;
99
use FRZB\Component\RequestMapper\Helper\HeaderHelper;
10-
use FRZB\Component\RequestMapper\Helper\ParamConverterHelper;
11-
use FRZB\Component\RequestMapper\RequestMapper\RequestMapperInterface as Converter;
10+
use FRZB\Component\RequestMapper\Helper\RequestBodyHelper;
11+
use FRZB\Component\RequestMapper\RequestMapper\RequestMapperInterface as RequestMapper;
1212
use Symfony\Component\EventDispatcher\Attribute\AsEventListener;
1313
use Symfony\Component\HttpKernel\Event\ControllerEvent;
1414
use Symfony\Component\HttpKernel\KernelEvents;
1515

1616
#[AsEventListener(event: KernelEvents::CONTROLLER, method: 'onKernelController', priority: -255)]
17-
final class RequestMapperListener
17+
class RequestMapperListener
1818
{
1919
public function __construct(
20-
private readonly Converter $converter,
20+
private readonly RequestMapper $mapper,
2121
) {
2222
}
2323

@@ -30,14 +30,14 @@ public function onKernelController(ControllerEvent $event): void
3030

3131
foreach ($method->getParameters() as $parameter) {
3232
$parameterType = (string) $parameter->getType();
33-
$attribute = ParamConverterHelper::getAttribute($parameter, $attributes);
34-
$isNativeRequest = is_a($request, $parameterType) || is_subclass_of($request, $parameterType);
33+
$attribute = RequestBodyHelper::getAttribute($parameter, $attributes);
34+
$isNativeRequest = $request instanceof $parameterType;
3535

3636
if (!$attribute || $isNativeRequest) {
3737
continue;
3838
}
3939

40-
$object = $this->converter->convert($request, $attribute);
40+
$object = $this->mapper->map($request, $attribute);
4141

4242
if ($object instanceof HasHeaders) {
4343
$object->setHeaders(HeaderHelper::getHeaders($request));
@@ -48,10 +48,10 @@ public function onKernelController(ControllerEvent $event): void
4848
}
4949

5050
/** @throws \ReflectionException */
51-
private function getReflectionMethod(mixed $controller): \ReflectionMethod|\ReflectionFunction
51+
private function getReflectionMethod(array|object|callable $controller): \ReflectionMethod|\ReflectionFunction
5252
{
5353
return match (true) {
54-
\is_array($controller) => new \ReflectionMethod(/** @scrutinizer ignore-type */ ...$controller),
54+
\is_array($controller) => new \ReflectionMethod(...$controller),
5555
\is_object($controller) && \is_callable($controller) => new \ReflectionMethod($controller, '__invoke'),
5656
default => new \ReflectionFunction($controller),
5757
};
@@ -60,7 +60,7 @@ private function getReflectionMethod(mixed $controller): \ReflectionMethod|\Refl
6060
/** @return array<RequestBody> */
6161
private function getAttributes(\ReflectionMethod|\ReflectionFunction $method): array
6262
{
63-
return ParamConverterHelper::fromReflectionAttributes(
63+
return RequestBodyHelper::fromReflectionAttributes(
6464
...$method->getAttributes(RequestBody::class, \ReflectionAttribute::IS_INSTANCEOF)
6565
);
6666
}

Exception/ExceptionMapperLocatorException.php

+3-3
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,12 @@
1010
#[Immutable]
1111
final class ExceptionMapperLocatorException extends \DomainException
1212
{
13-
private const NO_MAPPER_FOUND_MESSAGE = 'No mapper found for exception "%s"';
13+
private const NOT_FOUND_MESSAGE = 'No mapper found for exception "%s"';
1414

1515
#[Pure(true)]
16-
public static function noMapperFound(\Throwable $previous, bool $wrapCallable = true): callable|self
16+
public static function notFound(\Throwable $previous, bool $wrapCallable = true): callable|self
1717
{
18-
$message = sprintf(self::NO_MAPPER_FOUND_MESSAGE, $previous::class);
18+
$message = sprintf(self::NOT_FOUND_MESSAGE, $previous::class);
1919
$exception = new self($message, previous: $previous);
2020

2121
return $wrapCallable ? static fn () => throw $exception : $exception;

Exception/PropertyMapperLocatorException.php

+3-3
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,13 @@
99
#[Immutable]
1010
final class PropertyMapperLocatorException extends \LogicException
1111
{
12-
private const DEFAULT_NO_MAPPER_FOUND_MESSAGE = 'Mapper not found for %s::%s';
12+
private const NOT_FOUND_MESSAGE = 'Mapper not found for %s::%s';
1313

14-
public static function throwMapperNotFound(\ReflectionProperty $property, bool $wrapCallable = true, ?\Throwable $previous = null): callable|self
14+
public static function notFound(\ReflectionProperty $property, bool $wrapCallable = true, ?\Throwable $previous = null): callable|self
1515
{
1616
$className = $property->getDeclaringClass()->getName();
1717
$propertyName = $property->getName();
18-
$message = sprintf(self::DEFAULT_NO_MAPPER_FOUND_MESSAGE, $className, $propertyName);
18+
$message = sprintf(self::NOT_FOUND_MESSAGE, $className, $propertyName);
1919
$exception = new self($message, previous: $previous);
2020

2121
return $wrapCallable ? static fn () => throw $exception : throw $exception;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace FRZB\Component\RequestMapper\Exception;
6+
7+
class TypeExtractorLocatorException extends \LogicException
8+
{
9+
private const NOT_FOUND_MESSAGE = 'Type extractor not found for "%s:%s"';
10+
11+
public static function notFound(\ReflectionProperty|\ReflectionParameter $target, bool $wrapCallable = true, ?\Throwable $previous = null): callable|self
12+
{
13+
$message = sprintf(self::NOT_FOUND_MESSAGE, $target->getDeclaringClass()->getName(), $target->getName());
14+
$exception = new self($message, previous: $previous);
15+
16+
return $wrapCallable ? static fn () => throw $exception : $exception;
17+
}
18+
}

ExceptionMapper/ExceptionMapperLocator.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ public function get(\Throwable $exception): ExceptionMapper
2525
{
2626
return $this->mappers
2727
->get($exception::class)
28-
->getOrThrow(ExceptionMapperLocatorException::noMapperFound($exception))
28+
->getOrThrow(ExceptionMapperLocatorException::notFound($exception))
2929
;
3030
}
3131
}

Extractor/ConstraintExtractor.php

+9-4
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,22 @@
99
use FRZB\Component\RequestMapper\Helper\ClassHelper;
1010
use FRZB\Component\RequestMapper\Helper\ConstraintsHelper;
1111
use FRZB\Component\RequestMapper\Helper\PropertyHelper;
12+
use FRZB\Component\RequestMapper\TypeExtractor\TypeExtractorLocatorInterface as TypeExtractorLocator;
1213
use Symfony\Component\Validator\Constraints\All;
1314
use Symfony\Component\Validator\Constraints\Collection;
1415

1516
#[AsService]
1617
class ConstraintExtractor
1718
{
18-
public function extract(string $className, array $parameters = []): ?Collection
19+
public function __construct(
20+
private readonly TypeExtractorLocator $extractorLocator,
21+
) {
22+
}
23+
24+
public function extract(string $className, array $payload = []): ?Collection
1925
{
2026
try {
21-
return ConstraintsHelper::createCollection($this->extractConstraints($className, $parameters));
27+
return ConstraintsHelper::createCollection($this->extractConstraints($className, $payload));
2228
} catch (\ReflectionException) {
2329
return null;
2430
}
@@ -38,10 +44,9 @@ public function extractConstraints(string $className, array $parameters = []): a
3844
$propertyName = PropertyHelper::getName($property);
3945
$propertyValue = $parameters[$propertyName] ?? [];
4046
$propertyTypeName = PropertyHelper::getTypeName($property);
41-
$arrayTypeName = ConstraintsHelper::getArrayTypeAttribute($property)?->typeName;
4247

4348
$constraints[$propertyName] = match (true) {
44-
ConstraintsHelper::hasArrayTypeAttribute($property) => ArrayList::collect($propertyValue)->map(fn () => new All($this->extract($arrayTypeName, $propertyValue)))->toArray(),
49+
$this->extractorLocator->has($property) => ArrayList::collect($propertyValue)->map(fn () => new All($this->extract($this->extractorLocator->get($property)->extract($property), $propertyValue)))->toArray(),
4550
ClassHelper::isNotBuiltinAndExists($propertyTypeName) => $this->extract($propertyTypeName, $propertyValue),
4651
default => ConstraintsHelper::fromProperty($property),
4752
};

Extractor/DiscriminatorMapExtractor.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,12 @@
1313
class DiscriminatorMapExtractor
1414
{
1515
/** @throws ClassExtractorException */
16-
public function extract(string $className, array $parameters): string
16+
public function extract(string $className, array $payload): string
1717
{
1818
if ($discriminatorMap = ClassHelper::getAttribute($className, DiscriminatorMap::class)) {
1919
$property = $discriminatorMap->getTypeProperty();
2020
$mapping = $discriminatorMap->getMapping();
21-
$parameter = $parameters[$property] ?? throw ClassExtractorException::fromDiscriminatorMapWhenParameterIsNull($discriminatorMap);
21+
$parameter = $payload[$property] ?? throw ClassExtractorException::fromDiscriminatorMapWhenParameterIsNull($discriminatorMap);
2222
$className = $mapping[$parameter] ?? throw ClassExtractorException::fromDiscriminatorMapWhenParameterInvalid($discriminatorMap);
2323
}
2424

Extractor/ParametersExtractor.php

+4-5
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@ public function __construct(
1717
) {
1818
}
1919

20-
public function extract(string $class, array $parameters): array
20+
public function extract(string $className, array $payload): array
2121
{
22-
return [...$parameters, ...$this->mapProperties($this->classMapper->map($class, $parameters), $parameters)];
22+
return [...$payload, ...$this->mapProperties($this->classMapper->map($className, $payload), $payload)];
2323
}
2424

2525
private function mapProperties(array $properties, array $parameters): array
@@ -33,7 +33,6 @@ private function mapProperties(array $properties, array $parameters): array
3333
\is_array($propertyType) => array_map(fn (array $parameters) => $this->extract(current($propertyType), $parameters), $propertyValue ?? []),
3434
ClassHelper::isNotBuiltinAndExists($propertyType) => $this->extract($propertyType, $propertyValue ?? []),
3535
ClassHelper::isEnum($propertyType) => $this->mapEnum($propertyType, $propertyValue) ?? $propertyValue,
36-
!ClassHelper::isNotBuiltinAndExists($propertyType) => $propertyValue,
3736
default => $propertyValue,
3837
};
3938
}
@@ -45,8 +44,8 @@ private function mapProperties(array $properties, array $parameters): array
4544
private function mapEnum(string $enumClassName, mixed $value = null): ?\BackedEnum
4645
{
4746
return match (true) {
48-
is_subclass_of($enumClassName, \IntBackedEnum::class) && \is_int($value) && !empty($value) => $enumClassName::tryFrom($value),
49-
is_subclass_of($enumClassName, \StringBackedEnum::class) && \is_string($value) && !empty($value) => $enumClassName::tryFrom($value),
47+
is_subclass_of($enumClassName, \IntBackedEnum::class) && \is_int($value) => $enumClassName::tryFrom($value),
48+
is_subclass_of($enumClassName, \StringBackedEnum::class) && \is_string($value) => $enumClassName::tryFrom($value),
5049
default => null,
5150
};
5251
}

Helper/ConstraintsHelper.php

-17
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@
44

55
namespace FRZB\Component\RequestMapper\Helper;
66

7-
use FRZB\Component\PhpDocReader\Reader\ReaderInterface as PhpDocReader;
8-
use FRZB\Component\RequestMapper\Attribute\ArrayType;
97
use JetBrains\PhpStorm\Immutable;
108
use Symfony\Component\Validator\Constraint;
119
use Symfony\Component\Validator\Constraints\Collection;
@@ -28,19 +26,4 @@ public static function fromProperty(\ReflectionProperty $rProperty): array
2826
{
2927
return AttributeHelper::getAttributes($rProperty, Constraint::class);
3028
}
31-
32-
public static function getArrayTypeAttribute(\ReflectionProperty $rProperty): ?ArrayType
33-
{
34-
return AttributeHelper::getAttribute($rProperty, ArrayType::class);
35-
}
36-
37-
public static function hasArrayTypeAttribute(\ReflectionProperty $rProperty): bool
38-
{
39-
return 'array' === PropertyHelper::getTypeName($rProperty) && null !== AttributeHelper::getAttribute($rProperty, ArrayType::class);
40-
}
41-
42-
public static function hasArrayDocBlock(\ReflectionProperty $rProperty, PhpDocReader $reader): bool
43-
{
44-
return 'array' === PropertyHelper::getTypeName($rProperty) && null !== $reader->getPropertyClass($rProperty);
45-
}
4629
}

0 commit comments

Comments
 (0)