diff --git a/composer.json b/composer.json index 64defc52659..5a01a0fa328 100644 --- a/composer.json +++ b/composer.json @@ -39,7 +39,7 @@ "doctrine/annotations": "^1.13", "doctrine/coding-standard": "^9.0", "phpbench/phpbench": "^1.0", - "phpstan/phpstan": "1.5.0", + "phpstan/phpstan": "1.6.1", "phpunit/phpunit": "^9.5", "psr/log": "^1 || ^2 || ^3", "squizlabs/php_codesniffer": "3.6.2", @@ -50,6 +50,7 @@ "doctrine/annotations": "<1.13 || >= 2.0" }, "suggest": { + "ext-dom": "Provides support for XSD validation for XML mapping files", "symfony/cache": "Provides cache support for Setup Tool with doctrine/cache 2.0" }, "autoload": { diff --git a/lib/Doctrine/ORM/Internal/Hydration/HydrationException.php b/lib/Doctrine/ORM/Internal/Hydration/HydrationException.php index fa64d53ef9b..505966c7dbf 100644 --- a/lib/Doctrine/ORM/Internal/Hydration/HydrationException.php +++ b/lib/Doctrine/ORM/Internal/Hydration/HydrationException.php @@ -56,15 +56,15 @@ public static function missingDiscriminatorMetaMappingColumn(string $entityName, } /** - * @param string[] $discrMap - * @psalm-param array $discrMap + * @param string[] $discrValues + * @psalm-param list $discrValues */ - public static function invalidDiscriminatorValue(string $discrValue, array $discrMap): self + public static function invalidDiscriminatorValue(string $discrValue, array $discrValues): self { return new self(sprintf( 'The discriminator value "%s" is invalid. It must be one of "%s".', $discrValue, - implode('", "', $discrMap) + implode('", "', $discrValues) )); } } diff --git a/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php b/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php index 42c96cb4c66..cb2e5ca11b3 100644 --- a/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php +++ b/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php @@ -478,7 +478,9 @@ class ClassMetadataInfo implements ClassMetadata * * @see discriminatorColumn * - * @var mixed + * @var array + * + * @psalm-var array */ public $discriminatorMap = []; diff --git a/lib/Doctrine/ORM/Mapping/Driver/AnnotationDriver.php b/lib/Doctrine/ORM/Mapping/Driver/AnnotationDriver.php index 46f3624d1cb..a0968014265 100644 --- a/lib/Doctrine/ORM/Mapping/Driver/AnnotationDriver.php +++ b/lib/Doctrine/ORM/Mapping/Driver/AnnotationDriver.php @@ -10,9 +10,9 @@ use Doctrine\ORM\Events; use Doctrine\ORM\Mapping; use Doctrine\ORM\Mapping\Builder\EntityListenerBuilder; -use Doctrine\ORM\Mapping\ClassMetadataInfo; +use Doctrine\ORM\Mapping\ClassMetadata; use Doctrine\ORM\Mapping\MappingException; -use Doctrine\Persistence\Mapping\ClassMetadata; +use Doctrine\Persistence\Mapping\ClassMetadata as PersistenceClassMetadata; use Doctrine\Persistence\Mapping\Driver\ColocatedMappingDriver; use Doctrine\Persistence\Mapping\Driver\MappingDriver; use ReflectionClass; @@ -68,10 +68,14 @@ public function __construct($reader, $paths = null) /** * {@inheritDoc} + * + * @psalm-param class-string $className + * @psalm-param ClassMetadata $metadata + * + * @template T of object */ - public function loadMetadataForClass($className, ClassMetadata $metadata) + public function loadMetadataForClass($className, PersistenceClassMetadata $metadata) { - assert($metadata instanceof Mapping\ClassMetadata); $class = $metadata->getReflectionClass() // this happens when running annotation driver in combination with // static reflection services. This is not the nicest fix @@ -259,7 +263,7 @@ public function loadMetadataForClass($className, ClassMetadata $metadata) constant('Doctrine\ORM\Mapping\ClassMetadata::INHERITANCE_TYPE_' . $inheritanceTypeAnnot->value) ); - if ($metadata->inheritanceType !== ClassMetadataInfo::INHERITANCE_TYPE_NONE) { + if ($metadata->inheritanceType !== ClassMetadata::INHERITANCE_TYPE_NONE) { // Evaluate DiscriminatorColumn annotation if (isset($classAnnotations[Mapping\DiscriminatorColumn::class])) { $discrColumnAnnot = $classAnnotations[Mapping\DiscriminatorColumn::class]; @@ -504,7 +508,7 @@ public function loadMetadataForClass($className, ClassMetadata $metadata) private function loadRelationShipMapping( ReflectionProperty $property, array &$mapping, - ClassMetadata $metadata, + PersistenceClassMetadata $metadata, array $joinColumns, string $className ): void { @@ -608,7 +612,7 @@ private function loadRelationShipMapping( /** * Attempts to resolve the fetch mode. * - * @psalm-return \Doctrine\ORM\Mapping\ClassMetadata::FETCH_* The fetch mode as defined in ClassMetadata. + * @psalm-return ClassMetadata::FETCH_* The fetch mode as defined in ClassMetadata. * * @throws MappingException If the fetch mode is not valid. */ @@ -624,7 +628,7 @@ private function getFetchMode(string $className, string $fetchMode): int /** * Attempts to resolve the generated mode. * - * @psalm-return ClassMetadataInfo::GENERATED_* + * @psalm-return ClassMetadata::GENERATED_* * * @throws MappingException If the fetch mode is not valid. */ @@ -724,7 +728,7 @@ private function joinColumnToArray(Mapping\JoinColumn $joinColumn): array * precision: int, * notInsertable?: bool, * notUpdateble?: bool, - * generated?: ClassMetadataInfo::GENERATED_*, + * generated?: ClassMetadata::GENERATED_*, * enumType?: class-string, * options?: mixed[], * columnName?: string, diff --git a/lib/Doctrine/ORM/Mapping/Driver/AttributeDriver.php b/lib/Doctrine/ORM/Mapping/Driver/AttributeDriver.php index 0b3ef618e74..58d6d47cb0f 100644 --- a/lib/Doctrine/ORM/Mapping/Driver/AttributeDriver.php +++ b/lib/Doctrine/ORM/Mapping/Driver/AttributeDriver.php @@ -8,9 +8,9 @@ use Doctrine\ORM\Events; use Doctrine\ORM\Mapping; use Doctrine\ORM\Mapping\Builder\EntityListenerBuilder; -use Doctrine\ORM\Mapping\ClassMetadataInfo; +use Doctrine\ORM\Mapping\ClassMetadata; use Doctrine\ORM\Mapping\MappingException; -use Doctrine\Persistence\Mapping\ClassMetadata; +use Doctrine\Persistence\Mapping\ClassMetadata as PersistenceClassMetadata; use Doctrine\Persistence\Mapping\Driver\ColocatedMappingDriver; use Doctrine\Persistence\Mapping\Driver\MappingDriver; use ReflectionClass; @@ -88,10 +88,16 @@ public function isTransient($className) return true; } - public function loadMetadataForClass($className, ClassMetadata $metadata): void + /** + * {@inheritDoc} + * + * @psalm-param class-string $className + * @psalm-param ClassMetadata $metadata + * + * @template T of object + */ + public function loadMetadataForClass($className, PersistenceClassMetadata $metadata): void { - assert($metadata instanceof ClassMetadataInfo); - $reflectionClass = $metadata->getReflectionClass(); $classAttributes = $this->reader->getClassAnnotations($reflectionClass); @@ -228,7 +234,7 @@ public function loadMetadataForClass($className, ClassMetadata $metadata): void constant('Doctrine\ORM\Mapping\ClassMetadata::INHERITANCE_TYPE_' . $inheritanceTypeAttribute->value) ); - if ($metadata->inheritanceType !== Mapping\ClassMetadata::INHERITANCE_TYPE_NONE) { + if ($metadata->inheritanceType !== ClassMetadata::INHERITANCE_TYPE_NONE) { // Evaluate DiscriminatorColumn annotation if (isset($classAttributes[Mapping\DiscriminatorColumn::class])) { $discrColumnAttribute = $classAttributes[Mapping\DiscriminatorColumn::class]; @@ -481,7 +487,7 @@ public function loadMetadataForClass($className, ClassMetadata $metadata): void // Check for `fetch` if ($associationOverride->fetch) { - $override['fetch'] = constant(Mapping\ClassMetadata::class . '::FETCH_' . $associationOverride->fetch); + $override['fetch'] = constant(ClassMetadata::class . '::FETCH_' . $associationOverride->fetch); } $metadata->setAssociationOverride($fieldName, $override); @@ -548,7 +554,7 @@ public function loadMetadataForClass($className, ClassMetadata $metadata): void * @param string $className The class name. * @param string $fetchMode The fetch mode. * - * @return int The fetch mode as defined in ClassMetadata. + * @return ClassMetadata::FETCH_* The fetch mode as defined in ClassMetadata. * * @throws MappingException If the fetch mode is not valid. */ diff --git a/lib/Doctrine/ORM/Mapping/Driver/DatabaseDriver.php b/lib/Doctrine/ORM/Mapping/Driver/DatabaseDriver.php index e3669e58836..f88367655bf 100644 --- a/lib/Doctrine/ORM/Mapping/Driver/DatabaseDriver.php +++ b/lib/Doctrine/ORM/Mapping/Driver/DatabaseDriver.php @@ -12,9 +12,10 @@ use Doctrine\DBAL\Types\Types; use Doctrine\Inflector\Inflector; use Doctrine\Inflector\InflectorFactory; +use Doctrine\ORM\Mapping\ClassMetadata; use Doctrine\ORM\Mapping\ClassMetadataInfo; use Doctrine\ORM\Mapping\MappingException; -use Doctrine\Persistence\Mapping\ClassMetadata; +use Doctrine\Persistence\Mapping\ClassMetadata as PersistenceClassMetadata; use Doctrine\Persistence\Mapping\Driver\MappingDriver; use InvalidArgumentException; @@ -159,8 +160,13 @@ public function setInflector(Inflector $inflector): void /** * {@inheritDoc} + * + * @psalm-param class-string $className + * @psalm-param ClassMetadata $metadata + * + * @template T of object */ - public function loadMetadataForClass($className, ClassMetadata $metadata) + public function loadMetadataForClass($className, PersistenceClassMetadata $metadata) { $this->reverseEngineerMappingFromDatabase(); diff --git a/lib/Doctrine/ORM/Mapping/Driver/XmlDriver.php b/lib/Doctrine/ORM/Mapping/Driver/XmlDriver.php index 1b1969f3aac..7dbdd9ab9d8 100644 --- a/lib/Doctrine/ORM/Mapping/Driver/XmlDriver.php +++ b/lib/Doctrine/ORM/Mapping/Driver/XmlDriver.php @@ -5,11 +5,13 @@ namespace Doctrine\ORM\Mapping\Driver; use Doctrine\Common\Collections\Criteria; +use Doctrine\Deprecations\Deprecation; use Doctrine\ORM\Mapping\Builder\EntityListenerBuilder; -use Doctrine\ORM\Mapping\ClassMetadata as Metadata; +use Doctrine\ORM\Mapping\ClassMetadata; use Doctrine\ORM\Mapping\MappingException; -use Doctrine\Persistence\Mapping\ClassMetadata; +use Doctrine\Persistence\Mapping\ClassMetadata as PersistenceClassMetadata; use Doctrine\Persistence\Mapping\Driver\FileDriver; +use DOMDocument; use InvalidArgumentException; use LogicException; use SimpleXMLElement; @@ -22,6 +24,9 @@ use function extension_loaded; use function file_get_contents; use function in_array; +use function libxml_clear_errors; +use function libxml_get_errors; +use function libxml_use_internal_errors; use function simplexml_load_string; use function sprintf; use function str_replace; @@ -36,10 +41,13 @@ class XmlDriver extends FileDriver { public const DEFAULT_FILE_EXTENSION = '.dcm.xml'; + /** @var bool */ + private $isXsdValidationEnabled; + /** * {@inheritDoc} */ - public function __construct($locator, $fileExtension = self::DEFAULT_FILE_EXTENSION) + public function __construct($locator, $fileExtension = self::DEFAULT_FILE_EXTENSION, bool $isXsdValidationEnabled = false) { if (! extension_loaded('simplexml')) { throw new LogicException(sprintf( @@ -48,13 +56,37 @@ public function __construct($locator, $fileExtension = self::DEFAULT_FILE_EXTENS )); } + if (! $isXsdValidationEnabled) { + Deprecation::trigger( + 'doctrine/orm', + 'https://github.com/doctrine/orm/pull/6728', + sprintf( + 'Using XML mapping driver with XSD validation disabled is deprecated' + . ' and will not be supported in Doctrine ORM 3.0.' + ) + ); + } + + if ($isXsdValidationEnabled && ! extension_loaded('dom')) { + throw new LogicException(sprintf( + 'XSD validation cannot be enabled because the DOM extension is missing.' + )); + } + + $this->isXsdValidationEnabled = $isXsdValidationEnabled; + parent::__construct($locator, $fileExtension); } /** * {@inheritDoc} + * + * @psalm-param class-string $className + * @psalm-param ClassMetadata $metadata + * + * @template T of object */ - public function loadMetadataForClass($className, ClassMetadata $metadata) + public function loadMetadataForClass($className, PersistenceClassMetadata $metadata) { $xmlRoot = $this->getElement($className); assert($xmlRoot instanceof SimpleXMLElement); @@ -142,7 +174,7 @@ public function loadMetadataForClass($className, ClassMetadata $metadata) $inheritanceType = (string) $xmlRoot['inheritance-type']; $metadata->setInheritanceType(constant('Doctrine\ORM\Mapping\ClassMetadata::INHERITANCE_TYPE_' . $inheritanceType)); - if ($metadata->inheritanceType !== Metadata::INHERITANCE_TYPE_NONE) { + if ($metadata->inheritanceType !== ClassMetadata::INHERITANCE_TYPE_NONE) { // Evaluate if (isset($xmlRoot->{'discriminator-column'})) { $discrColumn = $xmlRoot->{'discriminator-column'}; @@ -659,7 +691,7 @@ public function loadMetadataForClass($className, ClassMetadata $metadata) // Check for `fetch` if (isset($overrideElement['fetch'])) { - $override['fetch'] = constant(Metadata::class . '::FETCH_' . (string) $overrideElement['fetch']); + $override['fetch'] = constant(ClassMetadata::class . '::FETCH_' . (string) $overrideElement['fetch']); } $metadata->setAssociationOverride($fieldName, $override); @@ -909,6 +941,7 @@ private function getCascadeMappings(SimpleXMLElement $cascadeElement): array */ protected function loadMappingFile($file) { + $this->validateMapping($file); $result = []; // Note: we do not use `simplexml_load_file()` because of https://bugs.php.net/bug.php?id=62577 $xmlElement = simplexml_load_string(file_get_contents($file)); @@ -936,6 +969,27 @@ protected function loadMappingFile($file) return $result; } + private function validateMapping(string $file): void + { + if (! $this->isXsdValidationEnabled) { + return; + } + + $backedUpErrorSetting = libxml_use_internal_errors(true); + + try { + $document = new DOMDocument(); + $document->load($file); + + if (! $document->schemaValidate(__DIR__ . '/../../../../../doctrine-mapping.xsd')) { + throw MappingException::fromLibXmlErrors(libxml_get_errors()); + } + } finally { + libxml_clear_errors(); + libxml_use_internal_errors($backedUpErrorSetting); + } + } + /** * @param mixed $element * diff --git a/lib/Doctrine/ORM/Mapping/MappingException.php b/lib/Doctrine/ORM/Mapping/MappingException.php index c7856d0381e..d1bea3fe443 100644 --- a/lib/Doctrine/ORM/Mapping/MappingException.php +++ b/lib/Doctrine/ORM/Mapping/MappingException.php @@ -7,6 +7,7 @@ use BackedEnum; use Doctrine\ORM\Exception\ORMException; use Exception; +use LibXMLError; use ReflectionException; use ValueError; @@ -18,6 +19,8 @@ use function implode; use function sprintf; +use const PHP_EOL; + /** * A MappingException indicates that something is wrong with the mapping setup. */ @@ -984,4 +987,21 @@ public static function invalidEnumValue( $enumType ), 0, $previous); } + + /** + * @param LibXMLError[] $errors + */ + public static function fromLibXmlErrors(array $errors): self + { + $formatter = static function (LibXMLError $error): string { + return sprintf( + 'libxml error: %s in %s at line %d', + $error->message, + $error->file, + $error->line + ); + }; + + return new self(implode(PHP_EOL, array_map($formatter, $errors))); + } } diff --git a/lib/Doctrine/ORM/ORMSetup.php b/lib/Doctrine/ORM/ORMSetup.php index 990550818f9..efd5682aedb 100644 --- a/lib/Doctrine/ORM/ORMSetup.php +++ b/lib/Doctrine/ORM/ORMSetup.php @@ -99,10 +99,11 @@ public static function createXMLMetadataConfiguration( array $paths, bool $isDevMode = false, ?string $proxyDir = null, - ?CacheItemPoolInterface $cache = null + ?CacheItemPoolInterface $cache = null, + bool $isXsdValidationEnabled = false ): Configuration { $config = self::createConfiguration($isDevMode, $proxyDir, $cache); - $config->setMetadataDriverImpl(new XmlDriver($paths)); + $config->setMetadataDriverImpl(new XmlDriver($paths, XmlDriver::DEFAULT_FILE_EXTENSION, $isXsdValidationEnabled)); return $config; } diff --git a/lib/Doctrine/ORM/Tools/Console/Command/SchemaTool/UpdateCommand.php b/lib/Doctrine/ORM/Tools/Console/Command/SchemaTool/UpdateCommand.php index f732a028972..ebbd877c2a6 100644 --- a/lib/Doctrine/ORM/Tools/Console/Command/SchemaTool/UpdateCommand.php +++ b/lib/Doctrine/ORM/Tools/Console/Command/SchemaTool/UpdateCommand.php @@ -87,7 +87,9 @@ protected function executeSchemaCommand(InputInterface $input, OutputInterface $ if ($dumpSql) { $ui->text('The following SQL statements will be executed:'); $ui->newLine(); - $ui->listing($sqls); + foreach ($sqls as $sql) { + $ui->text(sprintf(' %s;', $sql)); + } } if ($force) { diff --git a/lib/Doctrine/ORM/Tools/Console/Command/ValidateSchemaCommand.php b/lib/Doctrine/ORM/Tools/Console/Command/ValidateSchemaCommand.php index 0ba17a6c3bf..eaaf38897d7 100644 --- a/lib/Doctrine/ORM/Tools/Console/Command/ValidateSchemaCommand.php +++ b/lib/Doctrine/ORM/Tools/Console/Command/ValidateSchemaCommand.php @@ -73,7 +73,9 @@ protected function execute(InputInterface $input, OutputInterface $output): int if ($output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE) { $sqls = $validator->getUpdateSchemaList(); $ui->comment(sprintf('%d schema diff(s) detected:', count($sqls))); - $ui->listing($sqls); + foreach ($sqls as $sql) { + $ui->text(sprintf(' %s;', $sql)); + } } $exit += 2; diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index d64e07b5320..c80bc54bda3 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -130,16 +130,6 @@ parameters: count: 1 path: lib/Doctrine/ORM/EntityRepository.php - - - message: "#^Parameter \\#2 \\$discrMap of static method Doctrine\\\\ORM\\\\Internal\\\\Hydration\\\\HydrationException\\:\\:invalidDiscriminatorValue\\(\\) expects array\\, array\\ given\\.$#" - count: 1 - path: lib/Doctrine/ORM/Internal/Hydration/ObjectHydrator.php - - - - message: "#^Parameter \\#2 \\$discrMap of static method Doctrine\\\\ORM\\\\Internal\\\\Hydration\\\\HydrationException\\:\\:invalidDiscriminatorValue\\(\\) expects array\\, array\\ given\\.$#" - count: 1 - path: lib/Doctrine/ORM/Internal/Hydration/SimpleObjectHydrator.php - - message: "#^Offset 'indexes' on array\\{name\\: string, schema\\: string, indexes\\: array, uniqueConstraints\\: array, options\\: array\\, quoted\\?\\: bool\\} in isset\\(\\) always exists and is not nullable\\.$#" count: 1 @@ -215,181 +205,6 @@ parameters: count: 1 path: lib/Doctrine/ORM/Mapping/Driver/AnnotationDriver.php - - - message: "#^Parameter \\#1 \\$metadata of static method Doctrine\\\\ORM\\\\Mapping\\\\Builder\\\\EntityListenerBuilder\\:\\:bindEntityListener\\(\\) expects Doctrine\\\\ORM\\\\Mapping\\\\ClassMetadata, Doctrine\\\\ORM\\\\Mapping\\\\ClassMetadataInfo&Doctrine\\\\Persistence\\\\Mapping\\\\ClassMetadata\\ given\\.$#" - count: 1 - path: lib/Doctrine/ORM/Mapping/Driver/AttributeDriver.php - - - - message: "#^Access to an undefined property Doctrine\\\\Persistence\\\\Mapping\\\\ClassMetadata\\\\:\\:\\$name\\.$#" - count: 1 - path: lib/Doctrine/ORM/Mapping/Driver/DatabaseDriver.php - - - - message: "#^Access to an undefined property Doctrine\\\\Persistence\\\\Mapping\\\\ClassMetadata\\\\:\\:\\$table\\.$#" - count: 1 - path: lib/Doctrine/ORM/Mapping/Driver/DatabaseDriver.php - - - - message: "#^Call to an undefined method Doctrine\\\\Persistence\\\\Mapping\\\\ClassMetadata\\\\:\\:mapManyToMany\\(\\)\\.$#" - count: 1 - path: lib/Doctrine/ORM/Mapping/Driver/DatabaseDriver.php - - - - message: "#^Parameter \\#1 \\$metadata of method Doctrine\\\\ORM\\\\Mapping\\\\Driver\\\\DatabaseDriver\\:\\:buildFieldMappings\\(\\) expects Doctrine\\\\ORM\\\\Mapping\\\\ClassMetadataInfo, Doctrine\\\\Persistence\\\\Mapping\\\\ClassMetadata\\ given\\.$#" - count: 1 - path: lib/Doctrine/ORM/Mapping/Driver/DatabaseDriver.php - - - - message: "#^Parameter \\#1 \\$metadata of method Doctrine\\\\ORM\\\\Mapping\\\\Driver\\\\DatabaseDriver\\:\\:buildIndexes\\(\\) expects Doctrine\\\\ORM\\\\Mapping\\\\ClassMetadataInfo, Doctrine\\\\Persistence\\\\Mapping\\\\ClassMetadata\\ given\\.$#" - count: 1 - path: lib/Doctrine/ORM/Mapping/Driver/DatabaseDriver.php - - - - message: "#^Parameter \\#1 \\$metadata of method Doctrine\\\\ORM\\\\Mapping\\\\Driver\\\\DatabaseDriver\\:\\:buildToOneAssociationMappings\\(\\) expects Doctrine\\\\ORM\\\\Mapping\\\\ClassMetadataInfo, Doctrine\\\\Persistence\\\\Mapping\\\\ClassMetadata\\ given\\.$#" - count: 1 - path: lib/Doctrine/ORM/Mapping/Driver/DatabaseDriver.php - - - - message: "#^Access to an undefined property Doctrine\\\\Persistence\\\\Mapping\\\\ClassMetadata\\\\:\\:\\$inheritanceType\\.$#" - count: 1 - path: lib/Doctrine/ORM/Mapping/Driver/XmlDriver.php - - - - message: "#^Access to an undefined property Doctrine\\\\Persistence\\\\Mapping\\\\ClassMetadata\\\\:\\:\\$isEmbeddedClass\\.$#" - count: 1 - path: lib/Doctrine/ORM/Mapping/Driver/XmlDriver.php - - - - message: "#^Access to an undefined property Doctrine\\\\Persistence\\\\Mapping\\\\ClassMetadata\\\\:\\:\\$isMappedSuperclass\\.$#" - count: 1 - path: lib/Doctrine/ORM/Mapping/Driver/XmlDriver.php - - - - message: "#^Access to an undefined property Doctrine\\\\Persistence\\\\Mapping\\\\ClassMetadata\\\\:\\:\\$table\\.$#" - count: 3 - path: lib/Doctrine/ORM/Mapping/Driver/XmlDriver.php - - - - message: "#^Call to an undefined method Doctrine\\\\Persistence\\\\Mapping\\\\ClassMetadata\\\\:\\:addEntityListener\\(\\)\\.$#" - count: 1 - path: lib/Doctrine/ORM/Mapping/Driver/XmlDriver.php - - - - message: "#^Call to an undefined method Doctrine\\\\Persistence\\\\Mapping\\\\ClassMetadata\\\\:\\:addLifecycleCallback\\(\\)\\.$#" - count: 1 - path: lib/Doctrine/ORM/Mapping/Driver/XmlDriver.php - - - - message: "#^Call to an undefined method Doctrine\\\\Persistence\\\\Mapping\\\\ClassMetadata\\\\:\\:addSqlResultSetMapping\\(\\)\\.$#" - count: 1 - path: lib/Doctrine/ORM/Mapping/Driver/XmlDriver.php - - - - message: "#^Call to an undefined method Doctrine\\\\Persistence\\\\Mapping\\\\ClassMetadata\\\\:\\:enableCache\\(\\)\\.$#" - count: 1 - path: lib/Doctrine/ORM/Mapping/Driver/XmlDriver.php - - - - message: "#^Call to an undefined method Doctrine\\\\Persistence\\\\Mapping\\\\ClassMetadata\\\\:\\:getAssociationCacheDefaults\\(\\)\\.$#" - count: 4 - path: lib/Doctrine/ORM/Mapping/Driver/XmlDriver.php - - - - message: "#^Call to an undefined method Doctrine\\\\Persistence\\\\Mapping\\\\ClassMetadata\\\\:\\:mapEmbedded\\(\\)\\.$#" - count: 1 - path: lib/Doctrine/ORM/Mapping/Driver/XmlDriver.php - - - - message: "#^Call to an undefined method Doctrine\\\\Persistence\\\\Mapping\\\\ClassMetadata\\\\:\\:mapField\\(\\)\\.$#" - count: 3 - path: lib/Doctrine/ORM/Mapping/Driver/XmlDriver.php - - - - message: "#^Call to an undefined method Doctrine\\\\Persistence\\\\Mapping\\\\ClassMetadata\\\\:\\:mapManyToMany\\(\\)\\.$#" - count: 1 - path: lib/Doctrine/ORM/Mapping/Driver/XmlDriver.php - - - - message: "#^Call to an undefined method Doctrine\\\\Persistence\\\\Mapping\\\\ClassMetadata\\\\:\\:mapManyToOne\\(\\)\\.$#" - count: 1 - path: lib/Doctrine/ORM/Mapping/Driver/XmlDriver.php - - - - message: "#^Call to an undefined method Doctrine\\\\Persistence\\\\Mapping\\\\ClassMetadata\\\\:\\:mapOneToMany\\(\\)\\.$#" - count: 1 - path: lib/Doctrine/ORM/Mapping/Driver/XmlDriver.php - - - - message: "#^Call to an undefined method Doctrine\\\\Persistence\\\\Mapping\\\\ClassMetadata\\\\:\\:mapOneToOne\\(\\)\\.$#" - count: 1 - path: lib/Doctrine/ORM/Mapping/Driver/XmlDriver.php - - - - message: "#^Call to an undefined method Doctrine\\\\Persistence\\\\Mapping\\\\ClassMetadata\\\\:\\:markReadOnly\\(\\)\\.$#" - count: 1 - path: lib/Doctrine/ORM/Mapping/Driver/XmlDriver.php - - - - message: "#^Call to an undefined method Doctrine\\\\Persistence\\\\Mapping\\\\ClassMetadata\\\\:\\:setAssociationOverride\\(\\)\\.$#" - count: 1 - path: lib/Doctrine/ORM/Mapping/Driver/XmlDriver.php - - - - message: "#^Call to an undefined method Doctrine\\\\Persistence\\\\Mapping\\\\ClassMetadata\\\\:\\:setAttributeOverride\\(\\)\\.$#" - count: 1 - path: lib/Doctrine/ORM/Mapping/Driver/XmlDriver.php - - - - message: "#^Call to an undefined method Doctrine\\\\Persistence\\\\Mapping\\\\ClassMetadata\\\\:\\:setChangeTrackingPolicy\\(\\)\\.$#" - count: 1 - path: lib/Doctrine/ORM/Mapping/Driver/XmlDriver.php - - - - message: "#^Call to an undefined method Doctrine\\\\Persistence\\\\Mapping\\\\ClassMetadata\\\\:\\:setCustomGeneratorDefinition\\(\\)\\.$#" - count: 1 - path: lib/Doctrine/ORM/Mapping/Driver/XmlDriver.php - - - - message: "#^Call to an undefined method Doctrine\\\\Persistence\\\\Mapping\\\\ClassMetadata\\\\:\\:setCustomRepositoryClass\\(\\)\\.$#" - count: 2 - path: lib/Doctrine/ORM/Mapping/Driver/XmlDriver.php - - - - message: "#^Call to an undefined method Doctrine\\\\Persistence\\\\Mapping\\\\ClassMetadata\\\\:\\:setDiscriminatorColumn\\(\\)\\.$#" - count: 2 - path: lib/Doctrine/ORM/Mapping/Driver/XmlDriver.php - - - - message: "#^Call to an undefined method Doctrine\\\\Persistence\\\\Mapping\\\\ClassMetadata\\\\:\\:setDiscriminatorMap\\(\\)\\.$#" - count: 1 - path: lib/Doctrine/ORM/Mapping/Driver/XmlDriver.php - - - - message: "#^Call to an undefined method Doctrine\\\\Persistence\\\\Mapping\\\\ClassMetadata\\\\:\\:setIdGeneratorType\\(\\)\\.$#" - count: 1 - path: lib/Doctrine/ORM/Mapping/Driver/XmlDriver.php - - - - message: "#^Call to an undefined method Doctrine\\\\Persistence\\\\Mapping\\\\ClassMetadata\\\\:\\:setInheritanceType\\(\\)\\.$#" - count: 1 - path: lib/Doctrine/ORM/Mapping/Driver/XmlDriver.php - - - - message: "#^Call to an undefined method Doctrine\\\\Persistence\\\\Mapping\\\\ClassMetadata\\\\:\\:setPrimaryTable\\(\\)\\.$#" - count: 1 - path: lib/Doctrine/ORM/Mapping/Driver/XmlDriver.php - - - - message: "#^Call to an undefined method Doctrine\\\\Persistence\\\\Mapping\\\\ClassMetadata\\\\:\\:setSequenceGeneratorDefinition\\(\\)\\.$#" - count: 1 - path: lib/Doctrine/ORM/Mapping/Driver/XmlDriver.php - - - - message: "#^Call to an undefined method Doctrine\\\\Persistence\\\\Mapping\\\\ClassMetadata\\\\:\\:setVersionMapping\\(\\)\\.$#" - count: 2 - path: lib/Doctrine/ORM/Mapping/Driver/XmlDriver.php - - message: "#^Empty array passed to foreach\\.$#" count: 1 @@ -400,11 +215,6 @@ parameters: count: 1 path: lib/Doctrine/ORM/Mapping/Driver/XmlDriver.php - - - message: "#^Parameter \\#1 \\$metadata of static method Doctrine\\\\ORM\\\\Mapping\\\\Builder\\\\EntityListenerBuilder\\:\\:bindEntityListener\\(\\) expects Doctrine\\\\ORM\\\\Mapping\\\\ClassMetadata, Doctrine\\\\Persistence\\\\Mapping\\\\ClassMetadata\\ given\\.$#" - count: 1 - path: lib/Doctrine/ORM/Mapping/Driver/XmlDriver.php - - message: "#^Call to function is_int\\(\\) with string will always evaluate to false\\.$#" count: 1 @@ -1279,4 +1089,3 @@ parameters: message: "#^Access to an undefined property Doctrine\\\\Persistence\\\\Mapping\\\\ClassMetadata\\:\\:\\$subClasses\\.$#" count: 1 path: lib/Doctrine/ORM/Utility/HierarchyDiscriminatorResolver.php - diff --git a/psalm-baseline.xml b/psalm-baseline.xml index 0a1952a8eed..6c277678859 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -268,9 +268,6 @@ - - array_keys($discrMap) - $index @@ -298,11 +295,6 @@ $newObject['args'] - - - array_keys($discrMap) - - LazyCriteriaCollection @@ -482,7 +474,8 @@ $sequenceGeneratorDefinition $table - + + $this->discriminatorMap $this->entityListeners $this->fieldMappings $this->fullyQualifiedClassName($repositoryClassName) @@ -550,6 +543,9 @@ $mapping + + $metadata + $listenerClassName @@ -570,9 +566,6 @@ - - $metadata - $value[0] $value[0] @@ -582,6 +575,9 @@ $mapping + + $metadata + $listenerClassName @@ -596,22 +592,16 @@ - - $metadata - $metadata - $metadata - $this->namespace . $this->classNamesForTables[$tableName] $this->namespace . $this->inflector->classify(strtolower($tableName)) + + $metadata + class-string - - $metadata->name - $metadata->table - $this->tables[$tableName] $this->tables[$tableName] @@ -627,9 +617,9 @@ getColumns getIndexes - - mapManyToMany - + + $metadata->table + @@ -638,34 +628,38 @@ - - $metadata + + $map + (string) $xmlRoot['repository-class'] + isset($xmlRoot['repository-class']) ? (string) $xmlRoot['repository-class'] : null $xmlRoot->getName() === 'embeddable' $xmlRoot->getName() === 'entity' $xmlRoot->getName() === 'mapped-superclass' + + $this->cacheToArray($manyToManyElement->cache) + $this->cacheToArray($manyToOneElement->cache) + $this->cacheToArray($oneToManyElement->cache) + $this->cacheToArray($oneToOneElement->cache) + + + $metadata->table + $fileExtension $locator + + $metadata + array{usage: int|null, region?: string} - + $indexXml->options - $metadata->inheritanceType - $metadata->isEmbeddedClass - $metadata->isMappedSuperclass - $metadata->table - $metadata->table - $metadata->table - $metadata->table - $metadata->table - $metadata->table - $metadata->table $uniqueXml->options @@ -691,40 +685,6 @@ isset($xmlRoot->{'sql-result-set-mappings'}) isset($xmlRoot->{'unique-constraints'}) - - addEntityListener - addLifecycleCallback - addSqlResultSetMapping - enableCache - getAssociationCacheDefaults - getAssociationCacheDefaults - getAssociationCacheDefaults - getAssociationCacheDefaults - mapEmbedded - mapField - mapField - mapField - mapManyToMany - mapManyToOne - mapOneToMany - mapOneToOne - markReadOnly - setAssociationOverride - setAttributeOverride - setChangeTrackingPolicy - setCustomGeneratorDefinition - setCustomRepositoryClass - setCustomRepositoryClass - setDiscriminatorColumn - setDiscriminatorColumn - setDiscriminatorMap - setIdGeneratorType - setInheritanceType - setPrimaryTable - setSequenceGeneratorDefinition - setVersionMapping - setVersionMapping - diff --git a/tests/Doctrine/Tests/Mocks/ConnectionMock.php b/tests/Doctrine/Tests/Mocks/ConnectionMock.php index fad5e28626f..c9192dae4cd 100644 --- a/tests/Doctrine/Tests/Mocks/ConnectionMock.php +++ b/tests/Doctrine/Tests/Mocks/ConnectionMock.php @@ -51,9 +51,6 @@ public function __construct(array $params = [], ?Driver $driver = null, ?Configu $this->_platformMock = new DatabasePlatformMock(); parent::__construct($params, $driver ?? new DriverMock(), $config, $eventManager); - - // Override possible assignment of platform to database platform mock - $this->_platform = $this->_platformMock; } public function getDatabase(): string diff --git a/tests/Doctrine/Tests/ORM/Functional/BasicFunctionalTest.php b/tests/Doctrine/Tests/ORM/Functional/BasicFunctionalTest.php index d264a635b34..23aa589ca53 100644 --- a/tests/Doctrine/Tests/ORM/Functional/BasicFunctionalTest.php +++ b/tests/Doctrine/Tests/ORM/Functional/BasicFunctionalTest.php @@ -994,7 +994,7 @@ public function testFlushSingleAndNoCascade(): void $article1 = new CmsArticle(); $article1->topic = 'Foo'; $article1->text = 'Foo Text'; - $article1->author = $user; + $article1->user = $user; $user->articles[] = $article1; $this->expectException(InvalidArgumentException::class); diff --git a/tests/Doctrine/Tests/ORM/Functional/DatabaseDriverTestCase.php b/tests/Doctrine/Tests/ORM/Functional/DatabaseDriverTestCase.php index d2b7d67ea7e..a7e580646d5 100644 --- a/tests/Doctrine/Tests/ORM/Functional/DatabaseDriverTestCase.php +++ b/tests/Doctrine/Tests/ORM/Functional/DatabaseDriverTestCase.php @@ -4,7 +4,7 @@ namespace Doctrine\Tests\ORM\Functional; -use Doctrine\ORM\Mapping\ClassMetadataInfo; +use Doctrine\ORM\Mapping\ClassMetadata; use Doctrine\ORM\Mapping\Driver\DatabaseDriver; use Doctrine\Tests\OrmFunctionalTestCase; @@ -31,7 +31,7 @@ protected function convertToClassMetadata(array $entityTables, array $manyTables $metadatas = []; foreach ($driver->getAllClassNames() as $className) { - $class = new ClassMetadataInfo($className); + $class = new ClassMetadata($className); $driver->loadMetadataForClass($className, $class); $metadatas[$className] = $class; } @@ -57,7 +57,7 @@ protected function extractClassMetadata(array $classNames): array continue; } - $class = new ClassMetadataInfo($className); + $class = new ClassMetadata($className); $driver->loadMetadataForClass($className, $class); $metadatas[$className] = $class; } diff --git a/tests/Doctrine/Tests/ORM/Functional/Locking/LockTest.php b/tests/Doctrine/Tests/ORM/Functional/Locking/LockTest.php index 4629d6a621f..c9fd63344c9 100644 --- a/tests/Doctrine/Tests/ORM/Functional/Locking/LockTest.php +++ b/tests/Doctrine/Tests/ORM/Functional/Locking/LockTest.php @@ -23,8 +23,6 @@ protected function setUp(): void { $this->useModelSet('cms'); parent::setUp(); - - $this->handles = []; } /** diff --git a/tests/Doctrine/Tests/ORM/Functional/ReferenceProxyTest.php b/tests/Doctrine/Tests/ORM/Functional/ReferenceProxyTest.php index 2a852c34eea..604c432b2af 100644 --- a/tests/Doctrine/Tests/ORM/Functional/ReferenceProxyTest.php +++ b/tests/Doctrine/Tests/ORM/Functional/ReferenceProxyTest.php @@ -5,7 +5,6 @@ namespace Doctrine\Tests\ORM\Functional; use Doctrine\Common\Util\ClassUtils; -use Doctrine\ORM\Proxy\ProxyFactory; use Doctrine\Persistence\Proxy; use Doctrine\Tests\Models\Company\CompanyAuction; use Doctrine\Tests\Models\ECommerce\ECommerceProduct; @@ -31,12 +30,6 @@ protected function setUp(): void $this->useModelSet('ecommerce'); $this->useModelSet('company'); parent::setUp(); - $this->_factory = new ProxyFactory( - $this->_em, - __DIR__ . '/../../Proxies', - 'Doctrine\Tests\Proxies', - true - ); } public function createProduct(): int diff --git a/tests/Doctrine/Tests/ORM/Functional/SchemaTool/DBAL483Test.php b/tests/Doctrine/Tests/ORM/Functional/SchemaTool/DBAL483Test.php index 58795181f19..908ca790298 100644 --- a/tests/Doctrine/Tests/ORM/Functional/SchemaTool/DBAL483Test.php +++ b/tests/Doctrine/Tests/ORM/Functional/SchemaTool/DBAL483Test.php @@ -16,6 +16,9 @@ class DBAL483Test extends OrmFunctionalTestCase { + /** @var Tools\SchemaTool */ + private $schemaTool; + protected function setUp(): void { parent::setUp(); diff --git a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1163Test.php b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1163Test.php index a856df3935c..9ea3d883469 100644 --- a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1163Test.php +++ b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1163Test.php @@ -26,6 +26,12 @@ */ class DDC1163Test extends OrmFunctionalTestCase { + /** @var int|null */ + private $productId; + + /** @var int|null */ + private $proxyHolderId; + protected function setUp(): void { parent::setUp(); diff --git a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1193Test.php b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1193Test.php index e9e9b108f31..fb8fa3b1a94 100644 --- a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1193Test.php +++ b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1193Test.php @@ -38,16 +38,12 @@ public function testIssue(): void $account = new DDC1193Account(); $person->account = $account; - $person->company = $company; - $company->member = $person; $this->_em->persist($company); - $this->_em->flush(); $companyId = $company->id; - $accountId = $account->id; $this->_em->clear(); $company = $this->_em->find(get_class($company), $companyId); diff --git a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1301Test.php b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1301Test.php index cbea3508ee7..1fa7f783dd5 100644 --- a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1301Test.php +++ b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1301Test.php @@ -90,17 +90,14 @@ public function loadFixture(): void $user1 = new Models\Legacy\LegacyUser(); $user1->username = 'beberlei'; $user1->name = 'Benjamin'; - $user1->_status = 'active'; $user2 = new Models\Legacy\LegacyUser(); $user2->username = 'jwage'; $user2->name = 'Jonathan'; - $user2->_status = 'active'; $user3 = new Models\Legacy\LegacyUser(); $user3->username = 'romanb'; $user3->name = 'Roman'; - $user3->_status = 'active'; $this->_em->persist($user1); $this->_em->persist($user2); diff --git a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1885Test.php b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1885Test.php index 8ee1d7b7110..678783188de 100644 --- a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1885Test.php +++ b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1885Test.php @@ -25,7 +25,6 @@ protected function setUp(): void $user = new User(); $user->name = 'FabioBatSilva'; - $user->email = 'fabio.bat.silva@gmail.com'; $user->groups[] = new Group('G 1'); $user->groups[] = new Group('G 2'); $this->user = $user; diff --git a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC2519Test.php b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC2519Test.php index 0af5d161883..dab55094320 100644 --- a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC2519Test.php +++ b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC2519Test.php @@ -60,17 +60,14 @@ public function loadFixture(): void $user1 = new LegacyUser(); $user1->username = 'FabioBatSilva'; $user1->name = 'Fabio B. Silva'; - $user1->_status = 'active'; $user2 = new LegacyUser(); $user2->username = 'doctrinebot'; $user2->name = 'Doctrine Bot'; - $user2->_status = 'active'; $user3 = new LegacyUser(); $user3->username = 'test'; $user3->name = 'Tester'; - $user3->_status = 'active'; $this->_em->persist($user1); $this->_em->persist($user2); diff --git a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC522Test.php b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC522Test.php index 769bcfc701d..8fb713ecb4d 100644 --- a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC522Test.php +++ b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC522Test.php @@ -77,7 +77,6 @@ public function testJoinColumnWithSameNameAsAssociationField(): void public function testJoinColumnWithNullSameNameAssociationField(): void { $fkCust = new DDC522ForeignKeyTest(); - $fkCust->name = 'name'; $fkCust->cart = null; $this->_em->persist($fkCust); @@ -153,13 +152,13 @@ class DDC522ForeignKeyTest public $id; /** - * @var int + * @var int|null * @Column(type="integer", name="cart_id", nullable=true) */ public $cartId; /** - * @var DDC522Cart + * @var DDC522Cart|null * @OneToOne(targetEntity="DDC522Cart") * @JoinColumn(name="cart_id", referencedColumnName="id") */ diff --git a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC69Test.php b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC69Test.php index 03ed9d6f08d..52f0cf6c55e 100644 --- a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC69Test.php +++ b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC69Test.php @@ -135,7 +135,6 @@ class Lemma public function __construct() { - $this->types = new ArrayCollection(); $this->relations = new ArrayCollection(); } diff --git a/tests/Doctrine/Tests/ORM/Functional/Ticket/Ticket2481Test.php b/tests/Doctrine/Tests/ORM/Functional/Ticket/Ticket2481Test.php index 025fb03881b..8fb3b0c245c 100644 --- a/tests/Doctrine/Tests/ORM/Functional/Ticket/Ticket2481Test.php +++ b/tests/Doctrine/Tests/ORM/Functional/Ticket/Ticket2481Test.php @@ -20,8 +20,6 @@ protected function setUp(): void $this->_schemaTool->createSchema([ $this->_em->getClassMetadata(Ticket2481Product::class), ]); - - $this->_conn = $this->_em->getConnection(); } public function testEmptyInsert(): void diff --git a/tests/Doctrine/Tests/ORM/Mapping/AbstractMappingDriverTest.php b/tests/Doctrine/Tests/ORM/Mapping/AbstractMappingDriverTest.php index 97bd251ec4f..995b20039aa 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/AbstractMappingDriverTest.php +++ b/tests/Doctrine/Tests/ORM/Mapping/AbstractMappingDriverTest.php @@ -1788,3 +1788,11 @@ public static function loadMetadata(ClassMetadataInfo $metadata): void ); } } + +class UserIncorrectAttributes extends User +{ +} + +class UserMissingAttributes extends User +{ +} diff --git a/tests/Doctrine/Tests/ORM/Mapping/Symfony/AbstractDriverTest.php b/tests/Doctrine/Tests/ORM/Mapping/Symfony/AbstractDriverTest.php index cfc5ab1a913..774cd80d482 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/Symfony/AbstractDriverTest.php +++ b/tests/Doctrine/Tests/ORM/Mapping/Symfony/AbstractDriverTest.php @@ -21,6 +21,9 @@ */ abstract class AbstractDriverTest extends TestCase { + /** @var string */ + private $dir; + public function testFindMappingFile(): void { $driver = $this->getDriver( diff --git a/tests/Doctrine/Tests/ORM/Mapping/XmlMappingDriverTest.php b/tests/Doctrine/Tests/ORM/Mapping/XmlMappingDriverTest.php index 96e0deaf63d..a9da33e1e49 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/XmlMappingDriverTest.php +++ b/tests/Doctrine/Tests/ORM/Mapping/XmlMappingDriverTest.php @@ -9,35 +9,34 @@ use Doctrine\ORM\Mapping\ClassMetadata; use Doctrine\ORM\Mapping\ClassMetadataFactory; use Doctrine\ORM\Mapping\Driver\XmlDriver; +use Doctrine\ORM\Mapping\MappingException; use Doctrine\Persistence\Mapping\Driver\MappingDriver; use Doctrine\Persistence\Mapping\RuntimeReflectionService; use Doctrine\Tests\Models\DDC117\DDC117Translation; use Doctrine\Tests\Models\DDC3293\DDC3293User; use Doctrine\Tests\Models\DDC3293\DDC3293UserPrefixed; use Doctrine\Tests\Models\DDC889\DDC889Class; +use Doctrine\Tests\Models\DDC889\DDC889Entity; +use Doctrine\Tests\Models\DDC889\DDC889SuperClass; use Doctrine\Tests\Models\Generic\SerializationModel; use Doctrine\Tests\Models\GH7141\GH7141Article; use Doctrine\Tests\Models\GH7316\GH7316Article; use Doctrine\Tests\Models\ValueObjects\Name; use Doctrine\Tests\Models\ValueObjects\Person; -use DOMDocument; -use function array_filter; -use function array_map; -use function assert; -use function glob; -use function in_array; -use function is_array; -use function pathinfo; +use function substr_count; use const DIRECTORY_SEPARATOR; -use const PATHINFO_FILENAME; class XmlMappingDriverTest extends AbstractMappingDriverTest { protected function loadDriver(): MappingDriver { - return new XmlDriver(__DIR__ . DIRECTORY_SEPARATOR . 'xml'); + return new XmlDriver( + __DIR__ . DIRECTORY_SEPARATOR . 'xml', + XmlDriver::DEFAULT_FILE_EXTENSION, + true + ); } public function testClassTableInheritanceDiscriminatorMap(): void @@ -163,32 +162,89 @@ public function testInvalidMappingFileException(): void * @dataProvider dataValidSchema * @group DDC-2429 */ - public function testValidateXmlSchema(string $xmlMappingFile): void - { - $xsdSchemaFile = __DIR__ . '/../../../../../doctrine-mapping.xsd'; - $dom = new DOMDocument(); - - $dom->load($xmlMappingFile); - - self::assertTrue($dom->schemaValidate($xsdSchemaFile)); + public function testValidateXmlSchema( + string $class, + string $tableName, + array $fieldNames, + array $associationNames + ): void { + $metadata = $this->createClassMetadata($class); + + $this->assertInstanceOf(ClassMetadata::class, $metadata); + $this->assertEquals($metadata->getTableName(), $tableName); + $this->assertEquals($metadata->getFieldNames(), $fieldNames); + $this->assertEquals($metadata->getAssociationNames(), $associationNames); } /** - * @psalm-return list + * @psalm-return []array{0: class-string, 1: string, 2: list, 3: list} */ public static function dataValidSchema(): array { - $list = glob(__DIR__ . '/xml/*.xml'); - $invalid = ['Doctrine.Tests.Models.DDC889.DDC889Class.dcm']; - assert(is_array($list)); + return [ + [ + User::class, + 'cms_users', + ['name', 'email', 'version', 'id'], + ['address', 'phonenumbers', 'groups'], + ], + [ + DDC889Entity::class, + 'DDC889Entity', + [], + [], + ], + [ + DDC889SuperClass::class, + 'DDC889SuperClass', + ['name'], + [], + ], + ]; + } - $list = array_filter($list, static function (string $item) use ($invalid): bool { - return ! in_array(pathinfo($item, PATHINFO_FILENAME), $invalid, true); - }); + /** + * @param class-string $class + * @param non-empty-array $expectedExceptionOccurrences + * + * @dataProvider dataInvalidSchema + */ + public function testValidateIncorrectXmlSchema(string $class, array $expectedExceptionOccurrences): void + { + try { + $this->createClassMetadata($class); + + $this->fail('XML schema validation should throw a MappingException'); + } catch (MappingException $exception) { + foreach ($expectedExceptionOccurrences as $exceptionContent => $occurrencesCount) { + $this->assertEquals($occurrencesCount, substr_count($exception->getMessage(), $exceptionContent)); + } + } + } - return array_map(static function (string $item) { - return [$item]; - }, $list); + /** + * @return non-empty-list}> + */ + public static function dataInvalidSchema(): array + { + return [ + [ + DDC889Class::class, + ['This element is not expected' => 1], + ], + [ + UserIncorrectAttributes::class, + [ + 'attribute \'field\': The attribute \'field\' is not allowed' => 2, + 'The attribute \'name\' is required but missing' => 2, + 'attribute \'fieldName\': The attribute \'fieldName\' is not allowed' => 1, + ], + ], + [ + UserMissingAttributes::class, + ['The attribute \'name\' is required but missing' => 1], + ], + ]; } /** @@ -225,10 +281,11 @@ public function testManyToManyDefaultOrderByAsc(): void /** * @group DDC-889 */ - public function testinvalidEntityOrMappedSuperClassShouldMentionParentClasses(): void + public function testInvalidEntityOrMappedSuperClassShouldMentionParentClasses(): void { - $this->expectException('Doctrine\Persistence\Mapping\MappingException'); - $this->expectExceptionMessage('Invalid mapping file \'Doctrine.Tests.Models.DDC889.DDC889Class.dcm.xml\' for class \'Doctrine\Tests\Models\DDC889\DDC889Class\'.'); + $this->expectException(MappingException::class); + $this->expectExceptionMessage('libxml error: Element \'{http://doctrine-project.org/schemas/orm/doctrine-mapping}class\': This element is not expected.'); + $this->createClassMetadata(DDC889Class::class); } } diff --git a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC889.DDC889Class.dcm.xml b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC889.DDC889Class.dcm.xml index ea069f8eb4e..0b8a163c7f8 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC889.DDC889Class.dcm.xml +++ b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC889.DDC889Class.dcm.xml @@ -1,7 +1,7 @@ @@ -9,5 +9,5 @@ - - + + \ No newline at end of file diff --git a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC889.DDC889Entity.dcm.xml b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC889.DDC889Entity.dcm.xml index 7fc72bb0ea6..a1de4ea2c40 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC889.DDC889Entity.dcm.xml +++ b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC889.DDC889Entity.dcm.xml @@ -1,10 +1,10 @@ - + diff --git a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC889.DDC889SuperClass.dcm.xml b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC889.DDC889SuperClass.dcm.xml index c204e8651d5..6d03f391948 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC889.DDC889SuperClass.dcm.xml +++ b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC889.DDC889SuperClass.dcm.xml @@ -1,11 +1,11 @@ - + diff --git a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.ORM.Mapping.UserIncorrectAttributes.dcm.xml b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.ORM.Mapping.UserIncorrectAttributes.dcm.xml new file mode 100644 index 00000000000..f486dd9aedd --- /dev/null +++ b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.ORM.Mapping.UserIncorrectAttributes.dcm.xml @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.ORM.Mapping.UserMissingAttributes.dcm.xml b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.ORM.Mapping.UserMissingAttributes.dcm.xml new file mode 100644 index 00000000000..d736fa080fc --- /dev/null +++ b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.ORM.Mapping.UserMissingAttributes.dcm.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + diff --git a/tests/Doctrine/Tests/ORM/UnitOfWorkTest.php b/tests/Doctrine/Tests/ORM/UnitOfWorkTest.php index 84e9f064eb3..a180b26d3bc 100644 --- a/tests/Doctrine/Tests/ORM/UnitOfWorkTest.php +++ b/tests/Doctrine/Tests/ORM/UnitOfWorkTest.php @@ -491,8 +491,8 @@ public function testNewAssociatedEntityPersistenceOfNewEntitiesThroughCascadedAs // the cascading association not set. Having the "cascading path" involve // a non-new object is important to show that the ORM should be considering // cascades across entity changesets in subsequent flushes. - $cascading->cascaded = $cascadePersisted; - $nonCascading->cascaded = $cascadePersisted; + $cascading->cascaded = $cascadePersisted; + $nonCascading->nonCascaded = $cascadePersisted; $this->_unitOfWork->persist($cascading); $this->_unitOfWork->persist($nonCascading); @@ -861,7 +861,7 @@ class EntityWithCascadingAssociation private $id; /** - * @var CascadePersistedEntity + * @var CascadePersistedEntity|null * @ManyToOne(targetEntity=CascadePersistedEntity::class, cascade={"persist"}) */ public $cascaded; @@ -884,7 +884,7 @@ class EntityWithNonCascadingAssociation private $id; /** - * @var CascadePersistedEntity + * @var CascadePersistedEntity|null * @ManyToOne(targetEntity=CascadePersistedEntity::class) */ public $nonCascaded;