使用zf3 fieldset进行Doctrine Table继承

问题描述 投票:0回答:1

我正在使用Zend Framework 3和Doctrine 2开发一个项目,用于DcotrineModule集成,以下是我遇到问题的实体建模:

Entity Model

要使用我正在使用@InheritanceType的学说来处理这个建模,下面是来自实体的相关摘录:

实体人:

/**
 * Abstração de Pessoa
 *
 * @author Rodrigo Teixeira Andreotti <[email protected]>
 * 
 * @Entity
 * @InheritanceType("JOINED")
 * @DiscriminatorColumn(name="tipo", type="string")
 * @DiscriminatorMap( { "pessoa" = "Pessoa", 
 *                      "pessoa_fisica" = "PessoaFisica",
 *                      "pessoa_juridica" = "PessoaJuridica" } )
 * @Table(name="pessoa")
 */
abstract class Pessoa implements JsonSerializable, PessoaInterface
{

    use JsonSerializeTrait;

    /**
     * @Id
     * @GeneratedValue(strategy="IDENTITY")
     * @Column(type="integer", length=32, unique=true, nullable=false, name="id_pessoa")
     * @var integer
     */
    protected $idPessoa;

    /**
     * Usuário
     * @OneToOne(targetEntity="User\Entity\User", inversedBy="pessoa", cascade={"persist"})
     * @JoinColumn(name="usuario", referencedColumnName="id")
     * 
     * @var User
     */
    protected $usuario;

    /**
     * @OneToOne(targetEntity="EnderecoPessoa", mappedBy="pessoa", cascade={"persist"})
     * @var EnderecoPessoa
     */
    protected $endereco;

    /**
     * Contatos da pessoa
     * @OneToMany(targetEntity="ContatoPessoa", mappedBy="pessoa", cascade={"persist"}, orphanRemoval=true)
     * @var ArrayCollection|array
     */
    protected $contatos;

    const PESSOA_FISICA = "pessoa_fisica", PESSOA_JURIDICA = "pessoa_juridica";

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

物理实体:

/**
 * Abstração da pessoa física
 *
 * @Entity
 * @Table(name="pessoa_fisica")
 * @author Rodrigo Teixeira Andreotti <[email protected]>
 */
class PessoaFisica extends Pessoa implements JsonSerializable {

    use JsonSerializeTrait;

    /**
     * Nome da pessoa física
     * @Column(type="string", length=14)
     * @var string
     */
    private $nome;

    /**
     * Número do CPF da pessoa (quando brasileiro)
     * @Column(type="string", length=14)
     * @var string
     */
    private $cpf;

    /**
     * Número do RG (quando brasileiro)
     * @Column(type="string", length=13)
     * @var string
     */
    private $rg;

    /**
     * Data de nascimento
     * @Column(type="date", name="data_nascimento")
     * @var DateTime
     */
    private $dataNascimento;
}

法人实体:

/**
 * Abstração de Pessoa Jurídica
 * 
 * @Entity
 * @Table(name="pessoa_juridica")
 * @InheritanceType("JOINED")
 * @author Rodrigo Teixeira Andreotti <[email protected]>
 */
class PessoaJuridica extends Pessoa implements JsonSerializable {

    use JsonSerializeTrait;

    /**
     * @Id
     * @GeneratedValue(strategy="IDENTITY")
     * @Column(type="integer", length=32, unique=true, nullable=false, name="id_pessoa")
     * @var integer
     */
    protected $idPessoa;

    /**
     * Nome fantasia
     * @Column(type="string", length=32, name="nome_fantasia")
     * @var String
     */
    protected $nomeFantasia;

    /**
     * Número do CNPJ
     * @Column(type="string", length=14, unique=true, name="cnpj") 
     * @var string
     */
    protected $cnpj;

    /**
     * Razão social da empresa
     * @Column(type="string", length=32, name="razao_social")
     * @var string Razão social da empresa, quando necessário
     */
    protected $razaoSocial;
}

到目前为止一切都运行良好,问题是当我需要为此信息生成表单时,我正在研究“客户”模块,基本上我为它做的是:

