3

I struggle finding the solution for this problem: I have 2 classes contact and phones with a manytomany relationship. The phones table has 2 fields : countryCode and number. I want to check that 2 contacts don't have the same telephone number, so validation on the combination of the 2 fields. The last code is this one, but I tried lots of possibilities.

    /**
     * Contact
     *
     * @ORM\Table(
     *     name="contact"
     * )
     * @ORM\Entity(repositoryClass="EPI\PlatformBundle\Repository\ContactRepository")
     *
     * @UniqueEntity(fields={"email"}, message="ce mail existe déjà")
     * @UniqueEntity(fields={"phoneNumbers"}, message="this phone number already exists")
     *
     */
    class Contact
    {
        /**
         * @var int
         * @ORM\Column(name="id", type="integer")
         * @ORM\Id
         * @ORM\GeneratedValue(strategy="AUTO")
         */
        private $id;


        /**
         * One User can have several Phonenumbers.
         * @ORM\ManyToMany(targetEntity="Phone", cascade={"persist", "remove"}, orphanRemoval=true)
         * @ORM\JoinTable(name="contact_phones",
         *      joinColumns={@ORM\JoinColumn(name="contact_id", referencedColumnName="id", onDelete="CASCADE")},
         *      inverseJoinColumns={@ORM\JoinColumn(name="phone_id", referencedColumnName="id", unique=true, onDelete="CASCADE")}
         *      )
         */


   /**
     * Phone        
     *
     * @ORM\Table(name="phone")
     * @ORM\Entity(repositoryClass="EPI\PlatformBundle\Repository\PhoneRepository")
     *
     */

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

        /**
         * @var string
         *
         * @ORM\Column(name="country_code", type="string", length=4)
         */
        private $countryCode;

        /**
         * @var string
         *
         * @ORM\Column(name="phone_nb", type="string", length=9)
         */
        private $phoneNb;



    class ContactType extends AbstractType
    {
        /**
         * {@inheritdoc}
         */
        public function buildForm(FormBuilderInterface $builder, array $options)
        {
            $builder
                ->add('title', ChoiceType::class, array(
                    'choices' => array(
                        'Madame' => 'Madame',
                        'Monsieur' => 'Monsieur'
                    )
                ))
                ->add('firstName', TextType::class)
                ->add('surname', TextType::class)
                ->add('email', EmailType::class)
                ->add('phoneNumbers', CollectionType::class, array(
                    'entry_type' => PhoneType::class,
                    'entry_options' => array('label' => false),
                    'allow_add' => 'true',
                    'allow_delete' => 'true',
                    'error_bubbling' => 'true'
                ));
        }

        /**
         * {@inheritdoc}
         */
        public function configureOptions(OptionsResolver $resolver)
        {
            $resolver->setDefaults(array(
                'data_class' => 'EPI\PlatformBundle\Entity\Contact',
            ));
        }

        /**
         * {@inheritdoc}
         */
        public function getName()
        {
            return 'contact';
        }

        /**
         * {@inheritdoc}
         */
        public function getBlockPrefix()
        {
            return 'contact';
        }
    }

With this code I get the following error:

    An exception occurred while executing 'SELECT t0.id AS id_1, t0.title AS title_2, t0.first_name AS first_name_3, t0.surname AS surname_4, t0.email AS email_5 FROM contact t0 WHERE contact_phones.phone_id = ?' with params [{}]:

    SQLSTATE[42S22]: Column not found: 1054 Champ 'contact_phones.phone_id' inconnu dans where clause

Thank you for your help.

Jerry
  • 31
  • 2
  • Did you update the schema after you wrote the many to many relationship `php bin/console doctrine:schema:update --force` ? – teeyo Sep 22 '17 at 15:58
  • Your code is incomplete, you truncated some classes to shorten your question, but if you followed all the instructions in the manual : http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/association-mapping.html#many-to-many-unidirectional you probably only forgot to update your database schema which may result in the mentioned exception. – teeyo Sep 22 '17 at 16:03
  • I have updated the schema. But the manytomany relationship works well. The problem I have is only related to the uniqueEntity validation. – Jerry Sep 22 '17 at 17:11

1 Answers1

0

I finally found the solution, the "uniqueEntity" annotation in the contact entity is not the proper way to work, this annotation must be placed in the phone entity, but the "@Assert\Valid()" annotation must be added on top of the collection reference pointing to the phone object within the contact entity. To be clearer, here is the code:

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

        /**
         * One Contact can have Many Addresses.
         * @ORM\ManyToMany(targetEntity="Address", cascade={"persist", "remove"}, orphanRemoval=true)
         * @ORM\JoinTable(name="contact_addresses",
         *      joinColumns={@ORM\JoinColumn(name="contact_id", referencedColumnName="id", onDelete="CASCADE")},
         *      inverseJoinColumns={@ORM\JoinColumn(name="address_id", referencedColumnName="id", unique=true, onDelete="CASCADE")}
         *      )
         */
        private $addresses;

        /**
         * One User can have several Phonenumbers.
         * @ORM\ManyToMany(targetEntity="Phone", cascade={"persist", "remove"}, orphanRemoval=true)
         * @ORM\JoinTable(name="contact_phones",
         *      joinColumns={@ORM\JoinColumn(name="contact_id", referencedColumnName="id", onDelete="CASCADE")},
         *      inverseJoinColumns={@ORM\JoinColumn(name="phone_id", referencedColumnName="id", unique=true, onDelete="CASCADE")}
         *      )
         *
         * @Assert\Valid()
         *
         */
        private $phoneNumbers;


    <?php

    namespace EPI\PlatformBundle\Entity;

    use Doctrine\ORM\Mapping as ORM;
    use Symfony\Bridge\Doctrine\        Validator\Constraints\UniqueEntity;

    /**
     * Phone
     *
     * @ORM\Table(name="phone")
     * @ORM\Entity(repositoryClass="EPI\PlatformBundle\Repository\PhoneRepository")
     *
     *
     *  @UniqueEntity(fields={"countryCode","phoneNb"}, message="ce numéro de téléphone existe déjà")
     */

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

        /**
         * @var string
         *
         * @ORM\Column(name="country_code", type="string", length=4)
         */
        private $countryCode;

        /**
         * @var string
         *
         * @ORM\Column(name="phone_nb", type="string", length=9)
         */
        private $phoneNb;

The @Assert\Valid() annotation is the means to ask Symfony to force the validation of the "sub object" referenced by the private $phoneNb variable.

Jerry
  • 31
  • 2