3

How do I apply a filter to a field element with the contents of an array?

For example:

$this->add(
  "name" => "tags",
  "type" => "text",
  "filter" => array(
    array("name" => "StripTags"),
    array("name" => "StringTrim")
  )
);

$tags[0] = "PHP";
$tags[1] = "CSS";

If I attempt to filter I receive an error saying a scalar object is excepted, array given.

4 Answers 4

11

This isn't really possible at this time. Your best bet is to use a Callback filter and filter each Item individually. Something like this

$this->add(
  "name" => "tags",
  "type" => "text",
  "filter" => array(
    array("name" => "Callback", "options" => array(
       "callback" => function($tags) {
          $strip = new \Zend\Filter\StripTags();
          $trim = new \Zend\Filter\StringTrim();
          foreach($tags as $key => $tag) {
            $tag = $strip->filter($tag);
            $tag = $trim->filter($tag);
            $tags[$key] = $tag;
          }
          return $tags;
    }))
  )
);
Sign up to request clarification or add additional context in comments.

2 Comments

This code is 99% correct. The only tweak needed was to throw "callback" => function($tags){} block into an "options" array. If you update the code, I'll accept this as the correct answer. Thanks for the help.
Yup, and I forgot to take out the second StringTrim. Good catch :)
8

I realize this is old but you can specify the input type as ArrayInput and InputFilter will handle it as expected:

  "name" => "tags",
  "type" => "Zend\\InputFilter\\ArrayInput", // Treat this field as an array of inputs
  "filter" => array(
    array("name" => "StripTags"),
    array("name" => "StringTrim")
  )

Comments

4

I've made a CollectionValidator that applies an existing validator to all items in an array.

I'm using it with Apigility as such:

'input_filter_specs' => [
    'Api\\Contact\\Validator' => [
        [
            'name'       => 'addresses',
            'required'   => false,
            'filters'    => [],
            'validators' => [
                [
                    'name'    => 'Application\\Validator\\CollectionValidator',
                    'options' => ['validator' => 'Api\\Address\\Validator']
                ]
            ],
            'description'=> 'List of addresses for contact'
        ],
        [
            'name'       => 'birthdate',
            # ...
        ]
    ],
]

I'm not sure if this is how you would use a validator inside a controller, but probably something like this:

new Collection(array('validator' => 'Zend\Validator\CreditCard'))

It returns validation_messages per index. Let's say it was REST POST request to create a contact, it indicates that the second address contains an error in the zipcode field.

{
  "detail": "Failed Validation",
  "status": 422,
  "title": "Unprocessable Entity",
  "type": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html",
  "validation_messages": {
    "addresses": {
      "1": {
        "zipcode": {
          "notAlnum": "The input contains characters which are non alphabetic and no digits"
        }
      }
    },
    "birthdate": {
      "dateInvalidDate": "The input does not appear to be a valid date"
    }
  }
}

The Collection validator:

<?php
namespace Application\Validator;
class Collection extends \Zend\Validator\AbstractValidator  implements \Zend\ServiceManager\ServiceLocatorAwareInterface {
    protected $serviceLocator;
    protected $em;
    protected $messages;

    protected $options = array(
        'validator' => null
    );

    public function setServiceLocator(\Zend\ServiceManager\ServiceLocatorInterface $serviceLocator) {
        $this->serviceLocator = $serviceLocator->getServiceLocator();
    }

    public function getServiceLocator() {
        return $this->serviceLocator;
    }

    public function isValid($array) {
        $inputFilterManager = $this->getServiceLocator()->get('inputfiltermanager');
        $validatorName = $this->getOption('validator');

        $this->messages = [];
        $isvalid = true;
        foreach($array as $index => $item) {
            $inputFilter = $inputFilterManager->get($validatorName);
            $inputFilter->setData($item);
            $isvalid = $isvalid && $inputFilter->isValid($item);
            foreach($inputFilter->getMessages() as $field => $errors) {
                foreach($errors as $key => $string) {
                    $this->messages[$index][$field][$key] = $string;
                }
            }
        }
        return $isvalid;
    }

    public function getMessages() {
        return $this->messages;
    }
}

Current limitations:

  • No support for translation
  • Only the errors for the first erroneous array item are returned.

Comments

0

I had a very simular issue and I was able to solve it with Zend\Form\Element\Collection.

With the Collection Element I was able to validate inputs that looks like

$post = [
    [
        'idUser' => 1,
        'address' => 'foo street',
    ],
    [
        'idUser' => 2,
        'address' => 'bar street',
    ],
];

For a more detailed explanation check out the Zend Documentation and this working example

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.