diff --git a/src/AutoMapper.php b/src/AutoMapper.php index e627170..091369f 100644 --- a/src/AutoMapper.php +++ b/src/AutoMapper.php @@ -119,6 +119,10 @@ private function mapType(MapInterface $map, mixed $srcValue, mixed $destValue, M } foreach ($this->membersFor($map) as $member) { + if ($member->isIgnored()) { + continue; + } + [$sourcePropertyValue, $ok] = $this->memberSourceValueFor($map, $member, $srcValue, $ctx); if (!$ok) { $this->logger->warning('Cannot access source property.', [ @@ -260,10 +264,6 @@ private function handleMapping(Type $destPropertyInfoType, mixed $value, Mapping private function memberDestinationValuePut(MemberInterface $member, object $dest, mixed $value, MappingContext $ctx): void { - if ($member->isIgnored()) { - return; - } - // @phpstan-ignore-next-line if (method_exists($this->propertyInfoExtractor, 'getType')) { $type = $this->propertyInfoExtractor->getType(get_class($dest), $member->getDestinationProperty()); diff --git a/tests/Functional/MapTest.php b/tests/Functional/MapTest.php index a401e11..f6c70b3 100644 --- a/tests/Functional/MapTest.php +++ b/tests/Functional/MapTest.php @@ -19,6 +19,7 @@ use Backbrain\Automapper\Tests\Fixtures\ScalarDestWithAnotherString; use Backbrain\Automapper\Tests\Fixtures\ScalarSrc; use PHPUnit\Framework\TestCase; +use Psr\Log\LoggerInterface; class MapTest extends TestCase { @@ -176,4 +177,50 @@ public function testObjectMappingDestSameType() $this->assertSame($source->getObj(), $destination->getObj()); } + + public function testIgnoredMemberWithNoSourcePropertyDoesNotLogWarning() + { + $warningMembers = []; + $logger = $this->createMock(LoggerInterface::class); + $logger->method('warning')->willReturnCallback( + function (string $message, array $context) use (&$warningMembers) { + if ('Cannot access source property.' === $message) { + $warningMembers[] = $context['member'] ?? null; + } + } + ); + + $config = new MapperConfiguration(fn (Config $config) => $config + ->createMap(ScalarSrc::class, ScalarDestWithAnotherString::class) + ->forMember('anotherString', fn (Options $opts) => $opts->ignore()) + ); + + $autoMapper = new AutoMapper($config, logger: $logger); + + $source = new ScalarSrc('John Doe', 30, 1.75); + $destination = $autoMapper->map($source, ScalarDestWithAnotherString::class); + + $this->assertInstanceOf(ScalarDestWithAnotherString::class, $destination); + $this->assertNotContains('anotherString', $warningMembers, 'Ignored member "anotherString" should not trigger a source property warning'); + $this->assertEquals($source->aString, $destination->aString); + $this->assertEquals($source->anInt, $destination->anInt); + } + + public function testIgnoredMemberSkipsSourceReadAndDestinationWrite() + { + $config = new MapperConfiguration(fn (Config $config) => $config + ->createMap(ScalarSrc::class, ScalarDest::class) + ->forMember('aString', fn (Options $opts) => $opts->ignore()) + ); + + $autoMapper = $config->createMapper(); + + $source = new ScalarSrc('John Doe', 30, 1.75); + $destination = $autoMapper->map($source, ScalarDest::class); + + $this->assertInstanceOf(ScalarDest::class, $destination); + $this->assertEquals('', $destination->aString); + $this->assertEquals($source->anInt, $destination->anInt); + $this->assertEquals($source->aFloat, $destination->aFloat); + } }