Symfony3持久生成的实体

时间:2016-10-17 20:52:46

标签: php mysql symfony doctrine

我正在开发一个保存IP地址和IP范围的项目。目前,我的Range实体引用了两个IP地址实体(网络和广播实体),并且与主机具有OneToMany关系。 IP地址实体与IP范围具有ManyToOne关系,这是可选的。

这是我的IP地址实体:

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

    // relations to other tables
    /**
     * @var IPRange
     * @ORM\ManyToOne(targetEntity="AppBundle\Entity\IPRange", inversedBy="hosts", cascade={"persist", "remove"})
     * @ORM\JoinColumn(name="ip_range_id", referencedColumnName="id", nullable=true)
     */
    private $ipRangeId;

    // entity variables
    /**
     * @var mixed
     * @ORM\Column(name="ip_address", type="binary", length=16, nullable=false, unique=true)
     * @SIAssert\IpPacked(version="all")
     */
    private $ipAddress;
    /**
     * @var string
     * @ORM\Column(name="ip_address_text", type="string", length=50, nullable=false)
     */
    private $ipAddressText;
    /**
     * @var int
     * @ORM\Column(name="cidr", type="smallint", nullable=false, options={"unsigned"=true})
     */
    private $cidr;
    /**
     * @var mixed
     * @ORM\Column(name="gateway", type="binary", length=16, nullable=false)
     */
    private $gateway;
    /**
     * @var string
     * @ORM\Column(name="gateway_text", type="string", length=50, nullable=false)
     */
    private $gatewayText;
    /**
     * @var int
     * @ORM\Column(name="type", type="smallint", options={"unsigned"=true})
     */
    private $type;
    /**
     * @var string
     * @ORM\Column(name="description", type="string", length=50)
     */
    private $description;

    // getters and setters not shown
}

我的IP范围实体:

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

    // relations to other tables
    /**
     * @var IPAddress
     * @ORM\OneToOne(targetEntity="AppBundle\Entity\IPAddress", cascade={"persist", "remove"}, orphanRemoval=true)
     * @ORM\JoinColumn(name="network", referencedColumnName="id", nullable=false)
     */
    private $network;
    /**
     * @var IPAddress
     * @ORM\OneToOne(targetEntity="AppBundle\Entity\IPAddress", cascade={"persist", "remove"}, orphanRemoval=true)
     * @ORM\JoinColumn(name="broadcast", referencedColumnName="id", nullable=false)
     */
    private $broadcast;
    /**
     * @var array
     * @ORM\OneToMany(targetEntity="AppBundle\Entity\IPAddress", mappedBy="ipRangeId")
     */
    private $hosts;

    // entity variables
    /**
     * @var string
     * @ORM\Column(name="description", type="string", length=50, nullable=false)
     */
    private $description;
    /**
     * @var int
     * @ORM\Column(name="cidr", type="smallint", nullable=false, options={"unsigned"=true})
     */
    private $cidr;
    /**
     * @var string
     * @ORM\Column(name="notes", type="text", length=65535, nullable=true)
     */
    private $notes;

    // getters and setters not shown
}

创建新IP范围时的当前流程:

  • 生成新的IP范围实体(显示形式)
  • 从表格中获取信息
  • 生成IP范围实体,其中IP范围实体为空(IP范围尚未保留,因为未创建网络和广播IP地址实体)
  • 保留我的IP范围实体
  • 获取该ID并使用有效的IP范围实体重写我的所有IP地址实体

我必须遗漏一些东西,因为编程创建实体似乎有很多步骤。

有没有更好更有效的方法呢?

已编辑...添加了我的表单类型...

我的IPRangeType:

public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder
        ->add('description', TextType::class, array(
            'required' => true,
            'label' => 'Description:',
            'label_attr' => array(
                'class' => 'text-right middle',
            ),
        ))
        ->add('notes', TextareaType::class, array(
            'required' => false,
            'label' => 'Notes:',
            'label_attr' => array(
                'class' => 'text-right middle',
            ),
        ))
        ->add('cidr', ChoiceType::class, array(
            'required' => true,
            'multiple' => false,
            'expanded' => false,
            'choices' => array (
                'IPv4' => [
                    '/30 (255.255.255.252)' => 30,
                    '/29 (255.255.255.248)' => 29,
                    '/28 (255.255.255.240)' => 28,
                    '/27 (255.255.255.224)' => 27,
                    '/26 (255.255.255.192)' => 26,
                    '/25 (255.255.255.128)' => 25,
                    '/24 (255.255.255.0)' => 24,
                    '/23 (255.255.254.0)' => 23,
                    '/22 (255.255.252.0)' => 22,
                    '/21 (255.255.248.0)' => 21,
                    '/20 (255.255.240.0)' => 20,
                ],
                'IPv6' => [
                    '/64 network' => 64,
                ]
            ),
            'label' => 'CIDR (subnet):',
            'label_attr' => array(
                'class' => 'text-right middle',
            ),
        ))
        ->add('network', IPAddressType::class, array(
            'required' => true,
        ))
        ->add('gateway_select', ChoiceType::class, array(
            'mapped' => false,
            'required' => true,
            'multiple' => false,
            'expanded' => false,
            'choices' => array (
                '- enter in valid IP and CIDR -' => 0,
            ),
            'label' => 'Gateway:',
            'label_attr' => array(
                'class' => 'text-right middle',
            ),
        ))
        ->add('json_data', HiddenType::class, array(
            'mapped' => false,
        ))
    ;
}

