Possible to create a factory to instantiate custom Form validators?

丶灬走出姿态 提交于 2019-12-13 00:44:15

问题


(using Zend Framework 2.2.4)

My validator factory, doesn't seem to "exist" at validation time. If I attempt to instantiate the validator from the controller in which the form is housed, it conversely works fine:

This works...

$mycustomvalidator = $this->getServiceLocator()
    ->get('ValidatorManager')
    ->get('LDP_PinAvailable');

Here's how things are set up otherwise in the code, I can't seem to find the problem, and was hopeful to avoid opening up ZF2 source to understand. By way of documentation, it seems right.

Module Config

public function getValidatorConfig()
{
    return array(
       'abstract_factories' => array(
           '\LDP\Form\Validator\ValidatorAbstractFactory',
       ),
    );
}

Factory Class

namespace LDP\Form\Validator;

use Zend\ServiceManager\AbstractFactoryInterface,
    Zend\ServiceManager\ServiceLocatorInterface;

class ValidatorAbstractFactory implements AbstractFactoryInterface
{
    public function canCreateServiceWithName(ServiceLocatorInterface $serviceLocator, $name, $requestedName)
    {
        return stristr($requestedName, 'LDP_PinAvailable') !== false;
    }


    public function createServiceWithName(ServiceLocatorInterface $locator, $name, $requestedName)
    {
        // baked in for sake of conversation
        $validator = new \LDP\Form\Validator\PinAvailable();

        if( $validator instanceof DatabaseFormValidatorInterface )
            $validator->setDatabase( $locator->get('mysql_slave') );

        return $validator;
    }
}

Custom Validator

namespace LDP\Form\Validator;

class PinAvailable extends \Zend\Validator\AbstractValidator implements DatabaseFormValidatorInterface
{

    /**
     * @var \Zend\Db\Sql\Sql
     */
    private $database;

    public function setDatabase( \Zend\Db\Sql\Sql $db )
    {
        $this->database = $db;
    }


    public function isValid( $value )
    {
        $DBA = $this->database->getAdapter();
        // do the mixed database stuff here
        return true;
    }
}

Lastly, the form field validator config part of the array:

'pin' => array(
    'required' => true,
        'filters'  => array(
            array('name' => 'alnum'),
            array('name' => 'stringtrim'),
        ),
        'validators' => array(
            array( 'name' => 'LDP_PinAvailable' )
        ),
    ),
),

Piecing it all together, the form loads, and when submitted, it does with the stack trace below:

2013-10-28T17:09:35-04:00 ERR (3): Exception:
1: Zend\Validator\ValidatorPluginManager::get was unable to fetch or create an instance for LDP_PinAvailable
Trace:
#0 /Users/Saeven/Documents/workspace/Application/vendor/zendframework/zendframework/library/Zend/ServiceManager/AbstractPluginManager.php(103): Zend\ServiceManager\ServiceManager->get('LDP_PinAvailabl...', true)
#1 /Users/Saeven/Documents/workspace/Application/vendor/zendframework/zendframework/library/Zend/Validator/ValidatorChain.php(82): Zend\ServiceManager\AbstractPluginManager->get('LDP_PinAvailabl...', Array)

回答1:


The ValidatorPluginManager extends the Zend\ServiceManager\AbstractPluginManager. The AbstractPluginManager has a feature called "autoAddInvokableClass", which is enabled by default.

Basically, what this means, is that if the service name requested can't be resolved by the ValidatorPluginManager, it will then check if the name is a valid class name. If so, it will simply add it as an invokable class right there, on-demand, which of course means that it will never fall back to your abstract factory.

To circumvent this behavior, the easiest method is to simply make your abstract factory respond to service names that do not actually resolve to the actual class names.

See: AbstractPluginManager.php#L98-L100




回答2:


Digging some more, I've found the problem. It distilled to these lines in Zend\Validator\ValidatorChain circa line 80:

public function plugin($name, array $options = null)
{
    $plugins = $this->getPluginManager();
    return $plugins->get($name, $options);
} 

There was no plugin manager available in context.

It took about three seconds of Googling to find that I had to do this when I prepared the form in the controller:

 $validators = $this->getServiceLocator()->get('ValidatorManager');
 $chain      = new ValidatorChain();
 $chain->setPluginManager( $validators );
 $form->getFormFactory()->getInputFilterFactory()->setDefaultValidatorChain( $chain );

Hopefully this helps someone else. You are able to use regular old classnames when setting it up this way, no need to warp the classnames.



来源:https://stackoverflow.com/questions/19642139/possible-to-create-a-factory-to-instantiate-custom-form-validators

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!