  • 使用客户端ID + Pessoa Fieldset创建表单
  • 在Pessoa Fieldset中,我创建了共享信息的字段集(用户,地址,联系人等)
  • 在Pessoa Fieldset中,它还包括另外两个Fieldsets,每个Pessoa的子类(PessoaFisica和PessoaJuridica)都有一个 - 这就是问题所在。

在下面的屏幕中,您可以看到我的注册表格:Screen of system

此表单根据所选类型使用javascript显示或隐藏PessoaJuridica或PessoaFisica的字段集,但由于它们是表单中的不同字段集,当zend水合它们时它们也被水合为不同的对象,即继承不应用于Person对象,应根据类型选择。

基本上,在我看来,需要发生的是,有一种方法可以让zend不将字体集引用Person类的子类作为单独的对象,此时表单是使用这些对象呈现的字段所以(例如):

人[fsPeople] [姓名]

人[fsPessoaJuridica] [nameFantasica]

这导致zend不生成要保存在数据库中的正确类。

执行表单的正确方法是什么?

php doctrine-orm zend-framework2 zend-framework3 fieldset
1个回答
0
投票

好吧,来自@rkeet的回复帮助我了解了问题的位置,这不是真正的问题=]

由于继承的使用,您已创建单独的实体。但是,您最初在后端创建的表单使用单个实体。你修改过的前端处理2.所以你的前端与你的后端不匹配。由于继承,您现在有2个单独的实体,您应该创建2个单独的表单,使用不同的字段集(PessoaJuridica或PessoaFisica)作为基本字段集。

我将离开我在这里跟随的道路,它可能会帮助有同样疑问的人。

首先,遵循他的评论中解释的逻辑,我为PessoaEntity创建了一个抽象的字段集,其中包含两种类型的人之间共享的信息,并将其扩展为两个子类PessoaFisicaFieldset和PessoaJuridicaFieldset,我将在下面描述:

/**
 * Fieldset com dados para a pessoa
 *
 * @author Rodrigo Teixeira Andreotti <[email protected]>
 */
abstract class PessoaFieldset extends Fieldset implements InputFilterProviderInterface
{

    private $em;
    private $userFs;
    private $enderecoFs;
    private $contatoFs;

    public function __construct(ObjectManager $em,
            UserFieldset $userFs,
            PessoaEnderecoFieldset $enderecoFs,
            ContatoFieldset $contatoFs)
    {
        parent::__construct('pessoa');
        $this->em = $em;
        $this->userFs = $userFs;
        $this->enderecoFs = $enderecoFs;
        $this->contatoFs = $contatoFs;
        $this->init();
    }

    protected function getEm()
    {
        return $this->em;
    }

    public function init()
    {
        $this
                ->setHydrator(new DoctrineObject($this->getEm()));

        $this->add(array(
            'type' => 'Hidden',
            'name' => 'id_pessoa',
            'attributes' => array(
                'id' => 'txtId'
            )
        ));

        $this->add(array(
            'type' => 'hidden',
            'name' => 'tipo',
        ));


        $this->add($this->userFs);

        $this->add($this->enderecoFs);

        $elCollection = new Collection;
        $elCollection
                ->setName('contatos')
                ->setLabel('Informações de Contato')
                ->setCount(1)
                ->setShouldCreateTemplate(true)
                ->setAllowAdd(true)
                ->setAllowRemove(true)
                ->setTargetElement($this->contatoFs);


        $this->add($elCollection);

        $this->add(array(
            'type'  =>  'Button',
            'name'  =>  'btAddContato',
            'options' => array(
                'label' => '<i class="fa fa-fw fa-plus"></i> Adicionar',
                'label_options' => array(
                    'disable_html_escape' => true
                )
            ),
            'attributes' => array(
                'class' => 'btn btn-info',
                'id'    =>  'btAddContato'
            )
        ));
    }