我的IPAddressType:

public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder
        ->add('ipAddress', TextType::class, array(
            'required' => true,
            'label' => 'IP Address:',
            'label_attr' => array(
                'class' => 'text-right middle',
            ),
        ))
        ->add('cidr', ChoiceType::class, array(
            'required' => true,
            'multiple' => false,
            'expanded' => false,
            'choices' => array (
                'IPv4' => [
                    '/30 (255.255.255.252)' => 30,
                    '/29 (255.255.255.248)' => 29,
                    '/28 (255.255.255.240)' => 28,
                    '/27 (255.255.255.224)' => 27,
                    '/26 (255.255.255.192)' => 26,
                    '/25 (255.255.255.128)' => 25,
                    '/24 (255.255.255.0)' => 24,
                    '/23 (255.255.254.0)' => 23,
                    '/22 (255.255.252.0)' => 22,
                    '/21 (255.255.248.0)' => 21,
                    '/20 (255.255.240.0)' => 20,
                ],
                'IPv6' => [
                    '/64 network' => 64,
                ]
            ),
            'label' => 'CIDR (subnet):',
            'label_attr' => array(
                'class' => 'text-right middle',
            ),
        ))
        ->add('gateway', TextType::class, array(
            'required' => true,
            'label' => 'Gateway:',
            'label_attr' => array(
                'class' => 'text-right middle',
            ),
        ))
        ->add('type', ChoiceType::class, array(
            'required' => true,
            'multiple' => false,
            'expanded' => false,
            'choices' => IPAddress::TYPE,
            'label' => 'Address Type:',
            'label_attr' => array(
                'class' => 'text-right middle',
            ),
        ))
        ->add('description', TextType::class, array(
            'required' => true,
            'label' => 'Description:',
            'label_attr' => array(
                'class' => 'text-right middle',
            ),
        ))
    ;

    $builder->get('ipAddress')
        ->addModelTransformer(new IPToStringTransformer());

    $builder->get('gateway')
        ->addModelTransformer(new IPToStringTransformer());
}

1 个答案:

答案 0 :(得分:0)

听起来非常迂回。我将详细介绍一下我将采取的一般做法。

我会创建两个表单类型,调用一个IpAddressType和另一个IpRangeType。由于您在IpAddress中进行共享,因此您只需要一种类型,它就是所有相同的数据。

因此,您的表单类型将类似于:

(这是symfony 2.3语法 - 如果你有更新的版本会有一些差异 - 但方法是相同的)

class IpRangeType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('description');
        $builder->add('cidr'); // and other single fields

        $builder->add('network', new IpAddressType());
        $builder->add('broadcast', new IpAddressType());
        $builder->add('hosts', 'collection', ['type' => new IpAddressType()]);
    }

    public function getName()
    {
        return 'ip_range';
    }

    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'YourBundle\Entity\IpRange',
        ));
    }
}

子表单类型。

class IpAddressType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('ipAddress');
        $builder->add('ipAddressText'); // etc etc
    }

    public function getName()
    {
        return 'ip_address';
    }

    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'YourBundle\Entity\IpAddress',
        ));
    }
}

然后在你的控制器中:

$ipRange = new IpRange();
$em = $this->getDoctrine()->getManager();
$form = $this->createForm(new IpRangeType(), $ipRange);
$form->handleRequest($request);
if ($form->isValid()) {
    $em->persist($ipRange);
    $em->flush();
    return $this->redirect($this->generateUrl('your_success_route'));
}

应该那么简单。

注意:您需要在IpRange $ hosts属性上至少设置cascade = persist,否则它不会保留添加到集合中的IpAddress项。

由于IpRange网络上的级联持续存在,广播和主机属性不需要保留单个项目,因此ipAddress实体将自动与父实体相关联。

您需要按照此方法添加主机条目:

http://symfony.com/doc/current/form/form_collections.html

另外请一般查看表单文档,您永远不需要生成'表格是否正确完成的实体(非常特殊情况除外)。

正确实施表单应该返回您的完整实体,并在表单中添加数据,您只需验证&持续。

处理表单提交的文档:http://symfony.com/doc/current/forms.html#handling-form-submissions