diff --git a/lib/Doctrine/ORM/Mapping/Builder/FieldBuilder.php b/lib/Doctrine/ORM/Mapping/Builder/FieldBuilder.php index 743e63a9748..41729bd5c0a 100644 --- a/lib/Doctrine/ORM/Mapping/Builder/FieldBuilder.php +++ b/lib/Doctrine/ORM/Mapping/Builder/FieldBuilder.php @@ -119,7 +119,9 @@ public function precision($p) */ public function insertable($flag = true) { - $this->mapping['insertable'] = (bool) $flag; + if (! (bool) $flag) { + $this->mapping['notInsertable'] = true; + } return $this; } @@ -133,7 +135,9 @@ public function insertable($flag = true) */ public function updateable($flag = true) { - $this->mapping['updateable'] = (bool) $flag; + if (! (bool) $flag) { + $this->mapping['notUpdateable'] = true; + } return $this; } diff --git a/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php b/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php index f7819a3a4c8..bb6daf25be7 100644 --- a/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php +++ b/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php @@ -413,11 +413,11 @@ class ClassMetadataInfo implements ClassMetadata * - nullable (boolean, optional) * Whether the column is nullable. Defaults to FALSE. * - * - 'insertable' (boolean, optional) - * Whether the column is insertable. Defaults to TRUE. + * - 'notInsertable' (boolean, optional) + * Whether the column is not insertable. Optional. Is only set if value is TRUE. * - * - 'updateable' (boolean, optional) - * Whether the column is updateable. Defaults to TRUE. + * - 'notUpdateable' (boolean, optional) + * Whether the column is updateable. Optional. Is only set if value is TRUE. * * - columnDefinition (string, optional, schema-only) * The SQL fragment that is used when generating the DDL for the column. @@ -439,8 +439,8 @@ class ClassMetadataInfo implements ClassMetadata * length?: int, * id?: bool, * nullable?: bool, - * insertable?: bool, - * updateable?: bool, + * notInsertable?: bool, + * notUpdateable?: bool, * columnDefinition?: string, * precision?: int, * scale?: int, @@ -1268,13 +1268,13 @@ public function isNullable($fieldName) * * @param string $fieldName The field name. * - * @return bool TRUE if the field is not null, FALSE otherwise. + * @return bool TRUE if the field is insertable, FALSE otherwise. */ public function isInsertable($fieldName) { $mapping = $this->getFieldMapping($fieldName); - return $mapping !== false && isset($mapping['insertable']) && $mapping['insertable']; + return ! isset($mapping['notInsertable']); } /** @@ -1282,13 +1282,13 @@ public function isInsertable($fieldName) * * @param string $fieldName The field name. * - * @return bool TRUE if the field is not null, FALSE otherwise. + * @return bool TRUE if the field is updateable, FALSE otherwise. */ public function isUpdateable($fieldName) { $mapping = $this->getFieldMapping($fieldName); - return $mapping !== false && isset($mapping['updateable']) && $mapping['updateable']; + return ! isset($mapping['notUpdateable']); } /** @@ -1318,8 +1318,8 @@ public function getColumnName($fieldName) * columnName?: string, * inherited?: class-string, * nullable?: bool, - * insertable?: bool, - * updateable?: bool, + * notInsertable?: bool, + * notUpdateable?: bool, * originalClass?: class-string, * originalField?: string, * scale?: int, diff --git a/lib/Doctrine/ORM/Mapping/Column.php b/lib/Doctrine/ORM/Mapping/Column.php index 172bc0d2c6b..208f04b5358 100644 --- a/lib/Doctrine/ORM/Mapping/Column.php +++ b/lib/Doctrine/ORM/Mapping/Column.php @@ -67,8 +67,8 @@ public function __construct( ?int $scale = null, bool $unique = false, bool $nullable = false, - ?bool $insertable = true, - ?bool $updateable = true, + bool $insertable = true, + bool $updateable = true, array $options = [], ?string $columnDefinition = null ) { diff --git a/lib/Doctrine/ORM/Mapping/Driver/AnnotationDriver.php b/lib/Doctrine/ORM/Mapping/Driver/AnnotationDriver.php index 8ef72f92fff..0166b0df3dc 100644 --- a/lib/Doctrine/ORM/Mapping/Driver/AnnotationDriver.php +++ b/lib/Doctrine/ORM/Mapping/Driver/AnnotationDriver.php @@ -720,8 +720,8 @@ private function joinColumnToArray(Mapping\JoinColumn $joinColumn): array * unique: bool, * nullable: bool, * precision: int, - * insertable?: bool, - * updateble?: bool, + * notInsertable?: bool, + * notUpdateble?: bool, * options?: mixed[], * columnName?: string, * columnDefinition?: string @@ -739,12 +739,12 @@ private function columnToArray(string $fieldName, Mapping\Column $column): array 'precision' => $column->precision, ]; - if ($column->insertable) { - $mapping['insertable'] = $column->insertable; + if (! $column->insertable) { + $mapping['notInsertable'] = true; } - if ($column->updateable) { - $mapping['updateable'] = $column->updateable; + if (! $column->updateable) { + $mapping['notUpdateable'] = true; } if ($column->options) { diff --git a/lib/Doctrine/ORM/Mapping/Driver/XmlDriver.php b/lib/Doctrine/ORM/Mapping/Driver/XmlDriver.php index 262e88eaca8..d89dad0de3f 100644 --- a/lib/Doctrine/ORM/Mapping/Driver/XmlDriver.php +++ b/lib/Doctrine/ORM/Mapping/Driver/XmlDriver.php @@ -800,8 +800,8 @@ private function joinColumnToArray(SimpleXMLElement $joinColumnElement): array * scale?: int, * unique?: bool, * nullable?: bool, - * insertable?: bool, - * updateable?: bool, + * notInsertable?: bool, + * notUpdateable?: bool, * version?: bool, * columnDefinition?: string, * options?: array @@ -841,12 +841,12 @@ private function columnToArray(SimpleXMLElement $fieldMapping): array $mapping['nullable'] = $this->evaluateBoolean($fieldMapping['nullable']); } - if (isset($fieldMapping['insertable'])) { - $mapping['insertable'] = $this->evaluateBoolean($fieldMapping['insertable']); + if (isset($fieldMapping['insertable']) && ! $this->evaluateBoolean($fieldMapping['insertable'])) { + $mapping['notInsertable'] = true; } - if (isset($fieldMapping['updateable'])) { - $mapping['updateable'] = $this->evaluateBoolean($fieldMapping['updateable']); + if (isset($fieldMapping['updateable']) && ! $this->evaluateBoolean($fieldMapping['updateable'])) { + $mapping['notUpdateable'] = true; } if (isset($fieldMapping['version']) && $fieldMapping['version']) { diff --git a/lib/Doctrine/ORM/Mapping/Driver/YamlDriver.php b/lib/Doctrine/ORM/Mapping/Driver/YamlDriver.php index 166e19816aa..aecd071e43e 100644 --- a/lib/Doctrine/ORM/Mapping/Driver/YamlDriver.php +++ b/lib/Doctrine/ORM/Mapping/Driver/YamlDriver.php @@ -803,8 +803,8 @@ private function joinColumnToArray(array $joinColumnElement): array * unique?: bool, * options?: mixed, * nullable?: mixed, - * insertable?: mixed, - * updateable?: mixed, + * notInsertable?: mixed, + * notUpdateable?: mixed, * version?: mixed, * columnDefinition?: mixed * } @@ -852,12 +852,12 @@ private function columnToArray(string $fieldName, ?array $column): array $mapping['nullable'] = $column['nullable']; } - if (isset($column['insertable'])) { - $mapping['insertable'] = $column['insertable']; + if (isset($column['insertable']) && ! (bool) $column['insertable']) { + $mapping['notInsertable'] = true; } - if (isset($column['updateable'])) { - $mapping['updateable'] = $column['updateable']; + if (isset($column['updateable']) && ! (bool) $column['updateable']) { + $mapping['notUpdateable'] = true; } if (isset($column['version']) && $column['version']) { diff --git a/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php b/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php index a46c97a439a..9af968e956c 100644 --- a/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php +++ b/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php @@ -597,12 +597,13 @@ public function delete($entity) * ) * * - * @param object $entity The entity for which to prepare the data. + * @param object $entity The entity for which to prepare the data. + * @param bool $isInsert Whether the data to be prepared refers to an insert statement. * * @return mixed[][] The prepared data. * @psalm-return array> */ - protected function prepareUpdateData($entity) + protected function prepareUpdateData($entity, $isInsert = false) { $versionField = null; $result = []; @@ -628,8 +629,7 @@ protected function prepareUpdateData($entity) $fieldMapping = $this->class->fieldMappings[$field]; $columnName = $fieldMapping['columnName']; - $isInsert = ! empty($this->queuedInserts[spl_object_id($entity)]); - if (! $isInsert && ! $this->class->isUpdateable($field)) { + if (! $isInsert && isset($fieldMapping['notUpdateable'])) { if ($change[0] !== $change[1]) { throw NonUpdateableField::byName($field); } @@ -637,7 +637,7 @@ protected function prepareUpdateData($entity) continue; } - if ($isInsert && ! $this->class->isInsertable($field)) { + if ($isInsert && isset($fieldMapping['notInsertable'])) { continue; } @@ -708,7 +708,7 @@ protected function prepareUpdateData($entity) */ protected function prepareInsertData($entity) { - return $this->prepareUpdateData($entity); + return $this->prepareUpdateData($entity, true); } /** diff --git a/lib/Doctrine/ORM/Tools/Export/Driver/XmlExporter.php b/lib/Doctrine/ORM/Tools/Export/Driver/XmlExporter.php index 783d9a5a5fc..4b75d71784c 100644 --- a/lib/Doctrine/ORM/Tools/Export/Driver/XmlExporter.php +++ b/lib/Doctrine/ORM/Tools/Export/Driver/XmlExporter.php @@ -219,12 +219,12 @@ public function exportClassMetadata(ClassMetadataInfo $metadata) $fieldXml->addAttribute('nullable', $field['nullable'] ? 'true' : 'false'); } - if (isset($field['insertable'])) { - $fieldXml->addAttribute('insertable', $field['insertable'] ? 'true' : 'false'); + if (isset($field['notInsertable'])) { + $fieldXml->addAttribute('insertable', 'false'); } - if (isset($field['updateable'])) { - $fieldXml->addAttribute('updateable', $field['updateable'] ? 'true' : 'false'); + if (isset($field['notUpdateable'])) { + $fieldXml->addAttribute('updateable', 'false'); } } } diff --git a/tests/Doctrine/Tests/ORM/Persisters/BasicEntityPersisterUpsertableTest.php b/tests/Doctrine/Tests/ORM/Persisters/BasicEntityPersisterUpsertableTest.php index bd673eac360..dd10b7053c6 100644 --- a/tests/Doctrine/Tests/ORM/Persisters/BasicEntityPersisterUpsertableTest.php +++ b/tests/Doctrine/Tests/ORM/Persisters/BasicEntityPersisterUpsertableTest.php @@ -29,8 +29,8 @@ protected function setUp(): void public function testInsertSQLUsesInsertableColumns(): void { - $persister = new BasicEntityPersister($this->entityManager, $this->entityManager->getClassMetadata(Insertable::class)); - $method = new ReflectionMethod($persister, 'getInsertSQL'); + $persister = new BasicEntityPersister($this->entityManager, $this->entityManager->getClassMetadata(Insertable::class)); + $method = new ReflectionMethod($persister, 'getInsertSQL'); $method->setAccessible(true); self::assertEquals('INSERT INTO insertable_column (insertableContent, insertableContentDefault) VALUES (?, ?)', $method->invoke($persister)); @@ -38,13 +38,13 @@ public function testInsertSQLUsesInsertableColumns(): void public function testUpdateSQLUsesUpdateableColumns(): void { - $persister = new BasicEntityPersister($this->entityManager, $this->entityManager->getClassMetadata(Updateable::class)); + $persister = new BasicEntityPersister($this->entityManager, $this->entityManager->getClassMetadata(Updateable::class)); - $entity = new Updateable(); - $entity->id = 1; - $entity->nonUpdateableContent = 'non-persistable'; - $entity->updateableContent = 'persistable'; - $entity->updateableContentDefault = 'persistable'; + $entity = new Updateable(); + $entity->id = 1; + $entity->nonUpdateableContent = 'non-persistable'; + $entity->updateableContent = 'persistable'; + $entity->updateableContentDefault = 'persistable'; $this->entityManager->getUnitOfWork()->registerManaged($entity, ['id' => 1], ['nonUpdateableContent' => 'default', 'updateableContent' => 'default', 'updateableContentDefault' => 'default']); @@ -63,12 +63,12 @@ public function testExceptionIsThrownWhenTryingToChangeNonUpdateableColumn(): vo { $this->expectException(NonUpdateableField::class); - $persister = new BasicEntityPersister($this->entityManager, $this->entityManager->getClassMetadata(Updateable::class)); + $persister = new BasicEntityPersister($this->entityManager, $this->entityManager->getClassMetadata(Updateable::class)); - $entity = new Updateable(); - $entity->nonUpdateableContent = 'non-persistable'; - $entity->updateableContent = 'persistable'; - $entity->updateableContentDefault = 'persistable'; + $entity = new Updateable(); + $entity->nonUpdateableContent = 'non-persistable'; + $entity->updateableContent = 'persistable'; + $entity->updateableContentDefault = 'persistable'; $this->entityManager->getUnitOfWork()->registerManaged($entity, ['id' => 1], ['nonUpdateableContent' => 'default', 'updateableContent' => 'default', 'updateableContentDefault' => 'default']);