diff --git a/CHANGELOG.md b/CHANGELOG.md index 558dc72..f0296ba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ * feat(`Context`): `with()` not accepts multiple argument. * build: Deinternalize `ObjectCacheFactory` * fix(`PresetMapping`): Support proxied classes, add tests. +* fix: Disallow proxy for objects with dynamic properties, including `stdClass`. ## 1.0.0 diff --git a/config/services.php b/config/services.php index e07de6c..000ef65 100644 --- a/config/services.php +++ b/config/services.php @@ -28,6 +28,7 @@ use Rekalogika\Mapper\Mapping\MappingFactoryInterface; use Rekalogika\Mapper\ObjectCache\Implementation\ObjectCacheFactory; use Rekalogika\Mapper\Proxy\Implementation\DoctrineProxyGenerator; +use Rekalogika\Mapper\Proxy\Implementation\DynamicPropertiesProxyGenerator; use Rekalogika\Mapper\Proxy\Implementation\ProxyFactory; use Rekalogika\Mapper\Proxy\Implementation\ProxyGenerator; use Rekalogika\Mapper\Proxy\Implementation\ProxyRegistry; @@ -406,6 +407,13 @@ service('doctrine'), ]); + $services + ->set('rekalogika.mapper.proxy.generator.dynamic_properties', DynamicPropertiesProxyGenerator::class) + ->decorate('rekalogika.mapper.proxy.generator') + ->args([ + service('.inner'), + ]); + # proxy registry $services diff --git a/src/Proxy/Implementation/DynamicPropertiesProxyGenerator.php b/src/Proxy/Implementation/DynamicPropertiesProxyGenerator.php new file mode 100644 index 0000000..82ab81e --- /dev/null +++ b/src/Proxy/Implementation/DynamicPropertiesProxyGenerator.php @@ -0,0 +1,44 @@ + + * + * For the full copyright and license information, please view the LICENSE file + * that was distributed with this source code. + */ + +namespace Rekalogika\Mapper\Proxy\Implementation; + +use Rekalogika\Mapper\Proxy\Exception\ProxyNotSupportedException; +use Rekalogika\Mapper\Proxy\ProxyGeneratorInterface; + +/** + * Prevent proxy creation for objects with dynamic properties. + * + * @internal + */ +final readonly class DynamicPropertiesProxyGenerator implements ProxyGeneratorInterface +{ + public function __construct( + private ProxyGeneratorInterface $decorated, + ) { + } + + public function generateProxyCode(string $realClass, string $proxyClass): string + { + $reflection = new \ReflectionClass($realClass); + + do { + if ($reflection->getAttributes(\AllowDynamicProperties::class)) { + throw new ProxyNotSupportedException($realClass, reason: 'Objects with dynamic properties do not support proxying.'); + } + } while ($reflection = $reflection->getParentClass()); + + + return $this->decorated->generateProxyCode($realClass, $proxyClass); + } +}