ZF2 +原理2-在不满足要求且值为空时创建的实体 [英] ZF2 + Doctrine 2 - Entity created when requirements not met and values empty

查看:89
本文介绍了ZF2 +原理2-在不满足要求且值为空时创建的实体的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

扩展了先前关于表单结构的两个问题验证集合我碰到下一个问题.

Extending on 2 previous questions about form structure and validating collections I've run into the next issue.

我的表格可以正确验证.包括通过字段集包含的集合.但是,如果未设置其最内部的Fieldset的值,则不应导致Entity和与父级的FK关联.

My form validates properly. Including included collections by way of Fieldsets. But the innermost Fieldset should not result in an Entity and a FK association to the parent if its values are not set.

Address可能链接也可能没有链接Coordinates.可以用同一表格创建所有这些内容.

An Address may or may not have linked Coordinates. It's possible to create all of these in the same Form.

但是,如果在表单中未指定任何坐标,则不应创建Coordinates,也不应从Address链接Coordinates.表单中不需要它们,并且实体Coordinates本身需要同时设置纬度和经度这两个属性.

However, the Coordinates should not be created and should not be linked from the Address if no coordinates have been given in the Form. They're not required in the Form and the Entity Coordinates itself requires both properties of Latitude and Longitude to be set.

首先,下面是实体.以下是用于AddressForm的字段集.我已从与Address-> Coordinates链无关的所有内容中删除了东西.

Below, first the Entities. Following are the Fieldsets used for the AddressForm. I've removed stuff from both unrelated to the chain of Address -> Coordinates.

Address.php

Address.php

class Address extends AbstractEntity
{
    // Properties

    /**
     * @var Coordinates
     * @ORM\OneToOne(targetEntity="Country\Entity\Coordinates", cascade={"persist"}, fetch="EAGER", orphanRemoval=true)
     * @ORM\JoinColumn(name="coordinates_id", referencedColumnName="id", nullable=true)
     */
    protected $coordinates;

    // Getters/Setters
}

Coordinates.php

Coordinates.php

class Coordinates extends AbstractEntity
{
    /**
     * @var string
     * @ORM\Column(name="latitude", type="string", nullable=false)
     */
    protected $latitude;

    /**
     * @var string
     * @ORM\Column(name="longitude", type="string", nullable=false)
     */
    protected $longitude;

    // Getters/Setters
}

如上面的实体所示. AddressCoordinates具有单向关系. Coordinates实体需要同时具有latitudelongitude属性,如nullable=false所示.

As is seen in the Entities above. An Address has a OneToOne uni-directional relationship to Coordinates. The Coordinates entity requires both latitude and longitude properties, as seen with the nullable=false.

在那里出错了.如果创建了Address,但未在表单中设置Coordinates的属性,则它仍将创建Coordinates实体,但是将latitudelongitude属性保留为空,即使它们是必需的.

It's there that it goes wrong. If an Address is created, but no Coordinates's properties are set in the form, it still creates a Coordinates Entity, but leaves the latitude and longitude properties empty, even though they're required.

所以,简而言之:

  • 在不应该存在的地方创建一个Coordinates实体
  • Address创建到Coordinates的链接,其中应该不存在
  • A Coordinates Entity is created where non should exist
  • A link to Coordinates is created from Address where non should exist

在字段集"和输入过滤器"下面进一步说明.

Below the Fieldsets and InputFilters to clarify things further.

AddressFieldset.php

AddressFieldset.php

class AddressFieldset extends AbstractFieldset
{
    public function init()
    {
        parent::init();

        // Other properties

        $this->add([
            'type' => CoordinatesFieldset::class,
            'required' => false,
            'name' => 'coordinates',
            'options' => [
                'use_as_base_fieldset' => false,
            ],
        ]);
    }
}

CoordinatesFieldset.php

CoordinatesFieldset.php

class CoordinatesFieldset extends AbstractFieldset
{
    public function init()
    {
        parent::init();

        $this->add([
            'name' => 'latitude',
            'required' => true,
            'type' => Text::class,
            'options' => [
                'label' => _('Latitude'),
            ],
        ]);

        $this->add([
            'name' => 'longitude',
            'required' => true,
            'type' => Text::class,
            'options' => [
                'label' => _('Longitude'),
            ],
        ]);
    }
}

AddressFieldsetInputFilter.php

AddressFieldsetInputFilter.php

class AddressFieldsetInputFilter extends AbstractFieldsetInputFilter
{
    /** @var CoordinatesFieldsetInputFilter $coordinatesFieldsetInputFilter */
    protected $coordinatesFieldsetInputFilter;

    public function __construct(
        CoordinatesFieldsetInputFilter $filter,
        EntityManager $objectManager,
        Translator $translator
    ) {
        $this->coordinatesFieldsetInputFilter = $filter;

        parent::__construct([
            'object_manager' => $objectManager,
            'object_repository' => $objectManager->getRepository(Address::class),
            'translator' => $translator,
        ]);
    }

    /**
     * Sets AddressFieldset Element validation
     */
    public function init()
    {
        parent::init();

        $this->add($this->coordinatesFieldsetInputFilter, 'coordinates');

        // Other filters/validators
    }
}

CoordinatesFieldsetInputFilter.php

