简体   繁体   中英

Construct or validation does not work when I embed an entity with sonata_type_admin

I have an entity 'Employee' and I embed an entity 'User' with 'sonata_type_admin' form type (one to one relation). When I create a new Employee object I want to set default values to User object, but User __construct() or getNewInstance() method is never called. I also noticed that user validation constraints don't work when I edit an Employee (for instance, if I edit an employee and I try to set an username that already exists, validation constraint is not displayed on username field). If I edit an user, __construct(), getNewInstance() and validation constraints works fine.

What can I do?

I extended my user entity from SonataUserBundle (FOSUserBundle).

//User.orm.xml
...
    <entity name="Application\Sonata\UserBundle\Entity\User" table="fos_user_user">

        <id name="id" column="id" type="integer">
            <generator strategy="AUTO" />
        </id>

        <one-to-one field="employee" target-entity="AppBundle\Entity\Employee" mapped-by="user" />
    </entity>

</doctrine-mapping>

My Employee entity is in AppBundle.

//Employee.php
namespace AppBundle\Entity;

use Gedmo\Mapping\Annotation as Gedmo;
use Gedmo\Timestampable\Traits\TimestampableEntity;
use Doctrine\ORM\Mapping as ORM;

/**
 * Session
 *
 * @ORM\Table(name="nup_employee")
 * @ORM\Entity(repositoryClass="AppBundle\Entity\EmployeeRepository")
 */
class Employee
{
    const STATUS_INACTIVE = 0;
    const STATUS_ACTIVE = 1;

    use TimestampableEntity;

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

    /**
     * @ORM\OneToOne(
     *  targetEntity="Application\Sonata\UserBundle\Entity\User", 
     *  inversedBy="employee", 
     *  cascade={"persist", "remove"}
     * )
     * @ORM\JoinColumn(name="user_id", referencedColumnName="id", nullable=true, onDelete="SET NULL")
     */
    private $user;
...

My configureFormFields.

//UserAdmin.php
...
protected function configureFormFields(FormMapper $formMapper)
    {
        $formMapper
            ->with('General')
                ->add('username')
                ->add('email')
                ->add('plainPassword', 'text', array(
                    'required' => (!$this->getSubject() || is_null($this->getSubject()->getId()))
                ))
            ->end()
        ;

        $formMapper
            ->with('Security')
                ->add('enabled', null, array('required' => false))
                ->add('locked', null, array('required' => false))
                ->add('token', null, array('required' => false))
                ->add('twoStepVerificationCode', null, array('required' => false))
            ->end()
        ;
    }
...

Composer.json:

...
"symfony/symfony": "2.7.*",
...
"friendsofsymfony/user-bundle": "~1.3",
"sonata-project/admin-bundle": "2.3.*",
"sonata-project/doctrine-orm-admin-bundle": "2.3.*",
"sonata-project/user-bundle": "^2.2"

Finally, I found the solution (@anegrea thanks for your help).

Sonata doesn't call User construct on Employee create because it doesn't know if it's nullable or not (it's different if you create a user because the user is required). if you want to call User construct on Employee create you have to put data on related field.

class EmployeeAdmin extends Admin
{
...
    protected function configureFormFields(FormMapper $formMapper)
    {
        $data = new User();
        if ($this->getSubject()->getUser()) {
            $data = $this->getSubject()->getUser();
        }

        $formMapper
            ->with('General', array('class' => 'col-md-6'))
                ->add('name')
                ->add('surnames')
            ->end()

            ->with('Access', array('class' => 'col-md-6'))
                ->add('user', 'sonata_type_admin', 
                    array(
                        'data' => $data,
                        'label' => false
                    ), 
                    array(
                        'admin_code' => 'sonata.user.admin.user',
                        'edit' => 'inline'
                    )
                )
            ->end()
        ;
    }
...
}

On the other hand, to show errors on User fields when I create or edit an Employee, I had to add Valid constraint on user mapping in Employee entity and add validation groups related to FOSUserBundle in EmployeeAdmin.

class Employee
{
...    
    /**
     * @ORM\OneToOne(
     *  targetEntity="Application\Sonata\UserBundle\Entity\User", 
     *  inversedBy="employee", 
     *  cascade={"persist", "remove"}
     * )
     * @ORM\JoinColumn(name="user_id", referencedColumnName="id", nullable=true, onDelete="SET NULL")
     * @Assert\Valid
     */
    private $user;
...
}

class EmployeeAdmin extends Admin
{
    public function getFormBuilder()
    {
        $this->formOptions['data_class'] = $this->getClass();

        $options = $this->formOptions;

        $options['validation_groups'] = array('Default');
        array_push($options['validation_groups'], (!$this->getSubject() || is_null($this->getSubject()->getId())) ? 'Registration' : 'Profile');

        $formBuilder = $this->getFormContractor()->getFormBuilder($this->getUniqid(), $options);

        $this->defineFormBuilder($formBuilder);

        return $formBuilder;
    }
...
}

For the validation you have to add the constraint on the Employee entity for the $user property to be Valid. http://symfony.com/doc/current/reference/constraints/Valid.html

If there is a problem with persisting also, it might be because you are having the bidirectional relation that in you employee admin, on preUpdate/prePersist (these are funcitons the admin knows about) you must also link the employee to the user by doing something like:

public function prePersist($object) {
    $object->getUser()->setEmployee($object);
}

Or, you can try to have only the user mapped on the employee (without the inversedBy directve).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM