Wybraźmy sobie aplikację do analizy tekstu. Ma ona załóżmy wyłapywać fragmenty tekstu na podstawie patternu regex.

User ma podać dane do analizy przez formularz. Może podać albo za pomocą url'a albo przez wklejenie tekstu do textarea.

I teraz pojawia sę taka prosta logika tego formularza: wymagane jest wypełnienie jednago pola, ale zabronione wypełnienie obu oraz niewypełnienie żadnego. Zresztą to wydaje się dosyć oczywiste, bo analiza ma dotyczyć jednego przypadku, a nie dwóch.

Walidacja obu pól dotyczy tylko długości stringa. Docelowo url ma być walidowany pod względem poprawności, ale przyjąłem na razie walidację tylko długości stringa.

Poniżej przedstawiam moje rozwiązanie, które ma jeden mankament, z którym nie mogę sobie poradzić. Otóż niewypełnienie żadnego pola jest walidowane jako poprawne. A powinna być informacja, że wymagane jest wypełnienie jednego pola. Dzieje się tak mimo, że narzucona jest walidacja długości stringa od 3.

Jak zatem moje rozwiązanie poprawić?
  1. <?php
  2.  
  3. namespace Application\Filter;
  4.  
  5. use Application\Form\Test as Form;
  6. use Application\Validator\Text;
  7. use Application\Validator\Url;
  8. use Zend\InputFilter\InputFilter;
  9.  
  10. class Test extends InputFilter
  11. {
  12. public function init()
  13. {
  14. $this->add([
  15. 'name' => Form::TEXT,
  16. 'required' => false,
  17. 'validators' => [
  18. ['name' => Text::class],
  19. ],
  20. ]);
  21. $this->add([
  22. 'name' => Form::URL,
  23. 'required' => false,
  24. 'validators' => [
  25. ['name' => Url::class],
  26. ],
  27. ]);
  28. }
  29. }

  1. <?php
  2.  
  3. namespace Application\Validator;
  4.  
  5. use Zend\Validator\StringLength;
  6. use Zend\Validator\ValidatorInterface;
  7.  
  8. class Text implements ValidatorInterface
  9. {
  10. protected $stringLength;
  11. protected $messages = [];
  12.  
  13. public function __construct()
  14. {
  15. $this->stringLengthValidator = new StringLength();
  16. }
  17.  
  18. public function isValid($value, $context = null)
  19. {
  20. if (empty($context['url'])) {
  21. $this->stringLengthValidator->setMin(3);
  22. $this->stringLengthValidator->setMax(5000);
  23.  
  24. if ($this->stringLengthValidator->isValid($value)) {
  25. return true;
  26. }
  27. $this->messages = $this->stringLengthValidator->getMessages();
  28.  
  29. return false;
  30. }
  31. if (!empty($value)) return false;
  32. }
  33.  
  34. public function getMessages()
  35. {
  36. return $this->messages;
  37. }
  38. }

  1. <?php
  2.  
  3. namespace Application\Validator;
  4.  
  5. use Zend\Validator\StringLength;
  6. use Zend\Validator\ValidatorInterface;
  7.  
  8. class Url implements ValidatorInterface
  9. {
  10. const ERROR_NOT_ALLOWED_STRING = 'string-not-allowed';
  11. protected $stringLength;
  12. protected $messages = [
  13. self::ERROR_NOT_ALLOWED_STRING => 'Only one of text and url field may be filled out.',
  14. ];
  15.  
  16. public function __construct()
  17. {
  18. $this->stringLengthValidator = new StringLength();
  19. }
  20.  
  21. public function isValid($value, $context = null)
  22. {
  23. if (empty($context['text'])) {
  24. $this->stringLengthValidator->setMin(3);
  25. $this->stringLengthValidator->setMax(500);
  26.  
  27. if ($this->stringLengthValidator->isValid($value)) {
  28. return true;
  29. }
  30. $this->messages = $this->stringLengthValidator->getMessages();
  31.  
  32. return false;
  33. }
  34. if (!empty($value)) return false;
  35. }
  36.  
  37. public function getMessages()
  38. {
  39. return $this->messages;
  40. }
  41. }


Edit
Jest rozwiązanie!
https://stackoverflow.com/questions/4921668...lidation-in-zf3

W skrócie, dodać 2 pozycje do opcji filtrów w klasie filtra:
  1. 'allow_empty' => true,
  2. 'continue_if_empty' => true,


I doszły kosmetyczne dodatki, widoczne na SO.