diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 748a07b21..7d2644a9a 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -25,23 +25,16 @@ parameters: - message: '#^Result of method Doctrine\\Tests\\Common\\Proxy\\LazyLoadableObjectWithVoid::(adding|incrementing)AndReturningVoid\(\) \(void\) is used\.$#' path: 'tests/Common/Proxy/ProxyLogicVoidReturnTypeTest.php' - - - message: '#^Property Doctrine\\Tests\\Common\\Proxy\\ProxyLogicTest::\$initializerCallbackMock \(callable\(\): mixed&PHPUnit\\Framework\\MockObject\\MockObject\) does not accept PHPUnit\\Framework\\MockObject\\MockObject&stdClass\.$#' - path: 'tests/Common/Proxy/ProxyLogicTest.php' - message: '#.*LazyLoadableObject.*#' paths: - 'tests/Common/Proxy/ProxyLogicTest.php' - - 'tests/Common/Proxy/ProxyLogicVoidReturnTypeTest.php' - message: '#^Instantiated class Doctrine\\Tests\\Common\\ProxyProxy\\__CG__\\Doctrine\\Tests\\Common\\Proxy\\.* not found.$#' path: 'tests/Common/Proxy/ProxyLogicTest.php' - message: '#^Instantiated class Doctrine\\Tests\\Common\\ProxyProxy\\__CG__\\Doctrine\\Tests\\Common\\Proxy\\.* not found.$#' path: 'tests/Common/Proxy/ProxyLogicVoidReturnTypeTest.php' - - - message: '#^Property Doctrine\\Tests\\Common\\Proxy\\ProxyLogicVoidReturnTypeTest::\$initializerCallbackMock \(callable\(\): mixed&PHPUnit\\Framework\\MockObject\\MockObject\) does not accept PHPUnit\\Framework\\MockObject\\MockObject&stdClass\.$#' - path: 'tests/Common/Proxy/ProxyLogicVoidReturnTypeTest.php' - message: '#^Method Doctrine\\Tests\\Common\\Proxy\\MagicIssetClassWithInteger::__isset\(\) should return bool but returns int\.$#' path: 'tests/Common/Proxy/MagicIssetClassWithInteger.php' diff --git a/src/Proxy/ProxyGenerator.php b/src/Proxy/ProxyGenerator.php index 8019d418f..d10f68993 100644 --- a/src/Proxy/ProxyGenerator.php +++ b/src/Proxy/ProxyGenerator.php @@ -79,7 +79,7 @@ class ProxyGenerator (?\\?[a-z_\x7f-\xff][\w\x7f-\xff]*(?:\\[a-z_\x7f-\xff][\w\x7f-\xff]*)*) (?(?&type)\s*&\s*(?&type)) (?(?:(?:\(\s*(?&intersection_type)\s*\))|(?&type))(?:\s*\|\s*(?:(?:\(\s*(?&intersection_type)\s*\))|(?&type)))+) -)(?:public\s+)?(?:function\s+%s\s*\(\)\s*)\s*(?::\s*(?:(?&union_type)|(?&intersection_type)|(?:\??(?&type)))\s*)?{\s*return\s*\$this->%s;\s*})i +)(?:public\s+)?(?:function\s+%1$s\s*\(\)\s*)\s*(?::\s*(?:(?&union_type)|(?&intersection_type)|(?:\??(?&type)))\s*)?{\s*return\s*(\$this->%2$s|new\s+(?&type)\(\$this->%2$s\)|(?&type)::\w+\(\$this->%2$s\));\s*})i EOT; /** diff --git a/tests/Common/Proxy/LazyLoadableObjectWithCustomIdType.php b/tests/Common/Proxy/LazyLoadableObjectWithCustomIdType.php new file mode 100644 index 000000000..f56354dfe --- /dev/null +++ b/tests/Common/Proxy/LazyLoadableObjectWithCustomIdType.php @@ -0,0 +1,26 @@ +identifierFieldWithStaticVOConstructor); + } + + public function getIdentifierFieldWithVOConstructor() : ValueId + { + return new ValueId($this->identifierFieldWithVOConstructor); + } +} diff --git a/tests/Common/Proxy/LazyLoadableObjectWithCustomIdTypeClassMetadata.php b/tests/Common/Proxy/LazyLoadableObjectWithCustomIdTypeClassMetadata.php new file mode 100644 index 000000000..5cd36b2ae --- /dev/null +++ b/tests/Common/Proxy/LazyLoadableObjectWithCustomIdTypeClassMetadata.php @@ -0,0 +1,164 @@ + true, + 'identifierFieldWithVOConstructor' => true, + ]; + + /** + * @var array + */ + protected $fields = [ + 'identifierFieldWithStaticVOConstructor' => true, + 'identifierFieldWithVOConstructor' => true, + ]; + + /** + * {@inheritDoc} + */ + public function getName() + { + return $this->getReflectionClass()->getName(); + } + + /** + * {@inheritDoc} + */ + public function getIdentifier() + { + return array_keys($this->identifier); + } + + /** + * {@inheritDoc} + */ + public function getReflectionClass() + { + if (null === $this->reflectionClass) { + $this->reflectionClass = new \ReflectionClass(__NAMESPACE__ . '\LazyLoadableObjectWithCustomIdType'); + } + + return $this->reflectionClass; + } + + /** + * {@inheritDoc} + */ + public function isIdentifier($fieldName) + { + return isset($this->identifier[$fieldName]); + } + + /** + * {@inheritDoc} + */ + public function hasField($fieldName) + { + return isset($this->fields[$fieldName]); + } + + /** + * {@inheritDoc} + */ + public function hasAssociation($fieldName) + { + return false; + } + + /** + * {@inheritDoc} + */ + public function isSingleValuedAssociation($fieldName) + { + throw new \BadMethodCallException('not implemented'); + } + + /** + * {@inheritDoc} + */ + public function isCollectionValuedAssociation($fieldName) + { + throw new \BadMethodCallException('not implemented'); + } + + /** + * {@inheritDoc} + */ + public function getFieldNames() + { + return array_keys($this->fields); + } + + /** + * {@inheritDoc} + */ + public function getIdentifierFieldNames() + { + return $this->getIdentifier(); + } + + /** + * {@inheritDoc} + */ + public function getAssociationNames() + { + return []; + } + + /** + * {@inheritDoc} + */ + public function getTypeOfField($fieldName) + { + return 'string'; + } + + /** + * {@inheritDoc} + */ + public function getAssociationTargetClass($assocName) + { + throw new \BadMethodCallException('not implemented'); + } + + /** + * {@inheritDoc} + */ + public function isAssociationInverseSide($assocName) + { + throw new \BadMethodCallException('not implemented'); + } + + /** + * {@inheritDoc} + */ + public function getAssociationMappedByTargetField($assocName) + { + throw new \BadMethodCallException('not implemented'); + } + + /** + * {@inheritDoc} + */ + public function getIdentifierValues($object) + { + throw new \BadMethodCallException('not implemented'); + } +} diff --git a/tests/Common/Proxy/LazyLoadableObjectWithNoGetPrefix.php b/tests/Common/Proxy/LazyLoadableObjectWithNoGetPrefix.php new file mode 100644 index 000000000..e45053e63 --- /dev/null +++ b/tests/Common/Proxy/LazyLoadableObjectWithNoGetPrefix.php @@ -0,0 +1,19 @@ +identifierField); + } + +} diff --git a/tests/Common/Proxy/LazyLoadableObjectWithNoGetPrefixClassMetadata.php b/tests/Common/Proxy/LazyLoadableObjectWithNoGetPrefixClassMetadata.php new file mode 100644 index 000000000..96d24cc24 --- /dev/null +++ b/tests/Common/Proxy/LazyLoadableObjectWithNoGetPrefixClassMetadata.php @@ -0,0 +1,162 @@ + true, + ]; + + /** + * @var array + */ + protected $fields = [ + 'identifierField' => true, + ]; + + /** + * {@inheritDoc} + */ + public function getName() + { + return $this->getReflectionClass()->getName(); + } + + /** + * {@inheritDoc} + */ + public function getIdentifier() + { + return array_keys($this->identifier); + } + + /** + * {@inheritDoc} + */ + public function getReflectionClass() + { + if (null === $this->reflectionClass) { + $this->reflectionClass = new \ReflectionClass(__NAMESPACE__ . '\LazyLoadableObjectWithNoGetPrefix'); + } + + return $this->reflectionClass; + } + + /** + * {@inheritDoc} + */ + public function isIdentifier($fieldName) + { + return isset($this->identifier[$fieldName]); + } + + /** + * {@inheritDoc} + */ + public function hasField($fieldName) + { + return isset($this->fields[$fieldName]); + } + + /** + * {@inheritDoc} + */ + public function hasAssociation($fieldName) + { + return false; + } + + /** + * {@inheritDoc} + */ + public function isSingleValuedAssociation($fieldName) + { + throw new \BadMethodCallException('not implemented'); + } + + /** + * {@inheritDoc} + */ + public function isCollectionValuedAssociation($fieldName) + { + throw new \BadMethodCallException('not implemented'); + } + + /** + * {@inheritDoc} + */ + public function getFieldNames() + { + return array_keys($this->fields); + } + + /** + * {@inheritDoc} + */ + public function getIdentifierFieldNames() + { + return $this->getIdentifier(); + } + + /** + * {@inheritDoc} + */ + public function getAssociationNames() + { + return []; + } + + /** + * {@inheritDoc} + */ + public function getTypeOfField($fieldName) + { + return 'string'; + } + + /** + * {@inheritDoc} + */ + public function getAssociationTargetClass($assocName) + { + throw new \BadMethodCallException('not implemented'); + } + + /** + * {@inheritDoc} + */ + public function isAssociationInverseSide($assocName) + { + throw new \BadMethodCallException('not implemented'); + } + + /** + * {@inheritDoc} + */ + public function getAssociationMappedByTargetField($assocName) + { + throw new \BadMethodCallException('not implemented'); + } + + /** + * {@inheritDoc} + */ + public function getIdentifierValues($object) + { + throw new \BadMethodCallException('not implemented'); + } +} diff --git a/tests/Common/Proxy/ProxyLogicIdentifierGetterTest.php b/tests/Common/Proxy/ProxyLogicIdentifierGetterTest.php index 40ac68711..aedc9becf 100644 --- a/tests/Common/Proxy/ProxyLogicIdentifierGetterTest.php +++ b/tests/Common/Proxy/ProxyLogicIdentifierGetterTest.php @@ -18,11 +18,12 @@ class ProxyLogicIdentifierGetterTest extends TestCase { /** * @param string $fieldName - * @param mixed $expectedReturnedValue + * @param mixed $value + * @param mixed $expectedReturnedValue * * @dataProvider methodsForWhichLazyLoadingShouldBeDisabled */ - public function testNoLazyLoadingForIdentifier(ClassMetadata $metadata, $fieldName, $expectedReturnedValue) + public function testNoLazyLoadingForIdentifier(ClassMetadata $metadata, $fieldName, $value, $expectedReturnedValue = null) { $className = $metadata->getName(); $proxyClassName = 'Doctrine\Tests\Common\ProxyProxy\__CG__\\' . $className; @@ -48,9 +49,13 @@ static function () { $reflection = $metadata->getReflectionClass()->getProperty($fieldName); $reflection->setAccessible(true); - $reflection->setValue($proxy, $expectedReturnedValue); + $reflection->setValue($proxy, $value); - self::assertSame($expectedReturnedValue, $proxy->{'get' . $fieldName}()); + if ($expectedReturnedValue === null) { + self::assertSame($value, $proxy->{'get' . $fieldName}()); + } else { + self::assertEquals($expectedReturnedValue, $proxy->{'get' . $fieldName}()); + } } /** @@ -72,6 +77,8 @@ public function methodsForWhichLazyLoadingShouldBeDisabled() [new LazyLoadableObjectWithTraitClassMetadata(), 'identifierFieldInTrait', 123], [new LazyLoadableObjectWithNullableTypehintsClassMetadata(), 'identifierFieldReturnClassOneLetterNullable', new stdClass()], [new LazyLoadableObjectWithNullableTypehintsClassMetadata(), 'identifierFieldReturnClassOneLetterNullableWithSpace', new stdClass()], + [new LazyLoadableObjectWithCustomIdTypeClassMetadata(), 'identifierFieldWithStaticVOConstructor', 'a', ValueId::new('a')], + [new LazyLoadableObjectWithCustomIdTypeClassMetadata(), 'identifierFieldWithVOConstructor', 'b', ValueId::new('b')], ]; if (PHP_VERSION_ID >= 80000) { diff --git a/tests/Common/Proxy/ValueId.php b/tests/Common/Proxy/ValueId.php new file mode 100644 index 000000000..ac38fcc18 --- /dev/null +++ b/tests/Common/Proxy/ValueId.php @@ -0,0 +1,19 @@ +id = $id; + } + + public static function new(string $id) : self + { + return new self($id); + } +}