    public function getInputFilterSpecification(): array
    {
        return array(
            'id_pessoa' =>  array(
                'required'  =>  false,
                'filters'   =>  array(
                    ['name'=>'Int']
                )
            ),
            'tipo'  =>  array(
                'required'  =>  true,
            )
        );
    }

}

这是我的PessoaFisicaFieldset类。

/**
 * Fieldset com dados para a pessoa Física
 *
 * @author Rodrigo Teixeira Andreotti <[email protected]>
 */
class PessoaFisicaFieldset extends PessoaFieldset implements InputFilterProviderInterface
{

    private $em;

    public function __construct(ObjectManager $em, 
            \User\Form\UserFieldset $userFs, 
            PessoaEnderecoFieldset $enderecoFs, 
            \Common\Form\ContatoFieldset $contatoFs)
    {
        parent::__construct($em, $userFs, $enderecoFs, $contatoFs);
        $this->init();
    }



    public function init()
    {
        parent::init();
        $this
                ->setObject(new PessoaFisica());

        $this->get('tipo')->setValue(\Pessoa\Entity\Pessoa::PESSOA_FISICA);



        $this->add(array(
            'type' => 'Text',
            'name' => 'cpf',
            'options' => array(
                'label' => 'CPF',
                'label_attributes' => array(
                    'class' => 'col-sm-12'
                )
            ),
            'attributes' => array(
                'class' => 'form-control form-control-line',
                'id' => 'txtCpf'
            )
        ));

        $this->add(array(
            'type' => 'Text',
            'name' => 'nome',
            'options' => array(
                'label' => 'Nome',
                'label_attributes' => array(
                    'class' => 'col-sm-12'
                )
            ),
            'attributes' => array(
                'class' => 'form-control form-control-line',
                'id' => 'txtNome'
            )
        ));

        $this->add(array(
            'type' => 'Text',
            'name' => 'rg',
            'options' => array(
                'label' => 'RG',
                'label_attributes' => array(
                    'class' => 'col-sm-12'
                )
            ),
            'attributes' => array(
                'class' => 'form-control form-control-line',
                'id' => 'txtRazaoSocial'
            )
        ));

        $this->add(array(
            'type' => 'DateTime',
            'name' => 'dataNascimento',
            'options' => array(
                'format' => 'd/m/Y',
                'label' => 'Data de Nascimento',
                'label_attributes' => array(
                    'class' => 'col-sm-12'
                )
            ),
            'attributes' => array(
                'class' => 'form-control form-control-line data',
            )
        ));
    }

    public function getInputFilterSpecification(): array
    {
        return array(
            'nome'  =>  array(
                'required'  =>  true,
                'filters'   => array(
                    ['name' => 'StripTags'],
                    ['name' => 'StringTrim']
                )
            ),
            'rg'    =>      array(
                'required'  =>  false,
                'filters'   =>  array(
                    ['name' => 'StripTags'],
                    ['name' => 'StringTrim']
                )
            ),
            'cpf'   =>      array(
                'required'  =>  false,
                'filters'   =>  array(
                    ['name' => 'StripTags'],
                    ['name' => 'StringTrim']
                ),
                'validators'    =>  array(
                    ['name' => CpfValidator::class]
                )
            ),
            'dataNascimento'    =>  array(
                'required'  =>  true,
                'filters'   =>  array(
                    array(
                        'name' => 'Zend\Filter\DatetimeFormatter',
                        'options' => array (
                            'format' => 'd/m/Y',
                        ),
                    ),
                ),
                'validators'    =>  array(
                    array(
                        'name' => Date::class,
                        'options'   =>  array(
                            'format'    =>  'd/m/Y'
                        )
                    )
                )
            )
        );
    }

}

这是我的PessoaJuridicaFieldset

/**
 * Fieldset com dados específicos para a pessoa jurídica
 *
 * @author Rodrigo Teixeira Andreotti <[email protected]>
 */
class PessoaJuridicaFieldset extends PessoaFieldset implements InputFilterProviderInterface
{

