Last active
January 22, 2021 10:30
-
-
Save aronkerr/7275777 to your computer and use it in GitHub Desktop.
ZF2 Form Collection Validation - Unique
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Application\Entity | |
class Brand | |
{ | |
/** | |
* @var string | |
\*/ | |
protected $name; | |
/** | |
* @var string | |
\*/ | |
protected $url; | |
/** | |
* @param string $name | |
* @return Brand | |
\*/ | |
public function setName($name) | |
{ | |
$this->name = $name; | |
return $this; | |
} | |
/** | |
* @return string | |
\*/ | |
public function getName() | |
{ | |
return $this->name; | |
} | |
/** | |
* @param string $url | |
* @return Brand | |
\*/ | |
public function setUrl($url) | |
{ | |
$this->url = $url; | |
return $this; | |
} | |
/** | |
* @return string | |
\*/ | |
public function getUrl() | |
{ | |
return $this->url; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Application\Entity | |
class Category | |
{ | |
/** | |
* @var string | |
\*/ | |
protected $name; | |
/** | |
* @param string $name | |
* @return Category | |
\*/ | |
public function setName($name) | |
{ | |
$this->name = $name; | |
return $this; | |
} | |
/** | |
* @return string | |
\*/ | |
public function getName() | |
{ | |
return $this->name; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Application\Entity; | |
class Product | |
{ | |
/** | |
* @var string | |
\*/ | |
protected $name; | |
/** | |
* @var int | |
\*/ | |
protected $price; | |
/** | |
* @var Brand | |
\*/ | |
protected $brand; | |
/** | |
* @var array | |
\*/ | |
protected $categories; | |
/** | |
* @param string $name | |
* @return Product | |
\*/ | |
public function setName($name) | |
{ | |
$this->name = $name; | |
return $this; | |
} | |
/** | |
* @return string | |
\*/ | |
public function getName() | |
{ | |
return $this->name; | |
} | |
/** | |
* @param int $price | |
* @return Product | |
\*/ | |
public function setPrice($price) | |
{ | |
$this->price = $price; | |
return $this; | |
} | |
/** | |
* @return int | |
\*/ | |
public function getPrice() | |
{ | |
return $this->price; | |
} | |
/** | |
* @param Brand $brand | |
* @return Product | |
\*/ | |
public function setBrand(Brand $brand) | |
{ | |
$this->brand = $brand; | |
return $this; | |
} | |
/** | |
* @return Brand | |
\*/ | |
public function getBrand() | |
{ | |
return $this->brand; | |
} | |
/** | |
* @param array $categories | |
* @return Product | |
\*/ | |
public function setCategories(array $categories) | |
{ | |
$this->categories = $categories; | |
return $this; | |
} | |
/** | |
* @return array | |
\*/ | |
public function getCategories() | |
{ | |
return $this->categories; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Application\Form; | |
use Application\Entity\Brand; | |
use Zend\Form\Fieldset; | |
use Zend\InputFilter\InputFilterProviderInterface; | |
use Zend\Stdlib\Hydrator\ClassMethods as ClassMethodsHydrator; | |
class BrandFieldset extends Fieldset implements InputFilterProviderInterface | |
{ | |
public function __construct() | |
{ | |
parent::__construct('brand'); | |
$this->setHydrator(new ClassMethodsHydrator(false)) | |
->setObject(new Brand()); | |
$this->add(array( | |
'name' => 'name', | |
'options' => array( | |
'label' => 'Name of the brand' | |
), | |
'attributes' => array( | |
'required' => 'required' | |
) | |
)); | |
$this->add(array( | |
'name' => 'url', | |
'type' => 'Zend\Form\Element\Url', | |
'options' => array( | |
'label' => 'Website of the brand' | |
), | |
'attributes' => array( | |
'required' => 'required' | |
) | |
)); | |
} | |
/** | |
* @return array | |
\*/ | |
public function getInputFilterSpecification() | |
{ | |
return array( | |
'name' => array( | |
'required' => true, | |
) | |
); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Application\Form; | |
use Application\Entity\Brand; | |
use Zend\Form\Fieldset; | |
use Zend\Stdlib\Hydrator\ClassMethods as ClassMethodsHydrator; | |
class BrandFieldset extends Fieldset | |
{ | |
public function __construct() | |
{ | |
parent::__construct('brand'); | |
$this->setHydrator(new ClassMethodsHydrator(false)) | |
->setObject(new Brand()); | |
$this->add(array( | |
'name' => 'name', | |
'options' => array( | |
'label' => 'Name of the brand' | |
), | |
'attributes' => array( | |
'required' => 'required' | |
) | |
)); | |
$this->add(array( | |
'name' => 'url', | |
'type' => 'Zend\Form\Element\Url', | |
'options' => array( | |
'label' => 'Website of the brand' | |
), | |
'attributes' => array( | |
'required' => 'required' | |
) | |
)); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Application\Form; | |
use Zend\InputFilter\InputFilter; | |
use Zend\InputFilter\Factory as InputFactory; | |
class BrandFieldsetFilter extends InputFilter | |
{ | |
public function __construct() | |
{ | |
$factory = new InputFactory(); | |
$this->add($factory->createInput(array( | |
'name' => 'name', | |
'required' => true, | |
))); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Application\Form; | |
use Application\Entity\Category; | |
use Zend\Form\Fieldset; | |
use Zend\InputFilter\InputFilterProviderInterface; | |
use Zend\Stdlib\Hydrator\ClassMethods as ClassMethodsHydrator; | |
class CategoryFieldset extends Fieldset implements InputFilterProviderInterface | |
{ | |
public function __construct() | |
{ | |
parent::__construct('category'); | |
$this->setHydrator(new ClassMethodsHydrator(false)) | |
->setObject(new Category()); | |
$this->setLabel('Category'); | |
$this->add(array( | |
'name' => 'name', | |
'options' => array( | |
'label' => 'Name of the category' | |
), | |
'attributes' => array( | |
'required' => 'required' | |
) | |
)); | |
} | |
/** | |
* @return array | |
\*/ | |
public function getInputFilterSpecification() | |
{ | |
return array( | |
'name' => array( | |
'required' => true, | |
) | |
); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Application\Form; | |
use Application\Entity\Category; | |
use Zend\Form\Fieldset; | |
use Zend\Stdlib\Hydrator\ClassMethods as ClassMethodsHydrator; | |
class CategoryFieldset extends Fieldset | |
{ | |
public function __construct() | |
{ | |
parent::__construct('category'); | |
$this->setHydrator(new ClassMethodsHydrator(false)) | |
->setObject(new Category()); | |
$this->setLabel('Category'); | |
$this->add(array( | |
'name' => 'name', | |
'options' => array( | |
'label' => 'Name of the category' | |
), | |
'attributes' => array( | |
'required' => 'required' | |
) | |
)); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Application\Form; | |
use Zend\InputFilter\InputFilter; | |
use Zend\InputFilter\Factory as InputFactory; | |
class CategoryFieldsetFilter extends InputFilter | |
{ | |
public function __construct() | |
{ | |
$factory = new InputFactory(); | |
$this->add($factory->createInput(array( | |
'name' => 'name', | |
'required' => true, | |
))); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Application\Form; | |
use Zend\Form\Form; | |
use Zend\InputFilter\InputFilter; | |
use Zend\Stdlib\Hydrator\ClassMethods as ClassMethodsHydrator; | |
class CreateProduct extends Form | |
{ | |
public function __construct() | |
{ | |
parent::__construct('create_product'); | |
$this->setAttribute('method', 'post') | |
->setHydrator(new ClassMethodsHydrator(false)) | |
->setInputFilter(new InputFilter()); | |
$this->add(array( | |
'type' => 'Application\Form\ProductFieldset', | |
'options' => array( | |
'use_as_base_fieldset' => true | |
) | |
)); | |
$this->add(array( | |
'type' => 'Zend\Form\Element\Csrf', | |
'name' => 'csrf' | |
)); | |
$this->add(array( | |
'name' => 'submit', | |
'attributes' => array( | |
'type' => 'submit', | |
'value' => 'Send' | |
) | |
)); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Application\Form; | |
use Zend\Form\Form; | |
use Zend\InputFilter\InputFilter; | |
use Zend\Stdlib\Hydrator\ClassMethods as ClassMethodsHydrator; | |
class CreateProduct extends Form | |
{ | |
public function __construct() | |
{ | |
parent::__construct('create_product'); | |
$this->setAttribute('method', 'post') | |
->setHydrator(new ClassMethodsHydrator(false)) | |
->setInputFilter(new CreateProductFormFilter()); | |
$this->add(array( | |
'type' => 'Application\Form\ProductFieldset', | |
'name' => 'product', | |
'options' => array( | |
'use_as_base_fieldset' => true | |
) | |
)); | |
$this->add(array( | |
'type' => 'Zend\Form\Element\Csrf', | |
'name' => 'csrf' | |
)); | |
$this->add(array( | |
'name' => 'submit', | |
'attributes' => array( | |
'type' => 'submit', | |
'value' => 'Send' | |
) | |
)); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Application\Form; | |
use Zend\InputFilter\InputFilter; | |
use Zend\InputFilter\Factory as InputFactory; | |
class CreateProductFormFilter extends InputFilter | |
{ | |
public function __construct() | |
{ | |
$factory = new InputFactory(); | |
$this->add(new ProductFieldsetFilter(), 'product'); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Application\Form; | |
use Application\Entity\Product; | |
use Zend\Form\Fieldset; | |
use Zend\InputFilter\InputFilterProviderInterface; | |
use Zend\Stdlib\Hydrator\ClassMethods as ClassMethodsHydrator; | |
class ProductFieldset extends Fieldset implements InputFilterProviderInterface | |
{ | |
public function __construct() | |
{ | |
parent::__construct('product'); | |
$this->setHydrator(new ClassMethodsHydrator(false)) | |
->setObject(new Product()); | |
$this->add(array( | |
'name' => 'name', | |
'options' => array( | |
'label' => 'Name of the product' | |
), | |
'attributes' => array( | |
'required' => 'required' | |
) | |
)); | |
$this->add(array( | |
'name' => 'price', | |
'options' => array( | |
'label' => 'Price of the product' | |
), | |
'attributes' => array( | |
'required' => 'required' | |
) | |
)); | |
$this->add(array( | |
'type' => 'Application\Form\BrandFieldset', | |
'name' => 'brand', | |
'options' => array( | |
'label' => 'Brand of the product' | |
) | |
)); | |
$this->add(array( | |
'type' => 'Zend\Form\Element\Collection', | |
'name' => 'categories', | |
'options' => array( | |
'label' => 'Please choose categories for this product', | |
'count' => 2, | |
'should_create_template' => true, | |
'allow_add' => true, | |
'target_element' => array( | |
'type' => 'Application\Form\CategoryFieldset' | |
) | |
) | |
)); | |
} | |
/** | |
* Should return an array specification compatible with | |
* {@link Zend\InputFilter\Factory::createInputFilter()}. | |
* | |
* @return array | |
\*/ | |
public function getInputFilterSpecification() | |
{ | |
return array( | |
'name' => array( | |
'required' => true, | |
), | |
'price' => array( | |
'required' => true, | |
'validators' => array( | |
array( | |
'name' => 'Float' | |
) | |
) | |
) | |
); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Application\Form; | |
use Application\Entity\Product; | |
use Zend\Form\Fieldset; | |
use Zend\Stdlib\Hydrator\ClassMethods as ClassMethodsHydrator; | |
class ProductFieldset extends Fieldset | |
{ | |
public function __construct() | |
{ | |
parent::__construct('product'); | |
$this->setHydrator(new ClassMethodsHydrator(false)) | |
->setObject(new Product()); | |
$this->add(array( | |
'name' => 'name', | |
'options' => array( | |
'label' => 'Name of the product' | |
), | |
'attributes' => array( | |
'required' => 'required' | |
) | |
)); | |
$this->add(array( | |
'name' => 'price', | |
'options' => array( | |
'label' => 'Price of the product' | |
), | |
'attributes' => array( | |
'required' => 'required' | |
) | |
)); | |
$this->add(array( | |
'type' => 'Application\Form\BrandFieldset', | |
'name' => 'brand', | |
'options' => array( | |
'label' => 'Brand of the product' | |
) | |
)); | |
$this->add(array( | |
'type' => 'Zend\Form\Element\Collection', | |
'name' => 'categories', | |
'options' => array( | |
'label' => 'Please choose categories for this product', | |
'count' => 2, | |
'should_create_template' => true, | |
'allow_add' => true, | |
'target_element' => array( | |
'type' => 'Application\Form\CategoryFieldset' | |
) | |
) | |
)); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace Application\Form; | |
use Zend\InputFilter\InputFilter; | |
use Zend\InputFilter\Factory as InputFactory; | |
class ProductFieldsetFilter extends InputFilter | |
{ | |
public function __construct() | |
{ | |
$factory = new InputFactory(); | |
$this->add($factory->createInput(array( | |
'name' => 'name', | |
'required' => true, | |
))); | |
$this->add($factory->createInput(array( | |
'name' => 'price', | |
'required' => true, | |
'validators' => array( | |
array('name' => 'Float') | |
) | |
))); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Application\Form; | |
use Zend\InputFilter\InputFilter; | |
use Zend\InputFilter\Factory as InputFactory; | |
use Zend\InputFilter\CollectionInputFilter; | |
class ProductFieldsetFilter extends InputFilter | |
{ | |
public function __construct() | |
{ | |
$factory = new InputFactory(); | |
$this->add($factory->createInput(array( | |
'name' => 'name', | |
'required' => true, | |
))); | |
$this->add($factory->createInput(array( | |
'name' => 'price', | |
'required' => true, | |
'validators' => array( | |
array('name' => 'Float') | |
) | |
))); | |
// Add the brand fieldset filter | |
$this->add(new BrandFieldsetFilter(), 'brand'); | |
// Add the categories collection filter | |
$categoriesFilter = new CollectionInputFilter(); | |
$categoriesFilter->setInputFilter(new CategoryFieldsetFilter()); | |
$this->add($categoriesFilter, 'categories'); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Application\Form; | |
use Zend\InputFilter\InputFilter; | |
use Zend\InputFilter\Factory as InputFactory; | |
use Application\InputFilter\CollectionInputFilter; | |
class ProductFieldsetFilter extends InputFilter | |
{ | |
public function __construct() | |
{ | |
$factory = new InputFactory(); | |
$this->add($factory->createInput(array( | |
'name' => 'name', | |
'required' => true, | |
))); | |
$this->add($factory->createInput(array( | |
'name' => 'price', | |
'required' => true, | |
'validators' => array( | |
array('name' => 'Float') | |
) | |
))); | |
// Add the brand fieldset filter | |
$this->add(new BrandFieldsetFilter(), 'brand'); | |
// Add the categories collection filter | |
$categoriesFilter = new CollectionInputFilter(); | |
$categoriesFilter->setInputFilter(new CategoryFieldsetFilter()); | |
$categoriesFilter->setUniqueFields(array('name')); | |
$categoriesFilter->setMessage('Each category must be unique.'); | |
$this->add($categoriesFilter, 'categories'); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Application\InputFilter; | |
use Traversable; | |
use Zend\InputFilter\CollectionInputFilter as ZendCollectionInputFilter; | |
class CollectionInputFilter extends ZendCollectionInputFilter | |
{ | |
protected $uniqueFields; | |
protected $message; | |
const UNIQUE_MESSAGE = 'Each item must be unique within the collection'; | |
/** | |
* @return the $message | |
*/ | |
public function getMessage() | |
{ | |
return $this->message; | |
} | |
/** | |
* @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) | |
{ | |
// 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->collectionData 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->collectionInvalidInputs[$duplicate][$elementName] = array('unique' => $message); | |
} | |
} | |
} | |
return $valid; | |
} | |
} | |
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; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment