Zend Framework 2 filter / validate array of conten

2020-03-05 02:50发布

问题:

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.

回答1:

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


回答2:

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")
  )


回答3:

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.


回答4:

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