2

I have one small question about validating nested json data. For example, I have similar PATCH request as this:

{
    "awesome": "yes",
    "myObject": {
        "some_property": "Text Example value",
        "another_property": "1965"
    }
}

What is the proper and maybe correct way to set filters and validators for this nested data some_property and another_property?

Thanks a lot for answers

Wilt
  • 41,477
  • 12
  • 152
  • 203
Myroslav
  • 443
  • 1
  • 5
  • 11

2 Answers2

9

I know this answer is quite late. I stumbled on the same issue (unrelated to Apigility). After a lot of try & error I found a fully working InputFilter specification on validating nested fields / collections as well as keys named type. Adding this here for reference should others find this (hello future me).

Nested Objects

Already answered by Wilt, adding for completeness.

$data = [
    'root-key' => [
        'sub-key' => 'my-value',
        'sub-key2' => 'my-other-value',
    ],
    'simple-key' => 'simple-value'
];

'input_filter_specs' => [
    'my-filter' => [
        'root-key' => [
            'type' => InputFilter::class,
            'sub-key' => [
                'required' => true,
                'filters' => [ /** Add filters **/ ],
                'validators' => [ /** Add validators **/],
            ],
            'sub-key2' => [
                'required' => true,
                'filters' => [ /** Add filters **/ ],
                'validators' => [ /** Add validators **/],
            ],
        ],
        'simple-key' => [
            'required' => true,
            'filters' => [ /** Add filters **/ ],
            'validators' => [ /** Add validators **/],
        ],
    ],
],

Collections of Objects

For some reason the specification for validating a collection of objects is a bit different:

$data = [
    'root-key' => [[
        'sub-key' => 'my-value',
        'sub-key2' => 'my-other-value',
    ], [
        'sub-key' => 'my-value',
        'sub-key2' => 'my-other-value',
    ]],
    'simple-key' => 'simple-value'
];

'input_filter_specs' => [
    'my-filter' => [
        'root-key' => [
            'type' => CollectionInputFilter::class,
            'required' => true,
            'input_filter' => [
                'sub-key' => [
                    'required' => true,
                    'filters' => [ /** Add filters **/ ],
                    'validators' => [ /** Add validators **/],
                ],
                'sub-key2' => [
                    'required' => true,
                    'filters' => [ /** Add filters **/ ],
                    'validators' => [ /** Add validators **/],
                ],
            ]
        ],
        'simple-key' => [
            'required' => true,
            'filters' => [ /** Add filters **/ ],
            'validators' => [ /** Add validators **/],
        ],
    ],
],

Bypassing the type limitation / re-using filters specifications

Using the type key, the type of input filter can be specified (as done in the two examples before). What few do know however is that the specified filters implicitly are input filters as well and can be specified as the type too. This allows re-using specified filters within other filters and composing complex filters out of smaller ones. Simply pass the name of the specified input filter as the type.

$data = [
    'root-key' => [
        'sub-key' => 'my-value',
        'sub-key2' => 'my-other-value',
    ],
    'simple-key' => 'simple-value'
];

'input_filter_specs' => [
    'root-key-filter' => [
        'sub-key' => [
            'required' => true,
            'filters' => [ /** Add filters **/ ],
            'validators' => [ /** Add validators **/],
        ],
        'sub-key2' => [
            'required' => true,
            'filters' => [ /** Add filters **/ ],
            'validators' => [ /** Add validators **/],
        ],
    ],
    'my-filter' => [
        'root-key' => [
            'type' => 'root-key-filter',
        ],
        'simple-key' => [
            'required' => true,
            'filters' => [ /** Add filters **/ ],
            'validators' => [ /** Add validators **/],
        ],
    ],
],

Doing so then allows you to use the type name in the newly created input filter:

$data = [
    'root-key' => [
        'type' => 'my-value',
    ],
];

'input_filter_specs' => [
    'root-key-filter' => [
        'type' => [
            'required' => true,
            'filters' => [ /** Add filters **/ ],
            'validators' => [ /** Add validators **/],
        ],
    ],
    'my-filter' => [
        'root-key' => [
            'type' => 'root-key-filter',
        ],
    ],
],

I hope this late answer is still useful for anyone out there. Wilts answer sure was and brought me on the right track on this.

Fge
  • 2,971
  • 4
  • 23
  • 37
2

You can set nested data in your filter and validator configs the way as you would normally do in ZF2 for fieldsets.

return array(
    'awesome' => array(
        'name' => 'awesome',
        'required' => true,
        'filters' => array(
            //...
        ),
        'validators' => array(
            //...
        )
    ),
    'myObject' => array(
        'some_property' => array(
            'name' => 'some_property',
            'required' => true,
            'filters' => array(
                //...    
            ),
            'validators' => array(
                //...
            )
        ),
        'another_property' => array(
            'name' => 'another_property',
            'required' => true,
            'filters' => array(
                //...    
            ),
            'validators' => array(
                //...
            )
        ),
        // Type key necessary for nested fields
        'type' => 'Zend\InputFilter\InputFilter'
    )
);

Check for more information and on how to configure ZF content validation another question on StackOverfow here or the Content-Validation module documentation here.

Community
  • 1
  • 1
Wilt
  • 41,477
  • 12
  • 152
  • 203
  • This is the correct answer but it represents a flawed implementation because it prohibits having a nested field named `type`. – Quolonel Questions Apr 01 '16 at 12:38
  • @QuolonelQuestions I know, but this a zend implementation/architecture fault. I made an issue report **[here on GitHub](https://github.com/zendframework/zend-inputfilter/issues/81)**. Hope they will do something about it in ZF3. Maybe good to leave a comment there to encourage them to work on this. It is very annoying. – Wilt Apr 01 '16 at 12:55