Skip to content

Commit

Permalink
check that declared mapper is compatible with parameter type
Browse files Browse the repository at this point in the history
  • Loading branch information
JanTvrdik committed Aug 7, 2023
1 parent 97e182f commit dbac53c
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 0 deletions.
20 changes: 20 additions & 0 deletions src/Compiler/Exception/CannotCreateMapperCompilerException.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use LogicException;
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
use ReflectionParameter;
use ShipMonk\InputMapper\Compiler\Mapper\MapperCompiler;
use ShipMonk\InputMapper\Compiler\Validator\ValidatorCompiler;
use Throwable;
Expand All @@ -17,6 +18,25 @@ public static function fromType(TypeNode $type, ?string $reason = null, ?Throwab
return new self("Cannot create mapper for type {$type}{$reason}", 0, $previous);
}

public static function withIncompatibleMapperForMethodParameter(
MapperCompiler $mapperCompiler,
ReflectionParameter $parameter,
TypeNode $parameterType,
?Throwable $previous = null
): self
{
$mapperCompilerClass = $mapperCompiler::class;
$mapperOutputType = $mapperCompiler->getOutputType();

$parameterName = $parameter->getName();
$className = $parameter->getDeclaringClass()?->getName();
$methodName = $parameter->getDeclaringFunction()->getName();
$methodFullName = $className !== null ? "{$className}::{$methodName}" : $methodName;

$reason = "mapper output type '{$mapperOutputType}' is not compatible with parameter type '{$parameterType}'";
return new self("Cannot use mapper {$mapperCompilerClass} for parameter \${$parameterName} of method {$methodFullName}, because {$reason}", 0, $previous);
}

public static function withIncompatibleValidator(
ValidatorCompiler $validatorCompiler,
MapperCompiler $mapperCompiler,
Expand Down
4 changes: 4 additions & 0 deletions src/Compiler/MapperFactory/DefaultMapperCompilerFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,10 @@ protected function createParameterMapperCompiler(
default => new ChainMapperCompiler($mappers),
};

if (!PhpDocTypeUtils::isSubTypeOf($mapper->getOutputType(), $type)) {
throw CannotCreateMapperCompilerException::withIncompatibleMapperForMethodParameter($mapper, $parameterReflection, $type);
}

foreach ($validators as $validator) {
$mapper = $this->addValidator($mapper, $validator);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php declare(strict_types = 1);

namespace ShipMonkTests\InputMapper\Compiler\MapperFactory\Data;

use ShipMonk\InputMapper\Compiler\Mapper\Scalar\MapString;

class InputWithIncompatibleMapperCompiler
{

public function __construct(
#[MapString]
public readonly int $id,
)
{
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
use ShipMonkTests\InputMapper\Compiler\MapperFactory\Data\CarInputWithVarTags;
use ShipMonkTests\InputMapper\Compiler\MapperFactory\Data\ColorEnum;
use ShipMonkTests\InputMapper\Compiler\MapperFactory\Data\InputWithDate;
use ShipMonkTests\InputMapper\Compiler\MapperFactory\Data\InputWithIncompatibleMapperCompiler;
use ShipMonkTests\InputMapper\Compiler\MapperFactory\Data\InputWithoutConstructor;
use ShipMonkTests\InputMapper\Compiler\MapperFactory\Data\InputWithPrivateConstructor;
use ShipMonkTests\InputMapper\InputMapperTestCase;
Expand Down Expand Up @@ -308,6 +309,12 @@ public static function provideCreateErrorData(): iterable
'Cannot create mapper for type ShipMonkTests\InputMapper\Compiler\MapperFactory\Data\InputWithPrivateConstructor, because class has a non-public constructor',
];

yield 'InputWithIncompatibleMapperCompiler' => [
InputWithIncompatibleMapperCompiler::class,
[],
'Cannot use mapper ShipMonk\InputMapper\Compiler\Mapper\Scalar\MapString for parameter $id of method ShipMonkTests\InputMapper\Compiler\MapperFactory\Data\InputWithIncompatibleMapperCompiler::__construct, because mapper output type \'string\' is not compatible with parameter type \'int\'',
];

yield 'DateTime' => [
DateTime::class,
[DefaultMapperCompilerFactory::DELEGATE_OBJECT_MAPPING => false],
Expand Down

0 comments on commit dbac53c

Please sign in to comment.