Sonata Admin embed forms one-to-many does not persist

4,361 views
Skip to first unread message

Nelson Suniaga

unread,
Jan 14, 2013, 4:56:19 PM1/14/13
to sonata...@googlegroups.com
Hello everybody!

I've been trying to implement embed forms in Sonata Admin Bundle 2.0,  Sonata User Bundle 2.0 and Symfony 2.0.16 (yes, I know it's kind of old right now)  and after reading a lot of forum posts and manual I could be able to implement it... but just at form level, it can't display data in edition mode, or persist it in creation mode.

Being more expecific, I'm trying to make work a relationship between an User entity (from Sonata User Bundle) with an Email entity, in an one-to-many relationship (one User has many Emails, or just one). So in the User form is gonna have one or more emails forms dynamically embeded, which seems to be working, but are disconnected with the email table.

UserAdmin.php

class UserAdmin extends Admin
{
    // more code
   
        $formMapper
            ->with('General')
                ->add('username')
                ->add('email')
                ->add('plainPassword', 'text', array('required' => false))
            ->end()
            ->with('Groups')
                ->add('groups', 'sonata_type_model', array('required' => false))
            ->end()
            ->with('Profile')
                ->add('dateOfBirth', 'date', array('required' => false))
                ->add('firstname', null, array('required' => false))
                ->add('lastname', null, array('required' => false))
                ->add('website', 'url', array('required' => false))
                ->add('locale', null, array('required' => false))
                ->add('timezone', null, array('required' => false))
            ->end()
            ->with('Emails')
                ->add('emails', 'collection', array(
                    'label' => 'Emails',
                    'required' => true,
                    'allow_add' => true,
                    'allow_delete' => true,
                    'by_reference' => false,
                ),
                array(
                    'edit' => 'inline',
                    'inline' => 'table',
                    'sortable' => 'id',
                    'targetEntity'=> 'MyProject\xBundle\Entity\Email',
                    'link_parameters' => array('context' => 'user'),
                )
            )
        ;
    // more code ...
}

User.php

class User extends BaseUser
{
    /**
     * @var array emails
     */
    protected $emails;

    /**
     * @var string user
     */
    protected $user;


    public function __construct()
    {
        $this->emails = new \Doctrine\Common\Collections\ArrayCollection();
    }

    /**
     * Add emails
     *
     * @param MyProject\xBundle\Email $email
     */
    public function addEmails(\MyProject\xBundle\Entity\Email $email)
    {
        $this->emails[] = $email;
    }

    /**
     * Get emails
     *
     * @return Doctrine\Common\Collections\Collection
     */
    public function getEmails()
    {
        return $this->emails;
    }

    /**
     * Set emails
     *
     * @param  $emails
     * @return Email
     */
    public function setEmails($emails)
    {
        $this->$emails = $emails;

        foreach ($emails as $email) {
            $email->setUser($this);
        }
    }

    /**
     *
     * @param string $user
     */
    public function setUser($user)
    {
        $this->user = $user;
    }
}

Email.php

class Email
{
   /**
     * @var SystemUser
     *
     * @ORM\ManyToOne(targetEntity="User", cascade={"persist"})
     * @ORM\JoinColumns({
     *   @ORM\JoinColumn(name="system_user_id", referencedColumnName="id")
     * })
     *
     */
   private $systemUser;

   public function __construct()
    {
        $this->systemUser = new ArrayCollection();
    }

    /**
     *
     * @param MyProject\xBundle\Entity\User $systemUser
     */
    public function setSystemUser(\MyProject\xBundle\Entity\User $systemUsers = null)
    {
        $this->systemUser = $systemUser;

        return $this;
    }

    /**
     * Get systemUser
     *
     * @return MyProject\xBundle\Entity\User
     */
    public function getSystemUser()
    {
        return $this->systemUser;
    }
}

Lineke Kerckhoffs-Willems

unread,
Jan 15, 2013, 3:02:53 AM1/15/13
to sonata...@googlegroups.com
Hi Nelson,

Try the sonata_type_collection for the emails field instead of just
"collection". That might help.

Regards,

Lineke

2013/1/14 Nelson Suniaga <nelson....@gmail.com>:
> --
> You received this message because you are subscribed to the Google Groups
> "sonata-users" group.
> To view this discussion on the web visit
> https://groups.google.com/d/msg/sonata-users/-/gGAH4epyB80J.
> To post to this group, send email to sonata...@googlegroups.com.
> To unsubscribe from this group, send email to
> sonata-users...@googlegroups.com.
> For more options, visit this group at
> http://groups.google.com/group/sonata-users?hl=en.

Nelson Jesus Suniaga Romero

unread,
Jan 15, 2013, 1:41:29 PM1/15/13
to sonata...@googlegroups.com
Hey Lineke!

If I use sonata_type_collection I get this error message:

The current field `emails` is not linked to an admin. Please create one for the target entity : ``

The collection option is what I'm using right now, and it's the only one that kind of works.

Other thing I forgot to mention is the email embed form doesn't use the EmailType even if I use in the type option. Only display one text field, when the right thing will be display two (address and notes).

    protected function configureFormFields(FormMapper $formMapper)
    {
        $formMapper
            // other add methods
            ->with('Emails')
                ->add('emails', 'collection', array(
                    'type' => new EmailType(), // completely ignored

                    'label' => 'Emails',
                    'required' => true,
                    'allow_add' => true,
                    'allow_delete' => true,
                    'by_reference' => false,
                ),
                array(
                    'edit' => 'inline',
                    'inline' => 'table',
                    'sortable' => 'id',
                    'targetEntity'=> 'Mercury\CargoRecognitionBundle\Entity\Email',

                    'link_parameters' => array('context' => 'user'),
                )
            )
            // more add methods
       }

services.xml

        <service id="myproject_email_form" class="MyProject\xBundle\Form\Type\EmailType">
            <tag name="form.type" />
        </service>

I think this is the real issue, because the embed form is defined in the form type class, which is being ignored.

Lineke Kerckhoffs-Willems

unread,
Jan 15, 2013, 4:18:37 PM1/15/13
to sonata...@googlegroups.com
Hi Nelson,

I don't know anything about the collection type, so I can't help you there.
You can however easily solve the error you got with the
sonata_type_collection. If you define an admin class for the email
entity, then that would work just fine.

Regards,

Lineke

2013/1/15 Nelson Jesus Suniaga Romero <nelson....@gmail.com>:

Nelson Suniaga

unread,
Jan 15, 2013, 4:50:43 PM1/15/13
to sonata...@googlegroups.com
Actually there's a EmailAdmin class and it works perfectly fine (I can create, retrieve, updated and delete records with it) and guessing the issue came from the kind of association I'm trying to implement in the form.

In the database, User and Email has a one-to-many cardinality (one User can have one or many Emails), Email is the owner side of the relationship while User is the inverse side of it, but Sonata Admin implements this association connecting the User form into the Email form (using the foreign key as dropmenu field, for example), but this is a wrong design.

That's why I can not use sonata_type_collection in this case, it only works if I use it in the Email form, where there's a foreign key pointing to the User entity.

The right way is embeding the Emails form dynamically many times as it needed, but the only way I know to accomplish this is faking the cardinality of the association at a logical level into the class definition (look the User.php and Emails.php files). The User class has a $emails field that is somehow connected to the Email class.
Reply all
Reply to author
Forward
0 new messages