我正在努力让自定义验证器工作。 问题是我有一个使用自定义验证器的自定义表单元素。 但是当创建字段时,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
]
],
];
}
}
module.config.php
'form_elements' => [
'factories' => [
Form\Element\Alias::class => InvokableFactory::class,
],
],
'validators' => [
'factories' => [
Validator\AliasExists::class => Factory\AliasExistsFactory::class,
],
'aliases' => [
'AliasExists' => Validator\AliasExists::class,
]
]
实例化具有此自定义字段的表单的Controller工厂:
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);
}
}
我可以让我的自定义验证器工作的唯一方法是(在本回答Possible to create a factory to instantiate custom Form validators?中找到)是在控制器工厂中设置实例化表单的验证器链但是在每个控制器中都必须执行此操作工厂可能有一个使用此字段的表单,其中包含自定义验证程序。