Intereting Posts
DOMPDF Не поддерживает арабские символы Контроль доступа к классам в PHP Шифровать данные с помощью открытого ключа в c # и расшифровать данные с помощью закрытого ключа в php Google app-engine – загруженные файлы не являются общедоступными в облачном хранилище Google Запустите sql-запрос с таймаутом в PHP или Как в PHP, чтобы остановить запрос sql, как только он уже начался? Использование переменной Javascript в шаблоне Twig с использованием платформы Silex PHPMailer "$ mail-> MsgHTML ($ msg)" проблема с "$ msg" Точная отчетная ссылка от платежей, сделанных с помощью PayPal в Google Analytics PHP regex: как преобразовать строку HTML со ссылками в обычный текст, который показывает URL-адрес после текста в скобках Сессия уже запущена – игнорирование session_start () Xampp Каков правильный способ сравнить две даты в php? Как вы создаете строку на PHP с обратной косой чертой? Предупреждение: mysqli_connect (): (HY000 / 1045): доступ запрещен для пользователя «root» @ «localhost» (с использованием пароля: НЕТ) Как найти день недели с даты с помощью PHP? Как отображать дату и цену в базе данных MySQL и отображать ее в различных форматах в PHP

zf2 Проверка коллекции форм – уникальные элементы в наборах полей

Я хочу добавить уникальные элементы в Zend Form Collection. Я нашел эту потрясающую работу от Арона Керра

Я делаю формы и наборы полей, как в примере Арона Керра, и он отлично работает.

В моем случае я создаю форму для вставки коллекции магазинов из компании.

Моя форма

Прежде всего, у меня есть приложение \ Form \ CompanyStoreForm с StoreFieldset следующим образом:

$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', ), ), )); 

Application \ Form \ Fieldset \ StoreEntityFieldset

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

Разница с Arron Kerrs CategoryFieldset заключается в том, что я добавляю еще один набор полей : Application \ Form \ Fieldset \ AddressFieldset

Приложение \ Форма \ Полеsetset \ AddressFieldset имеет текстовое имя streetName .

Входные фильтры

У CompanyStoresFieldsetInputFilter нет элементов для проверки.

StoreEntityFieldsetInputFilter имеет валидаторы для storeName и Application \ Form \ Fieldset \ 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 есть другой InputFilter AddressFieldsetInputFilter . В AddressFieldsetInputFilter я добавляю InputFilter для streetName.

FormFactory

Добавление всех входных фильтров в форму как это

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

Я использую Aron Kerrs CollectionInputFilter.

Имя storeName должно быть уникальным во всей коллекции. Пока все работает нормально!

Но теперь моя проблема!

Имя улицы должно быть уникальным во всей коллекции. Но элемент находится в AddressFieldset. Я не могу сделать что-то вроде этого:

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

Я думал, что должен расширить Aron Kerrs isValid () от CollectionInputFilter

Арон Керрс Оригинал 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); 

Я думаю, причина в том, что у Fieldset есть собственный InputFilter ()?

Когда я делаю var_dump ($ this-> collectionValues ​​()), я получил многомерный массив всех значений (также из адресного набора). Хорошо! Но я не могу добавлять сообщения об ошибках в элемент в наборе полей.

Как я могу это сделать? Я не хочу вставлять все элементы AddressFieldset в StoreEntityFieldset. (Я использую AddressFieldset также в других формах)

Related of "zf2 Проверка коллекции форм – уникальные элементы в наборах полей"

Я понял. Вы просто можете добавлять значения с помощью

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

Я не знаю, как это не работает вчера. Это была еще одна ошибка.

Я написал решение для своей проблемы. Может быть, это не самое лучшее, но это работает для меня.

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´ta 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'); 

Поэтому позвольте мне объяснить:

Теперь мы можем добавлять элементы как уникальные в полях в нашей коллекции. Мы не можем добавлять коллекции полей в нашу коллекцию, а не другие поля в наших полях. На мой взгляд, если кто-то хочет делать это, им лучше реорганизовать форму 🙂

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 ..'))