Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Check mapper compatibility with target type #20

Merged
merged 1 commit into from
Aug 7, 2023
Merged
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
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
Loading