当我使用 sonata_type_admin 嵌入实体时,构造或验证不起作用

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

我有一个实体 'Employee',我嵌入了一个具有 'sonata_type_admin' 表单类型(一对一关系)的实体 'User'。 当我创建一个新的 Employee 对象时,我想将默认值设置为 User 对象,但是从不调用 User __construct() 或 getNewInstance() 方法。 我还注意到,当我编辑员工时,用户验证约束不起作用(例如,如果我编辑员工并尝试设置已经存在的用户名,验证约束不会显示在用户名字段上)。如果我编辑用户,__construct()、getNewInstance() 和验证约束工作正常。

我能做什么?

我从 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>

我的员工实体在 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;
...

我的 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"

为了进行验证,您必须在 Employee 实体上添加约束才能使 $user 属性 有效。 http://symfony.com/doc/current/reference/constraints/Valid.html

如果坚持也有问题,可能是因为您在员工管理员中存在双向关系,在 preUpdate/prePersist(这些是管理员知道的功能)上,您还必须 link 员工通过做类似的事情给用户:

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

或者,您可以尝试仅将用户映射到员工(不使用 inversedBy 指令)。

终于,我找到了解决方案(@anegrea 感谢您的帮助)。

Sonata 不会在 Employee create 上调用 User 构造,因为它不知道它是否可以为空(如果创建用户则不同,因为用户是必需的)。如果你想在 Employee create 上调用 User 构造,你必须将数据放在相关字段上。

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()
        ;
    }
...
}

另一方面,为了在创建或编辑员工时在用户字段上显示错误,我必须在员工实体中的用户映射上添加有效约束,并在员工管理中添加与 FOSUserBundle 相关的验证组。

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;
    }
...
}