ZF2形式收集验证 - 独特的元素在字段集(zf2 Form Collection Validati

2019-10-23 04:00发布

我想在一个Zend表格Collection中添加独特的元素。 我发现从这个真棒工作阿隆克尔

我做的形式和字段集像阿隆Kerr's例子,它工作正常。

在我来说,我创建表单,从公司门店插入的集合。

我的表

首先,我有这样的一个StoreFieldset 申请\表格\ CompanyStoreForm:

$this->add(array(
                'name' => 'company',
                'type' => 'Application\Form\Stores\CompanyStoresFieldset',
            ));

该字段集

申请\表格\店\ CompanyStoresFieldset有实体店这样的集合:

$this->add(array(
            'type' => 'Zend\Form\Element\Collection',
            'name' => 'stores',
            'options' => array(
                'target_element' => array(
                    'type' => 'Application\Form\Fieldset\StoreEntityFieldset',
                ),
            ),
        ));

申请\表格\字段集\ StoreEntityFieldset

$this->add(array(
            'name' => 'storeName',
            'attributes' => ...,
            'options' => ...,
        ));

        //AddressFieldset
        $this->add(array(
            'name' => 'address',
            'type' => 'Application\Form\Fieldset\AddressFieldset',
        ));

到阿龙Kerrs CategoryFieldset的差异我再增加一个字段集: 应用程序\表格\字段集\ AddressFieldset

申请\表格\字段集\ AddressFieldset具有文本元素streetName。

该Inputfilters

CompanyStoresFieldsetInputFilter没有元件进行验证。

StoreEntityFieldsetInputFilterSTORENAME应用程序\表格\字段集\ AddressFieldset这样的验证

public function __construct() {
        $factory = new InputFactory(); 

        $this->add($factory->createInput([ 
            'name' => 'storeName', 
            'required' => true, 
            'filters' => array( ....
            ),
            'validators' => array(...
            ),
        ]));

        $this->add(new AddressFieldsetInputFilter(), 'address');

    }

AddressFieldset有另一个输入过滤AddressFieldsetInputFilter。AddressFieldsetInputFilter我增加了对streetName一个输入过滤器。

FormsFactory

将所有Inputfilters以这样的形式

    public function createService(ServiceLocatorInterface $serviceLocator) {
            $form = $serviceLocator->get('FormElementManager')->get('Application\Form\CompanyStoreForm');

            //Create a Form Inputfilter
            $formFilter = new InputFilter();

            //Create Inputfilter for CompanyStoresFieldsetInputFilter()
            $formFilter->add(new CompanyStoresFieldsetInputFilter(), 'company');

            //Create Inputfilter for StoreEntityFieldsetInputFilter()
            $storeInputFilter = new CollectionInputFilter();
            $storeInputFilter->setInputFilter(new StoreEntityFieldsetInputFilter());
            $storeInputFilter->setUniqueFields(array('storeName'));
            $storeInputFilter->setMessage('Just insert one entry with this store name.');
            $formFilter->get('company')->add($storeInputFilter, 'stores');


            $form->setInputFilter($formFilter);


            return $form;
        }

我用阿隆Kerrs CollectionInputFilter。

STORENAME应该是整个集合中是唯一的。 一切工作正常,到目前为止!

但现在我的问题!

streetName应该是整个集合中是唯一的。 但元素在AddressFieldset。 我不能做这样的事情:

$storeInputFilter->setUniqueFields(array('storeName', 'address' => array('streetName')));

我想我应该从CollectionInputFilter延长阿隆Kerrs 的isValid()

阿隆Kerrs原始的isValid()

public function isValid()
{
    $valid = parent::isValid();

// Check that any fields set to unique are unique
if($this->uniqueFields)
{
    // for each of the unique fields specified spin through the collection rows and grab the values of the elements specified as unique.
    foreach($this->uniqueFields as $k => $elementName)
    {
        $validationValues = array();
        foreach($this->collectionValues as $rowKey => $rowValue)
        {
            // Check if the row has a deleted element and if it is set to 1. If it is don't validate this row.
            if(array_key_exists('deleted', $rowValue) && $rowValue['deleted'] == 1) continue;

            $validationValues[] = $rowValue[$elementName];
        }


        // Get only the unique values and then check if the count of unique values differs from the total count
        $uniqueValues = array_unique($validationValues);
        if(count($uniqueValues) < count($validationValues))
        {            
            // The counts didn't match so now grab the row keys where the duplicate values were and set the element message to the element on that row
            $duplicates = array_keys(array_diff_key($validationValues, $uniqueValues));
            $valid = false;
            $message = ($this->getMessage()) ? $this->getMessage() : $this::UNIQUE_MESSAGE;
            foreach($duplicates as $duplicate)
            {
                $this->invalidInputs[$duplicate][$elementName] = array('unique' => $message);
            }
        }
    }

    return $valid;
}
}

首先,我尝试(只是用于测试)在集合的第一个条目添加一个错误消息streetName。

$this->invalidInputs[0]['address']['streetName'] = array('unique' => $message);

但它好好尝试的工作。

添加它来STORENAME它的工作原理

$this->invalidInputs[0]['storeName'] = array('unique' => $message);

我想原因是字段集有一个自己的输入过滤器()?

当我做的var_dump($这- > collectionValues())1接收到的所有的值(也addressFieldset的)的多维阵列。 没关系! 但我不能添加的错误消息,在字段集的元素。

我怎样才能做到这一点? 我不希望插入在StoreEntityFieldset的AddressFieldset的所有元素。 (我用的是AddressFieldset还以其他形式)

Answer 1:

我想到了。 您只需可以添加值与

$this->invalidInputs[<entry-key>]['address']['streetName'] = array('unique' => $message);

我不知道是怎么回事不昨天工作。 这又是一个错误。

我写了我的问题的解决方案。 也许it's不是最好的,但它为我工作。

CollectionInputFilter

class CollectionInputFilter extends ZendCollectionInputFilter
{    
    protected $uniqueFields;
    protected $validationValues = array();
    protected $message = array();

    const UNIQUE_MESSAGE = 'Each item must be unique within the collection';

    /**
     * @return the $message
     */
    public function getMessageByElement($elementName, $fieldset = null)
    {
        if($fieldset != null){
            return $this->message[$fieldset][$elementName];
        }
        return $this->message[$elementName];
    }

    /**
     * @param field_type $message
     */
    public function setMessage($message)
    {
        $this->message = $message;
    }

    /**
     * @return the $uniqueFields
     */
    public function getUniqueFields()
    {
        return $this->uniqueFields;
    }

 /**
     * @param multitype:string  $uniqueFields
     */
    public function setUniqueFields($uniqueFields)
    {
        $this->uniqueFields = $uniqueFields;
    }

    public function isValid()
    {
        $valid = parent::isValid();

        // Check that any fields set to unique are unique
        if($this->uniqueFields)
        {
            foreach($this->uniqueFields as $key => $elementOrFieldset){
                // if the $elementOrFieldset is a fieldset, $key is our fieldset name, $elementOrFieldset is our collection of elements we have to check
                if(is_array($elementOrFieldset) && !is_numeric($key)){
                    // We need to validate every element in the fieldset that should be unique
                    foreach($elementOrFieldset as $elementKey => $elementName){
                        // $key is our fieldset key, $elementName is the name of our element that should be unique
                        $validationValues = $this->getValidCollectionValues($elementName, $key);

                        // get just unique values
                        $uniqueValues = array_unique($validationValues);

                        //If we have a difference, not all are unique
                        if(count($uniqueValues) < count($validationValues))
                        {
                            // The counts didn't match so now grab the row keys where the duplicate values were and set the element message to the element on that row
                            $duplicates = array_keys(array_diff_key($validationValues, $uniqueValues));
                            $valid = false;
                            $message = ($this->getMessageByElement($elementName, $key)) ? $this->getMessageByElement($elementName, $key) : $this::UNIQUE_MESSAGE;
                            // set error messages
                            foreach($duplicates as $duplicate)
                            {
                                //$duplicate = our collection entry key, $key is our fieldsetname
                                $this->invalidInputs[$duplicate][$key][$elementName] = array('unique' => $message);
                            }
                        }
                    }
                }
                //its just a element in our collection, $elementOrFieldset is a simple element
                else {
                    // in this case $key is our element key , we don´t need the second param because we haven´t a fieldset
                    $validationValues = $this->getValidCollectionValues($elementOrFieldset);

                    $uniqueValues = array_unique($validationValues);
                    if(count($uniqueValues) < count($validationValues))
                    {            
                        // The counts didn't match so now grab the row keys where the duplicate values were and set the element message to the element on that row
                        $duplicates = array_keys(array_diff_key($validationValues, $uniqueValues));
                        $valid = false;
                        $message = ($this->getMessageByElement($elementOrFieldset)) ? $this->getMessageByElement($elementOrFieldset) : $this::UNIQUE_MESSAGE;
                        foreach($duplicates as $duplicate)
                        {
                            $this->invalidInputs[$duplicate][$elementOrFieldset] = array('unique' => $message);
                        }
                    }
                }
            }

        }
        return $valid;
    }

    /**
     * 
     * @param type $elementName
     * @param type $fieldset
     * @return type
     */
    public function getValidCollectionValues($elementName, $fieldset = null){
        $validationValues = array();
        foreach($this->collectionValues as $rowKey => $collection){
            // If our values are in a fieldset
            if($fieldset != null && is_array($collection[$fieldset])){
                $rowValue = $collection[$fieldset][$elementName];
            }
            else{
                //collection is one element like $key => $value
                $rowValue = $collection[$elementName];
            }
            // Check if the row has a deleted element and if it is set to 1. If it is don't validate this row.
            if($rowValue == 1 && $rowKey == 'deleted') continue;
            $validationValues[$rowKey] = $rowValue;
        }
        return $validationValues;
    }


    public function getMessages()
    {
        $messages = array();
        if (is_array($this->getInvalidInput()) || $this->getInvalidInput() instanceof Traversable) {
            foreach ($this->getInvalidInput() as $key => $inputs) {
                foreach ($inputs as $name => $input) {
                    if(!is_string($input) && !is_array($input))
                    {
                        $messages[$key][$name] = $input->getMessages();                                                
                        continue;
                    }         
                    $messages[$key][$name] = $input;
                }
            }
        }
        return $messages;
    }
}

定义CollectionInputFilter(在工厂)

$storeInputFilter = new CollectionInputFilter();
        $storeInputFilter->setInputFilter(new StoreEntityFieldsetInputFilter());
        $storeInputFilter->setUniqueFields(array('storeName', 'address' => array('streetName')));
        $storeInputFilter->setMessage(array('storeName' => 'Just insert one entry with this store name.', 'address' => array('streetName' => 'You already insert a store with this street name')));
        $formFilter->get('company')->add($storeInputFilter, 'stores');

因此,让我解释一下:

现在,我们可以在集合中的字段集添加元素为独特。 我们不能我们收集和我们的fieldsets不是另一个字段集在增加收集字段集。 在如果有人想这样做的情况下我认为,他们应该更好地重构形式:-)

setUniqueFields添加一个简单的元素作为唯一

array('your-unique-element','another-element'); 

如果你想加入一个字段作为唯一一个元素

array('your-unique-element', 'fieldsetname' => array('your-unique-element-in-fieldset'))

我们可以用setMessage每一个元素添加特殊消息

添加消息的集合中元素

array('storeName' => 'Just insert one entry...')

在一个字段的元素添加消息

array('fieldset-name' => array('your-unique-element-in-fieldset' => 'You already insert ..'))


文章来源: zf2 Form Collection Validation - Unique Elements in Fieldsets