@@ -291,15 +291,6 @@ public function loadMetadataForClass(string $className, PersistenceClassMetadata
291291 );
292292 }
293293
294- // Check for JoinColumn/JoinColumns attributes
295- $ joinColumns = [];
296-
297- $ joinColumnAttributes = $ this ->reader ->getPropertyAttributeCollection ($ property , Mapping \JoinColumn::class);
298-
299- foreach ($ joinColumnAttributes as $ joinColumnAttribute ) {
300- $ joinColumns [] = $ this ->joinColumnToArray ($ joinColumnAttribute );
301- }
302-
303294 // Field can only be attributed with one of:
304295 // Column, OneToOne, OneToMany, ManyToOne, ManyToMany, Embedded
305296 $ columnAttribute = $ this ->reader ->getPropertyAttribute ($ property , Mapping \Column::class);
@@ -309,8 +300,18 @@ public function loadMetadataForClass(string $className, PersistenceClassMetadata
309300 $ manyToManyAttribute = $ this ->reader ->getPropertyAttribute ($ property , Mapping \ManyToMany::class);
310301 $ embeddedAttribute = $ this ->reader ->getPropertyAttribute ($ property , Mapping \Embedded::class);
311302
303+ // Check for JoinColumn/JoinColumns attributes
304+ $ joinColumns = [];
305+
306+ $ joinColumnAttributes = $ this ->reader ->getPropertyAttributeCollection ($ property , Mapping \JoinColumn::class);
307+
308+ foreach ($ joinColumnAttributes as $ joinColumnAttribute ) {
309+ $ joinColumns [] = $ this ->joinColumnToArray ($ joinColumnAttribute , $ metadata ->inferNullabilityFromPHPType && (
310+ $ oneToOneAttribute !== null || $ manyToOneAttribute !== null ));
311+ }
312+
312313 if ($ columnAttribute !== null ) {
313- $ mapping = $ this ->columnToArray ($ property ->name , $ columnAttribute );
314+ $ mapping = $ this ->columnToArray ($ property ->name , $ columnAttribute, $ metadata -> inferNullabilityFromPHPType );
314315
315316 if ($ this ->reader ->getPropertyAttribute ($ property , Mapping \Id::class)) {
316317 $ mapping ['id ' ] = true ;
@@ -473,10 +474,12 @@ public function loadMetadataForClass(string $className, PersistenceClassMetadata
473474
474475 // Check for JoinColumn/JoinColumns attributes
475476 if ($ associationOverride ->joinColumns ) {
476- $ joinColumns = [];
477+ $ inferNullabilityFromPHPType = $ metadata ->inferNullabilityFromPHPType && isset ($ metadata ->associationMappings [$ fieldName ])
478+ && $ metadata ->associationMappings [$ fieldName ]['type ' ] & ClassMetadata::TO_ONE ;
477479
480+ $ joinColumns = [];
478481 foreach ($ associationOverride ->joinColumns as $ joinColumn ) {
479- $ joinColumns [] = $ this ->joinColumnToArray ($ joinColumn );
482+ $ joinColumns [] = $ this ->joinColumnToArray ($ joinColumn, $ inferNullabilityFromPHPType );
480483 }
481484
482485 $ override ['joinColumns ' ] = $ joinColumns ;
@@ -530,7 +533,7 @@ public function loadMetadataForClass(string $className, PersistenceClassMetadata
530533 $ attributeOverridesAnnot = $ classAttributes [Mapping \AttributeOverrides::class];
531534
532535 foreach ($ attributeOverridesAnnot ->overrides as $ attributeOverride ) {
533- $ mapping = $ this ->columnToArray ($ attributeOverride ->name , $ attributeOverride ->column );
536+ $ mapping = $ this ->columnToArray ($ attributeOverride ->name , $ attributeOverride ->column , $ metadata -> inferNullabilityFromPHPType );
534537
535538 $ metadata ->setAttributeOverride ($ attributeOverride ->name , $ mapping );
536539 }
@@ -673,25 +676,28 @@ private function getMethodCallbacks(ReflectionMethod $method): array
673676 * @phpstan-return array{
674677 * name: string|null,
675678 * unique: bool,
676- * nullable: bool,
679+ * nullable? : bool,
677680 * onDelete: mixed,
678681 * columnDefinition: string|null,
679682 * referencedColumnName: string,
680683 * options?: array<string, mixed>
681684 * }
682685 */
683- private function joinColumnToArray (Mapping \JoinColumn |Mapping \InverseJoinColumn $ joinColumn ): array
686+ private function joinColumnToArray (Mapping \JoinColumn |Mapping \InverseJoinColumn $ joinColumn, bool $ inferNullabilityFromPHPType = false ): array
684687 {
685688 $ mapping = [
686689 'name ' => $ joinColumn ->name ,
687690 'deferrable ' => $ joinColumn ->deferrable ,
688691 'unique ' => $ joinColumn ->unique ,
689- 'nullable ' => $ joinColumn ->nullable ,
690692 'onDelete ' => $ joinColumn ->onDelete ,
691693 'columnDefinition ' => $ joinColumn ->columnDefinition ,
692694 'referencedColumnName ' => $ joinColumn ->referencedColumnName ,
693695 ];
694696
697+ if (! $ inferNullabilityFromPHPType || $ joinColumn ->nullableSet ) {
698+ $ mapping ['nullable ' ] = $ joinColumn ->nullable ;
699+ }
700+
695701 if ($ joinColumn ->options ) {
696702 $ mapping ['options ' ] = $ joinColumn ->options ;
697703 }
@@ -709,26 +715,29 @@ private function joinColumnToArray(Mapping\JoinColumn|Mapping\InverseJoinColumn
709715 * scale: int,
710716 * length: int,
711717 * unique: bool,
712- * nullable: bool,
718+ * nullable? : bool|null ,
713719 * precision: int,
714720 * enumType?: class-string,
715721 * options?: mixed[],
716722 * columnName?: string,
717723 * columnDefinition?: string
718724 * }
719725 */
720- private function columnToArray (string $ fieldName , Mapping \Column $ column ): array
726+ private function columnToArray (string $ fieldName , Mapping \Column $ column, bool $ inferNullabilityFromPHPType = false ): array
721727 {
722728 $ mapping = [
723729 'fieldName ' => $ fieldName ,
724730 'type ' => $ column ->type ,
725731 'scale ' => $ column ->scale ,
726732 'length ' => $ column ->length ,
727733 'unique ' => $ column ->unique ,
728- 'nullable ' => $ column ->nullable ,
729734 'precision ' => $ column ->precision ,
730735 ];
731736
737+ if (! $ inferNullabilityFromPHPType || $ column ->nullableSet ) {
738+ $ mapping ['nullable ' ] = $ column ->nullable ;
739+ }
740+
732741 if ($ column ->options ) {
733742 $ mapping ['options ' ] = $ column ->options ;
734743 }
0 commit comments