diff --git a/src/Security/UserClassBuilder.php b/src/Security/UserClassBuilder.php index 8a1e9fa09..261780368 100644 --- a/src/Security/UserClassBuilder.php +++ b/src/Security/UserClassBuilder.php @@ -12,6 +12,7 @@ namespace Symfony\Bundle\MakerBundle\Security; use PhpParser\Node; +use Symfony\Bundle\MakerBundle\Str; use Symfony\Bundle\MakerBundle\Util\ClassSource\Model\ClassProperty; use Symfony\Bundle\MakerBundle\Util\ClassSourceManipulator; use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface; @@ -28,6 +29,8 @@ public function addUserInterfaceImplementation(ClassSourceManipulator $manipulat { $manipulator->addInterface(UserInterface::class); + $this->addUniqueConstraint($manipulator, $userClassConfig); + $this->addGetUsername($manipulator, $userClassConfig); $this->addGetRoles($manipulator, $userClassConfig); @@ -57,7 +60,6 @@ private function addGetUsername(ClassSourceManipulator $manipulator, UserClassCo propertyName: $userClassConfig->getIdentityPropertyName(), type: 'string', length: 180, - unique: true, ) ); } else { @@ -259,4 +261,19 @@ private function addEraseCredentials(ClassSourceManipulator $manipulator): void $manipulator->addMethodBuilder($builder); } + + private function addUniqueConstraint(ClassSourceManipulator $manipulator, UserClassConfiguration $userClassConfig): void + { + if (!$userClassConfig->isEntity()) { + return; + } + + $manipulator->addAttributeToClass( + 'ORM\\UniqueConstraint', + [ + 'name' => 'UNIQ_IDENTIFIER_'.strtoupper(Str::asSnakeCase($userClassConfig->getIdentityPropertyName())), + 'fields' => [$userClassConfig->getIdentityPropertyName()], + ] + ); + } } diff --git a/src/Util/ClassSourceManipulator.php b/src/Util/ClassSourceManipulator.php index 4dbe9c05d..cde3cade1 100644 --- a/src/Util/ClassSourceManipulator.php +++ b/src/Util/ClassSourceManipulator.php @@ -395,7 +395,9 @@ public function addAttributeToClass(string $attributeClass, array $options): voi $classNode = $this->getClassNode(); - $classNode->attrGroups[] = new Node\AttributeGroup([$this->buildAttributeNode($attributeClass, $options)]); + $attributePrefix = str_starts_with($attributeClass, 'ORM\\') ? 'ORM' : null; + + $classNode->attrGroups[] = new Node\AttributeGroup([$this->buildAttributeNode($attributeClass, $options, $attributePrefix)]); $this->updateSourceCodeFromNewStmts(); } @@ -783,6 +785,10 @@ public function addUseStatementIfNecessary(string $class): string return $alias; } + if (str_starts_with($class, $alias)) { + return $class; + } + if ($alias === $shortClassName) { // we have a conflicting alias! // to be safe, use the fully-qualified class name diff --git a/tests/Security/fixtures/expected/UserEntityWithEmailAsIdentifier.php b/tests/Security/fixtures/expected/UserEntityWithEmailAsIdentifier.php index 722dd2507..71d2e49fa 100644 --- a/tests/Security/fixtures/expected/UserEntityWithEmailAsIdentifier.php +++ b/tests/Security/fixtures/expected/UserEntityWithEmailAsIdentifier.php @@ -7,6 +7,7 @@ use Symfony\Component\Security\Core\User\UserInterface; #[ORM\Entity] +#[ORM\UniqueConstraint(name: 'UNIQ_IDENTIFIER_EMAIL', fields: ['email'])] class User implements UserInterface, PasswordAuthenticatedUserInterface { #[ORM\Id] @@ -14,7 +15,7 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface #[ORM\Column()] private ?int $id = null; - #[ORM\Column(length: 180, unique: true)] + #[ORM\Column(length: 180)] private ?string $email = null; /** diff --git a/tests/Security/fixtures/expected/UserEntityWithPassword.php b/tests/Security/fixtures/expected/UserEntityWithPassword.php index c2a0ca349..dc4999299 100644 --- a/tests/Security/fixtures/expected/UserEntityWithPassword.php +++ b/tests/Security/fixtures/expected/UserEntityWithPassword.php @@ -7,6 +7,7 @@ use Symfony\Component\Security\Core\User\UserInterface; #[ORM\Entity] +#[ORM\UniqueConstraint(name: 'UNIQ_IDENTIFIER_USER_IDENTIFIER', fields: ['userIdentifier'])] class User implements UserInterface, PasswordAuthenticatedUserInterface { #[ORM\Id] @@ -14,7 +15,7 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface #[ORM\Column()] private ?int $id = null; - #[ORM\Column(length: 180, unique: true)] + #[ORM\Column(length: 180)] private ?string $userIdentifier = null; /** diff --git a/tests/Security/fixtures/expected/UserEntityWithUser_IdentifierAsIdentifier.php b/tests/Security/fixtures/expected/UserEntityWithUser_IdentifierAsIdentifier.php index ae8333885..a77a08fed 100644 --- a/tests/Security/fixtures/expected/UserEntityWithUser_IdentifierAsIdentifier.php +++ b/tests/Security/fixtures/expected/UserEntityWithUser_IdentifierAsIdentifier.php @@ -7,6 +7,7 @@ use Symfony\Component\Security\Core\User\UserInterface; #[ORM\Entity] +#[ORM\UniqueConstraint(name: 'UNIQ_IDENTIFIER_USER_IDENTIFIER', fields: ['user_identifier'])] class User implements UserInterface, PasswordAuthenticatedUserInterface { #[ORM\Id] @@ -14,7 +15,7 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface #[ORM\Column()] private ?int $id = null; - #[ORM\Column(length: 180, unique: true)] + #[ORM\Column(length: 180)] private ?string $user_identifier = null; /** diff --git a/tests/Security/fixtures/expected/UserEntityWithoutPassword.php b/tests/Security/fixtures/expected/UserEntityWithoutPassword.php index bd90ddb36..a1deca0f6 100644 --- a/tests/Security/fixtures/expected/UserEntityWithoutPassword.php +++ b/tests/Security/fixtures/expected/UserEntityWithoutPassword.php @@ -6,6 +6,7 @@ use Symfony\Component\Security\Core\User\UserInterface; #[ORM\Entity] +#[ORM\UniqueConstraint(name: 'UNIQ_IDENTIFIER_USER_IDENTIFIER', fields: ['userIdentifier'])] class User implements UserInterface { #[ORM\Id] @@ -13,7 +14,7 @@ class User implements UserInterface #[ORM\Column()] private ?int $id = null; - #[ORM\Column(length: 180, unique: true)] + #[ORM\Column(length: 180)] private ?string $userIdentifier = null; /**