    public function __construct(ObjectManager $em, 
            \User\Form\UserFieldset $userFs, PessoaEnderecoFieldset $enderecoFs, 
            \Common\Form\ContatoFieldset $contatoFs)
    {
        parent::__construct($em, $userFs, $enderecoFs, $contatoFs);
        $this->init();
    }

    public function init()
    {
        parent::init();
        $this
                ->setObject(new PessoaJuridica());

        $this->get('tipo')->setValue(\Pessoa\Entity\Pessoa::PESSOA_JURIDICA);


        $this->add(array(
            'type' => 'Text',
            'name' => 'cnpj',
            'options' => array(
                'label' => 'CNPJ',
                'label_attributes' => array(
                    'class' => 'col-sm-12'
                )
            ),
            'attributes' => array(
                'class' => 'form-control form-control-line',
                'id' => 'txtCnpj'
            )
        ));



        $this->add(array(
            'type' => 'Text',
            'name' => 'razaoSocial',
            'options' => array(
                'label' => 'Razão Social',
                'label_attributes' => array(
                    'class' => 'col-sm-12'
                )
            ),
            'attributes' => array(
                'class' => 'form-control form-control-line',
                'id' => 'txtRazaoSocial'
            )
        ));

        $this->add(array(
            'type' => 'Text',
            'name' => 'nomeFantasia',
            'options' => array(
                'label' => 'Nome Fantasia',
                'label_attributes' => array(
                    'class' => 'col-sm-12'
                )
            ),
            'attributes' => array(
                'class' => 'form-control form-control-line',
                'id' => 'txtNomeFantasia'
            )
        ));
    }

    public function getInputFilterSpecification(): array
    {
        return array(
            'razaoSocial'  =>  array(
                'required'  =>  true,
                'filters'   => array(
                    ['name' => 'StripTags'],
                    ['name' => 'StringTrim']
                )
            ),
            'nomeFantasia'    =>      array(
                'required'  =>  true,
                'filters'   =>  array(
                    ['name' => 'StripTags'],
                    ['name' => 'StringTrim']
                )
            ),
            'cnpj'   =>      array(
                'required'  =>  true,
                'filters'   =>  array(
                    ['name' => 'StripTags'],
                    ['name' => 'StringTrim']
                ),
                'validators'    =>  array(
                    ['name' => CnpjValidator::class]
                )
            )
        );
    }

}

为了完成,我在Controller上进行了实体类型处理,将加载此表单,如下所示:(仅相关部分)

//...
if ($id) {
            $cliente = $this->repository->getById($id);
            $form->remove('pessoa');
            // loads form according to the type loaded from the database
            if (!$request->isXmlHttpRequest()) {
                if ($cliente->getPessoa() instanceof \Pessoa\Entity\PessoaFisica) {
                    $form->add($this->pessoaFisicaFieldset);
                } elseif ($cliente->getPessoa() instanceof \Pessoa\Entity\PessoaJuridica) {
                    $form->add($this->pessoaJuridicaFieldset);
                }
                var_dump($cliente->getPessoa());
            }
            $form->bind($cliente);
        }



        if ($request->isPost()) {
            $form->remove('pessoa');
            // loads form according to the type selected in the post
            if ($request->getPost('tipo') == \Pessoa\Entity\Pessoa::PESSOA_FISICA) {
                $form->add($this->pessoaFisicaFieldset);
            } elseif ($request->getPost('tipo') == \Pessoa\Entity\Pessoa::PESSOA_JURIDICA) {
                $form->add($this->pessoaJuridicaFieldset);
            }


            $form->get('tipo')->setValue($request->getPost('tipo'));


            $form->setData($request->getPost());

            if(!$request->isXmlHttpRequest()) {
                if ($form->isValid()) {
                    $cliente = $form->getObject();

                    if ($cliente->getId() != 0) {
                        $cliente->getPessoa()->setCadastradoEm(new \DateTime);
                    }

                    // ...
                }
            }
        }
//...

再次感谢@rkeet!

© www.soinside.com 2019 - 2024. All rights reserved.