CoordinatesFieldsetInputFilter.php

class CoordinatesFieldsetInputFilter extends AbstractFieldsetInputFilter
{
    public function init()
    {
        parent::init();

        $this->add([
            'name' => 'latitude',
            'required' => true,
            'allow_empty' => true,
            'filters' => [
                ['name' => StringTrim::class],
                ['name' => StripTags::class],
            ],
            'validators' => [
                [
                    'name' => StringLength::class,
                    'options' => [
                        'min' => 2,
                        'max' => 255,
                    ],
                ],
                [
                    'name' => Callback::class,
                    'options' => [
                        'callback' => function($value, $context) {
                            //If longitude has a value, mark required
                            if(empty($context['longitude']) && strlen($value) > 0) {
                                $validatorChain = $this->getInputs()['longitude']->getValidatorChain();

                                $validatorChain->attach(new NotEmpty(['type' => NotEmpty::NULL]));
                                $this->getInputs()['longitude']->setValidatorChain($validatorChain);

                                return false;
                            }

                            return true;
                        },
                        'messages' => [
                            'callbackValue' => _('Longitude is required when setting Latitude. Give both or neither.'),
                        ],
                    ],
                ],
            ],
        ]);

        // Another, pretty much identical function for longitude (reverse some params and you're there...)
    }
}

编辑:添加数据库转储图像.显示空的纬度和经度.

Adding a DB Dump image. Shows empty latitude, longitude.

EDIT2 :当我从AddressFieldsetInputFilter输入项中删除'allow_empty' => true,并填写单个输入项(纬度或经度)时,它将正确验证,除非您将两个输入项都留为空白,否则它将中断立即关闭以返回要求输入的内容. (Value is required and can't be empty).

When I remove 'allow_empty' => true, from the AddressFieldsetInputFilter inputs and fill a single input (latitude or longitude), then it validates correctly, unless you leave both inputs empty, then it breaks off immediately to return that the input is required. (Value is required and can't be empty).

推荐答案

我偶然偶然发现了这个答案,允许字段集为空,但如果至少填写了一个输入,则对其进行验证.

By chance did I stumple upon this answer, which was for allowing a Fieldset to be empty but validate it if at least a single input was filled in.

通过从包含答案的AbstractInputFilter类扩展我自己的AbstractFormInputFilterAbstractFieldsetInputFilter类,我现在能够为FielsetInputFilters(例如AddressFieldsetInputFilter)提供附加的->setRequired(false).如果AbstractInputFilter实际上为空,则在AbstractInputFilter中对其进行验证.

By extending my own AbstractFormInputFilter and AbstractFieldsetInputFilter classes from an AbstractInputFilter class, which incorporates the answer, I'm now able to supply FielsetInputFilters, such as the AddressFieldsetInputFilter, with an additional ->setRequired(false). Which is then validated in the AbstractInputFilter, if it actually is empty.

链接的答案给出以下代码:

The linked answer gives this code:

<?php
namespace Application\InputFilter;

use Zend\InputFilter as ZFI;

class InputFilter extends ZFI\InputFilter
{
    private $required = true;

    /**
     * @return boolean
     */
    public function isRequired()
    {
        return $this->required;
    }

    /**
     * @param boolean $required
     *
     * @return $this
     */
    public function setRequired($required)
    {
        $this->required = (bool) $required;
        return $this;
    }

    /**
     * @return bool
     */
    public function isValid()
    {
        if (!$this->isRequired() && empty(array_filter($this->getRawValues()))) {
            return true;
        }

        return parent::isValid();
    }
}

正如我提到的那样,我使用此代码扩展了自己的AbstractInputFilter,从而允许在*FieldsetInputFilterFactory类中进行小的更改.

As I mentioned I used this code to extend my own AbstractInputFilter, allowing small changes in *FieldsetInputFilterFactory classes.

AddressFieldsetInputFilterFactory.php

AddressFieldsetInputFilterFactory.php

class AddressFieldsetInputFilterFactory extends AbstractFieldsetInputFilterFactory
{
    /**
     * @param ServiceLocatorInterface|ControllerManager $serviceLocator
     * @return InputFilter
     */
    public function createService(ServiceLocatorInterface $serviceLocator)
    {
        parent::setupRequirements($serviceLocator, Address::class);

        /** @var CoordinatesFieldsetInputFilter $coordinatesFieldsetInputFilter */
        $coordinatesFieldsetInputFilter = $this->getServiceManager()->get('InputFilterManager')
            ->get(CoordinatesFieldsetInputFilter::class);
        $coordinatesFieldsetInputFilter->setRequired(false); // <-- Added option

        return new AddressFieldsetInputFilter(
            $coordinatesFieldsetInputFilter,
            $this->getEntityManager(),
            $this->getTranslator()
        );
    }
}

对于每个人的项目可能都不是一个好主意,但是它解决了我不总是想要验证Fieldset的问题,并且它确实解决了原始问题,即不创建仅具有ID的实体,如截图所示.问题.

Might not be a good idea for everybody's projects, but it solves my problem of not always wanting to validate a Fieldset and it definitely solves the original issue of not creating an Entity with just an ID, as shown in the screenshot in the question.

这篇关于ZF2 +原理2-在不满足要求且值为空时创建的实体的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