Search code examples
doctrine-ormdoctrine

How to save two relation entities in Doctrine?


I'm doing a user registration. I have two entities: User, UserCredential

#[Entity, Table(name: 'user')]
#[HasLifecycleCallbacks]
class UserEntity implements JsonSerializable
{
    const INACTIVE = 0;
    const ACTIVE = 1;
    const BLOCKED = 2;
    const IS_DELETED_NO = 0;
    const IS_DELETED_YES = 1;

    #[Id, Column(type: Types::INTEGER), GeneratedValue(strategy: 'AUTO')]
    private int $id;

    #[Column(name: 'role_id', type: Types::INTEGER, length: 11, options: ['default' => 0])]
    private int $roleId;

    #[Column(name: 'email', type: Types::STRING, length: 255, unique: true, nullable: false)]
    private string $email;

    #[Column(name: 'status', type: Types::SMALLINT, options: ['default' => self::INACTIVE])]
    private int $status = self::INACTIVE;

    #[Column(name: 'created_at', type: Types::INTEGER, length: 11)]
    private int $createdAt;

    #[Column(name: 'updated_at', type: Types::INTEGER, length: 11)]
    private int $updatedAt;

    #[Column(name: 'is_deleted', type: Types::SMALLINT, options: ['default' => self::IS_DELETED_NO])]
    private int $isDeleted = self::IS_DELETED_NO;

    #[OneToOne(mappedBy: 'user', targetEntity: UserCredentialEntity::class)]
    private UserCredentialEntity $credential;
....




#[Entity, Table(name: 'user_credential')]
class UserCredentialEntity
{
    #[Id, Column(type: Types::INTEGER), GeneratedValue(strategy: 'AUTO')]
    private int $id;

    #[Column(name: 'user_id', type: Types::INTEGER, length: 11)]
    private int $userId;

    #[Column(name: 'password_hash', type: Types::STRING, length: 255, nullable: false)]
    private string $passwordHash;

    #[Column(name: 'email_confirm_key', type: Types::STRING, length: 255, nullable: true)]
    private ?string $emailConfirmKey = null;


    #[OneToOne(targetEntity: UserEntity::class)]
    #[JoinColumn(name: 'user_id', referencedColumnName: 'id')]
    private UserEntity $user;

    public function __construct(UserEntity $user, string $password)
    {
        //$this->userId = $user->getId();
        $this->user = $user;
        $this->passwordHash = $password;
    }
}


 public function createUser(string $email, string $password): User | Exception
    {
        $this->em->getConnection()->beginTransaction();
        try {
            $user = new User($email);
            $user->setRoleId(1);
            $this->em->persist($user);

            $userCredential = new UserCredentialEntity($user, 'password');

            $this->em->persist($userCredential);
            $this->em->flush();

            $this->em->getConnection()->commit();

            return $user;
        } catch (Exception $e) {
            var_dump($e->getMessage());
            $this->em->getConnection()->rollback();
            throw $e;
        }
    }

How to make the UserCredential entity be saved automatically with the required User id?

I'm getting an error:

"An exception occurred while executing a query: SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'user_id' cannot be null"


Solution

  • Why would you have two references to the User in the UserCredentials?

    In the User entity

    #[OneToOne(mappedBy: 'user', targetEntity: UserCredentialEntity::class)]
    private UserCredentialEntity $credential;
    

    In the UserCredentials entity

    Remove the $userId in this class because you can already get it from the $user.

    #[OneToOne(inversedBy: 'credential', targetEntity: UserEntity::class)]
    private UserEntity $user;