diff --git a/src/Maker/MakeEntity.php b/src/Maker/MakeEntity.php index 71bfd3b2f..4dfdcb176 100644 --- a/src/Maker/MakeEntity.php +++ b/src/Maker/MakeEntity.php @@ -235,12 +235,6 @@ public function generate(InputInterface $input, ConsoleStyle $io, Generator $gen // save the inverse side if it's being mapped if ($newField->getMapInverseRelation()) { $fileManagerOperations[$otherManipulatorFilename] = $otherManipulator; - } else { - // print message about it not being saved - $fileManagerOperations[] = sprintf( - 'The inverse side of the relation was not mapped in "%s" because it lives in the vendor/ directory.', - $newField->getInverseClass() - ); } $currentFields[] = $newFieldName; } else { @@ -554,8 +548,30 @@ function ($name) use ($targetClass) { return $io->confirm(sprintf('Do you want to automatically delete orphaned %s objects (orphanRemoval)?', $owningClass), false); }; - $setMapInverseSide = function (EntityRelation $relation) { - $relation->setMapInverseRelation(!$this->isClassInVendor($relation->getInverseClass())); + $askInverseSide = function (EntityRelation $relation) use ($io) { + if ($this->isClassInVendor($relation->getInverseClass())) { + $relation->setMapInverseRelation(false); + } + + // recommend an inverse side, except for OneToOne, where it's inefficient + $recommendMappingInverse = EntityRelation::ONE_TO_ONE === $relation->getType() ? false : true; + + $getterMethodName = 'get'.Str::asCamelCase(Str::getShortClassName($relation->getOwningClass())); + if (EntityRelation::ONE_TO_ONE !== $relation->getType()) { + // pluralize! + $getterMethodName = Str::singularCamelCaseToPluralCamelCase($getterMethodName); + } + $mapInverse = $io->confirm( + sprintf( + 'Do you want to add a new property to %s so that you can access/update %s objects from it - e.g. $%s->%s()?', + Str::getShortClassName($relation->getInverseClass()), + Str::getShortClassName($relation->getOwningClass()), + Str::asLowerCamelCase(Str::getShortClassName($relation->getInverseClass())), + $getterMethodName + ), + $recommendMappingInverse + ); + $relation->setMapInverseRelation($mapInverse); }; switch ($type) { @@ -572,7 +588,7 @@ function ($name) use ($targetClass) { $relation->getOwningClass() )); - $setMapInverseSide($relation); + $askInverseSide($relation); if ($relation->getMapInverseRelation()) { $io->comment(sprintf( 'A new property will also be added to the %s class so that you can access the related %s objects from it.', @@ -583,13 +599,14 @@ function ($name) use ($targetClass) { $relation->getInverseClass(), Str::singularCamelCaseToPluralCamelCase(Str::getShortClassName($relation->getOwningClass())) )); - } - if (!$relation->isNullable()) { - $relation->setOrphanRemoval($askOrphanRemoval( - $relation->getOwningClass(), - $relation->getInverseClass() - )); + // orphan removal only applies of the inverse relation is set + if (!$relation->isNullable()) { + $relation->setOrphanRemoval($askOrphanRemoval( + $relation->getOwningClass(), + $relation->getInverseClass() + )); + } } break; @@ -633,7 +650,7 @@ function ($name) use ($targetClass) { ); $relation->setOwningProperty($newFieldName); - $setMapInverseSide($relation); + $askInverseSide($relation); if ($relation->getMapInverseRelation()) { $io->comment(sprintf( 'A new property will also be added to the %s class so that you can access the related %s objects from it.', @@ -660,7 +677,7 @@ function ($name) use ($targetClass) { $relation->getOwningClass() )); - $setMapInverseSide($relation); + $askInverseSide($relation); if ($relation->getMapInverseRelation()) { $io->comment(sprintf( 'A new property will also be added to the %s class so that you can access the related %s object from it.', diff --git a/tests/Maker/FunctionalTest.php b/tests/Maker/FunctionalTest.php index 119431381..ec02275ff 100644 --- a/tests/Maker/FunctionalTest.php +++ b/tests/Maker/FunctionalTest.php @@ -206,6 +206,8 @@ public function getCommandTests() 'ManyToOne', // nullable 'n', + // do you want to generate an inverse relation? (default to yes) + '', // field name on opposite side - use default 'userAvatarPhotos' '', // orphanRemoval (default to no) @@ -218,6 +220,31 @@ public function getCommandTests() ->updateSchemaAfterCommand() ]; + yield 'entity_many_to_one_simple_no_inverse' => [MakerTestDetails::createTest( + $this->getMakerInstance(MakeEntity::class), + [ + // entity class name + 'UserAvatarPhoto', + // field name + 'user', + // add a relationship field + 'relation', + // the target entity + 'User', + // relation type + 'ManyToOne', + // nullable + 'n', + // do you want to generate an inverse relation? (default to yes) + 'n', + // finish adding fields + '' + ]) + ->setFixtureFilesPath(__DIR__.'/../fixtures/MakeEntityManyToOneNoInverse') + ->configureDatabase() + ->updateSchemaAfterCommand() + ]; + yield 'entity_one_to_many_simple' => [MakerTestDetails::createTest( $this->getMakerInstance(MakeEntity::class), [ @@ -231,6 +258,8 @@ public function getCommandTests() 'UserAvatarPhoto', // relation type 'OneToMany', + // inverse side? + 'y', // field name on opposite side - use default 'user' '', // nullable @@ -258,6 +287,8 @@ public function getCommandTests() 'User', // relation type 'ManyToMany', + // inverse side? + 'y', // field name on opposite side - use default 'courses' '', // finish adding fields @@ -283,6 +314,8 @@ public function getCommandTests() 'OneToOne', // nullable 'n', + // inverse side? + 'y', // field name on opposite side - use default 'userProfile' '', // finish adding fields @@ -310,8 +343,6 @@ public function getCommandTests() * normally, we ask for the field on the *other* side, but we * do not here, since the other side won't be mapped. */ - // orphanRemoval (default to no) - '', // finish adding fields '' ]) diff --git a/tests/fixtures/MakeEntityManyToOneNoInverse/src/Entity/User.php b/tests/fixtures/MakeEntityManyToOneNoInverse/src/Entity/User.php new file mode 100644 index 000000000..773668263 --- /dev/null +++ b/tests/fixtures/MakeEntityManyToOneNoInverse/src/Entity/User.php @@ -0,0 +1,23 @@ +id; + } +} diff --git a/tests/fixtures/MakeEntityManyToOneNoInverse/tests/GeneratedEntityTest.php b/tests/fixtures/MakeEntityManyToOneNoInverse/tests/GeneratedEntityTest.php new file mode 100644 index 000000000..6fe3f832a --- /dev/null +++ b/tests/fixtures/MakeEntityManyToOneNoInverse/tests/GeneratedEntityTest.php @@ -0,0 +1,36 @@ +getContainer() + ->get('doctrine') + ->getManager(); + + $em->createQuery('DELETE FROM App\\Entity\\User u')->execute(); + $em->createQuery('DELETE FROM App\\Entity\\UserAvatarPhoto u')->execute(); + + $user = new User(); + $em->persist($user); + + $photo = new UserAvatarPhoto(); + $photo->setUser($user); + $em->persist($photo); + + $em->flush(); + $em->refresh($photo); + + $this->assertSame($photo->getUser(), $user); + } +}