1

I'm currently working on a Symfony v3.3.6 project. I have a form for user creation. I would like to make sure that the email and the username (of fos user bundle) is unique.

I currently own this model (only a little part) :

<?php

namespace ProjectBundle\Entity\User;

use Doctrine\ORM\Mapping as ORM;
use FOS\UserBundle\Model\User as BaseUser;
use Gedmo\Mapping\Annotation as Gedmo;
use Gedmo\SoftDeleteable\Traits\SoftDeleteableEntity;
use Gedmo\Timestampable\Traits\TimestampableEntity;
use ProjectBundle\Entity\Gender\Gender;
use ProjectBundle\Entity\Organisation\Organisation;
use ProjectBundle\Entity\Traits\BlameableEntity;
use ProjectBundle\Entity\User\Profile;
use Symfony\Component\Security\Core\User\AdvancedUserInterface;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
use Doctrine\Common\Collections\ArrayCollection;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntityValidator;


/**
 * @ORM\Entity(repositoryClass="ProjectBundle\Repository\User\UserRepository")
 * @Gedmo\SoftDeleteable(fieldName="deletedAt")
 * @ORM\Entity
 * @UniqueEntity(fields={"email"}, groups={"registration"})
 * @UniqueEntity(fields={"username"}, groups={"registration"})
 * @ORM\Table(name="user")
 */
class User extends BaseUser implements AdvancedUserInterface, \Serializable
{
    use TimestampableEntity;
    use SoftDeleteableEntity;
    use BlameableEntity;

    const ID_ORGA_GC = 1;

    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;


    /**
     * @Assert\NotBlank()
     */
    protected $username;

    /**
     * @Assert\NotBlank(groups={"registration"})
     * @Assert\Length(groups={"registration"},
     *      min = 2,
     *      max = 254,
     *      minMessage = "Votre mot de passe doit comporter au minimum {{ limit }} caractères.",
     *      maxMessage = "Votre mot de passe doit comporter au maximum {{ limit }} caractères."
     * )
     *
     * @var string
     */
    protected $plainPassword;


    /**
     * @Assert\NotBlank()
     * @Assert\Email(
     *     message = "L'adresse mail '{{ value }}' n'est pas valide.",
     *     checkMX = true
     * )
     *
     * @var string
     */
    protected $email;

As you can see I added 2 'Unique entity' attribute, for username and email, also with a 'NotBlank' constraint on each.

In my controller, I call my form:

$form = $this->createForm('ProjectBundle\Form\User\UserType', $entity,array('organisation' => $organisations, 'validation_groups' => array('Default','registration')));

$form->handleRequest($request);

        if ($form->isSubmitted()) {
            if ($form->isValid()) {

However, even if I write an e-mail address that already exists, I go into the condition, and when the time comes for the flush I get a big SQL error:

SQLSTATE [23000]: Integrity constraint violation: 1062 Duplicate entry 'emailtest@test.fr' for key 'UNIQ_8D93D649A0D96FBF'

But interesting remark is that the 'NotBlank' constraint works correctly, and shows me on my view 'The value can not be empty'

Here is my form:

class UserType extends AbstractType
{
    /**
     * {@inheritdoc}
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('lastname',null,array('required' => true))
            ->add('firstname')
            ->add('gender',null,array('required'=>true))
            ->add('organisationMember',null,array(
                'required' => true,
                'choices' => $options['organisation'],
                'group_by' => 'type_organisation',
                'placeholder' => 'Choisissez votre organisation'
            ))
            ->add('job')
            ->add('lang', null, array(
                'required' => true
            ))
            ->add('mobile',null, array(
                'required' => false
            ))
            ->add('phone', null, array(
                'required' => true
            ))
            ->add('enabled')
            ->add('is_external')
            ->add('alert_failure')
            ->add('alert_full')
            ->add('alert_other')
            ->add('plainPassword', TextType::class, array('required' => false))
            ->add('email')
            ->add('profile', null, array(
                'required' => true,
                'placeholder' => 'Choose an organisation !',
            ));
    }

    /**
     * {@inheritdoc}
     */
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'ProjectBundle\Entity\User\User',
            'organisation' => 'ProjectBundle\Entity\Organisation\Organisation',
            'profiles' => 'ProjectBundle\Entity\User\Profile',
            'csrf' => true,
        ));

    }
}

If anyone has a solution.

Thank you in advance !

Peter Artoung
  • 224
  • 5
  • 20
  • Possible duplicate of [Doctrine 2 @Gedmo\SoftDeleteable and unique fields](https://stackoverflow.com/questions/33533761/doctrine-2-gedmo-softdeleteable-and-unique-fields) – Vadim Ashikhman Oct 18 '17 at 16:37
  • The error is almost identical but the proposed solution does not work, I still have the SQL exception. – Peter Artoung Oct 19 '17 at 07:22

2 Answers2

0

Have you tried like this:

/**
 * @ORM\Entity(repositoryClass="ProjectBundle\Repository\User\UserRepository")
 * @Gedmo\SoftDeleteable(fieldName="deletedAt")
 * @ORM\Entity
 * @UniqueEntity(fields={"email", "username"}, groups={"registration"})
 * @ORM\Table(name="user")
 */

But make sure that you have unique index for email and username.

Carca
  • 564
  • 1
  • 6
  • 16
  • Your solution works only in DEV. When I update the changes to PROD, the exception is still there. (The database is ready with good index) – Peter Artoung Oct 19 '17 at 07:29
0

Currently, @CarcaBot's response works only in DEV, the update dont change my problem in PROD while the files are identical, as well as the database.

An idea ?

Peter Artoung
  • 224
  • 5
  • 20