1

我正在努力让我的自定义验证器工作。问题是我有一个使用自定义验证器的自定义表单元素。但是在创建字段时,ValidatorPluginManager 无法找到我的自定义验证器。现在我知道这是一个范围问题,但我无法解决它。

错误信息:

A plugin by the name "AliasExists" was not found in the plugin manager Zend\Validator\ValidatorPluginManager

验证码:

class AliasExists
    extends AbstractValidator
    implements AdapterAwareInterface
{
    use AdapterAwareTrait;

    const NOT_UNIQUE = 'notUnique';

    /**
     * Validation failure message templates definition
     *
     * @var array
     */
    protected $messageTemplates = [
        self::NOT_UNIQUE => "Entry with alias %value% already exists",
    ];

    /**
     * @var string
     */
    protected $table;

    /**
     * @var Select
     */
    protected $select;

    /**
     * @var string
     */
    protected $categoryField = 'category';

    /**
     * @var int
     */
    protected $categoryValue;

    public function __construct($options)
    {
        parent::__construct($options);

        if ($options instanceof Traversable) {
            $options = ArrayUtils::iteratorToArray($options);
        } elseif ($options instanceof Adapter) {
            $temp = [];
            $temp['adapter'] = $options;
            $options = $temp;
        } else {
            if (func_num_args() > 1) {
                $options = func_get_args();
                $firstArgument = array_shift($options);
                if (is_array($firstArgument)) {
                    $temp = ArrayUtils::iteratorToArray($firstArgument);
                } else {
                    $temp['table'] = $firstArgument;
                }

                if (!empty($options)) {
                    $temp['adapter'] = array_shift($options);
                }

                $options = $temp;
            }
        }

        if (array_key_exists('table', $options)) {
            $this->setTable($options['table']);
        }

        if (array_key_exists('adapter', $options)) {
            $this->setAdapter($options['adapter']);
        }
    }

    public function isValid($value, $context = null)
    {
        if (null === $this->adapter) {
            throw new \RuntimeException('No database adapter set.');
        }

        if (empty($this->table)) {
            throw new \RuntimeException('Table has not been set.');
        }

        $valid = true;
        $this->setValue($value);

        if ($context) {
            // TODO
        }

        $result = $this->query($value);
        if (!$result) {
            $valid = false;
            $this->error(self::NOT_UNIQUE);
        }

        return $valid;
    }

    public function getSelect()
    {
        if ($this->select instanceof Select) {
            return $this->select;
        }

        $select = new Select();
        $table = new TableIdentifier($this->table);
        $select->from($table);
        $select->where->equalTo(
            'alias',
            null
        );
        if (!empty($this->categoryField) && !empty($this->categoryValue)) {
            $select->where->equalTo(
                $this->categoryField,
                $this->categoryValue
            );
        }
        $select->columns(['id']);

        $this->select = $select;

        return $this->select;
    }

    /**
     * Returns the set adapter
     *
     * @return Adapter
     */
    public function getAdapter(): Adapter
    {
        return $this->adapter;
    }

    /**
     * Sets a (new) DB adapter
     *
     * @param Adapter $adapter
     * @return self Provides a fluent interface
     */
    public function setAdapter(Adapter $adapter)
    {
        return $this->setDbAdapter($adapter);
    }

    /**
     * Returns the set table
     *
     * @return string
     */
    public function getTable(): string
    {
        return $this->table;
    }

    /**
     * Sets a (new) table
     *
     * @param string $table
     * @return self Provides a fluent interface
     */
    public function setTable(string $table)
    {
        $this->table = $table;
        $this->select = null;
        return $this;
    }

    /**
     * @return string
     */
    public function getCategoryField(): string
    {
        return $this->categoryField;
    }

    /**
     * @param string $categoryField
     */
    public function setCategoryField(string $categoryField)
    {
        $this->categoryField = $categoryField;
    }

    /**
     * @return int
     */
    public function getCategoryValue(): int
    {
        return $this->categoryValue;
    }

    /**
     * @param int $categoryValue
     */
    public function setCategoryValue(int $categoryValue)
    {
        $this->categoryValue = $categoryValue;
    }

    protected function query($value)
    {
        $sql = new Sql($this->getAdapter());
        $select = $this->getSelect();
        $statement = $sql->prepareStatementForSqlObject($select);
        $parameters = $statement->getParameterContainer();
        $parameters['where1'] = (string)$value;
        $result = $statement->execute();

        return $result->current();
    }
}

验证器工厂:

class AliasExistsFactory implements FactoryInterface
{
    public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
    {
        $db = $container->get(AdapterInterface::class);

        return new AliasExists($db);
    }
}

自定义表单元素代码:

class Alias
    extends Text
    implements InputProviderInterface
{
    protected $attributes = [
        'name' => 'alias',
        'required' => 'required',
        'class' => 'form-control',
    ];

    protected $label = 'Alias';

    public function __construct($name = null, array $options = [])
    {
        parent::__construct($name, $options);

        $this->setAttribute('id', $this->getName());
    }

    public function getInputSpecification()
    {
        return [
            'name' => $this->getName(),
            'required' => true,
            'filters' => [
                ['name' => 'StringTrim'],
                ['name' => 'StringToLower'],
            ],
            'validators' => [
                [
                    'name' => 'NotEmpty',
                    'options' => [
                        'type' => 'string'
                    ],
                ],
                [
                    'name' => 'Regex',
                    'options' => [
                        'pattern' => '/^[0-9a-zA-Z-_]+$/',
                        'messages' => [
                            Regex::NOT_MATCH => 'Only numbers, underscore, dash and characters from A to Z are allowed'
                        ],
                    ],
                ],
                [
                    'name' => 'StringLength',
                    'options' => [
                        'min' => 1,
                        'max' => 255
                    ],
                ],
                [
                    'name' => 'AliasExists', <--- Custom validator
                ]
            ],
        ];
    }
}

模块.config.php

'form_elements' => [
    'factories' => [
        Form\Element\Alias::class => InvokableFactory::class,
    ],
],
'validators' => [
    'factories' => [
        Validator\AliasExists::class => Factory\AliasExistsFactory::class,
    ],
    'aliases' => [
        'AliasExists' => Validator\AliasExists::class,
    ]
]

实例化具有此自定义字段的表单的控制器工厂:

class EditControllerFactory implements FactoryInterface
{
    public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
    {

        $formManager = $container->get('FormElementManager');
        $form = $formManager->get(ArticleForm::class);

        return new EditController($form);
    }
}

我可以让我的自定义验证器工作的唯一方法是(如在this answer中找到的可能创建工厂来实例化自定义表单验证器?)是在控制器工厂中设置验证器链来实例化表单,但这样做有点过头了在每个可能具有使用该字段的表单的控制器工厂中,其中包含自定义验证器。

4

0 回答 0