Skip to content
This repository has been archived by the owner on Jan 21, 2020. It is now read-only.

ZF\ContentValidation\Validator\Db\[No]RecordExists exclude current entity by default? #181

Open
intellent opened this issue Nov 11, 2016 · 3 comments

Comments

@intellent
Copy link

I’m in running into a rather tricky situation, using NoRecordExists validtor within Apigility.

It’s quite easy to setup and force a field value to be unique like this:

'validators' => array(
    0 => array(
        'name' => 'ZF\\ContentValidation\\Validator\\Db\\NoRecordExists',
        'options' => array(
            'adapter' => 'Zend\\Db\\Adapter\\Adapter',
            'table' => 'mytable',
            'field' => 'myuniquefield',
        ),
    ),
)

However, this does not really work in real-life, since only POST requests deliver the expected results. Once you want to modify a records using PUT, this fails, because … well … the record exists already. In case of PUT/PATCH, I need to set up the validator to exclude the entity that’s being updated, like this:

'validators' => array(
    0 => array(
        'name' => 'ZF\\ContentValidation\\Validator\\Db\\NoRecordExists',
        'options' => array(
            'adapter' => 'Zend\\Db\\Adapter\\Adapter',
            'table' => 'mytable',
            'field' => 'myuniquefield',
            'exclude' => array(
                'field' => 'id',
                'value' => CURRENT_ENTITY_ID,
            ),
        ),
    ),
)

But I don’t know how to inject the requested entity’s ID into the options array. Wouldn’t it make sense, to have Apigility set these excludes for PUT/PATCH requests automatically?

@Wilt
Copy link

Wilt commented Nov 23, 2016

This CURRENT_ENTITY_ID is inside the route parameters of your RouteMatch. A route identifier does not belong inside the validator/input filter logic. You can make your own validator class where you inject the RouteMatch instance or you can move validation to your ResourceListener class and do the validation after your resolved your object from the database in your patch or update method.

@intellent
Copy link
Author

intellent commented Dec 22, 2016

I’ve solved it with the event listener for the time being. But this seems very cumbersome to me.

Here’s a simple example that expects you to have a route like /entities/:id and modifies the NoRecordExists validator of a unique field named 'alias'.

Put this in your Module.php:

public function onBootstrap(MvcEvent $e)
{
    $serviceManager = $e->getApplication()->getServiceManager();

    $events = $serviceManager->get('ZF\ContentValidation\ContentValidationListener')->getEventManager();

    $events->attach('contentvalidation.beforevalidate', function(MvcEvent $e)
    {
        $inputFilter = $e->getParam('ZF\ContentValidation\InputFilter');

        $alias = $inputFilter->get('alias');
        $validatorChain = $alias->getValidatorChain();

        foreach ($validatorChain->getValidators() as $validator) {
            if (! $validator['instance'] instanceof NoRecordExists) {
                continue;
            }

            $validator['instance']->setExclude(array(
                'field' => 'id',
                'value' => intval($e->getRouteMatch()->getParam('id')),
            ));
            break;
        }
    });
}

@weierophinney
Copy link
Member

This repository has been closed and moved to laminas-api-tools/api-tools; a new issue has been opened at laminas-api-tools/api-tools#12.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants