Symfony 4 Regex,找到一个从url检查中排除电子邮件检查的模式



我有一个Symfony表单,它有一些字段应该允许用户写电子邮件,但不允许用户写URL。我目前正在使用这个正则表达式:

return new Regex(
[
'pattern' => '((http|https|ftp|ftps)://)?([a-zA-Z0-9-]*.)+[a-zA-Z0-9]{2,4}(/[a-zA-Z0-9=.?&-]*)?',
'match'   => false,
'message' => $this->translator->trans('form.field.urlNotAllowed', ['%label%' => $label])
]
);

此正则表达式匹配所有URL,但也匹配用于验证的电子邮件。我想做的是将电子邮件排除在验证之外,只匹配URL。

我的代码:

/**
* @param RegistrationFormField $field
* @param string $key
* @param array $validationAttributes
* @return Regex
*/
public function getUrlNotAllowedConstraint($field, $key, &$validationAttributes)
{
$event = $field->getRegistrationForm()->getEvent();
$label = /** @Ignore */
$this->translator->trans($field->getLabel(), [], 'custom') ?: $this->getDefaultLabelName($event, $key);

$validationAttributes['data-validation'][] = 'url_not_allowed';
return new Regex(
[
'pattern' => '((http|https|ftp|ftps)://)?([a-zA-Z0-9-]*.)+[a-zA-Z0-9]{2,4}(/[a-zA-Z0-9=.?&-]*)?',
'match'   => false,
'message' => $this->translator->trans('form.field.urlNotAllowed', ['%label%' => $label])
]
);
}

有什么帮助吗?

我已经创建了自定义顺序约束:

namespace AppFormValidator;
use SymfonyComponentValidatorConstraintsComposite as 
ConstraintsComposite;
/**
* Use this constraint to sequentially validate nested 
constraints.
* Validation for the nested constraints collection will stop at 
first violation.
*
* @Annotation
* @Target({"CLASS", "PROPERTY", "METHOD", "ANNOTATION"})
*
*/
class CustomSequentially extends ConstraintsComposite
{
public $constraints = [];
public function getDefaultOption()
{
return 'constraints';
}
public function getRequiredOptions()
{
return ['constraints'];
}
protected function getCompositeOption()
{
return 'constraints';
}
public function getTargets()
{
return [self::CLASS_CONSTRAINT, self::PROPERTY_CONSTRAINT];
}
}

和CustomSequentialyValidator类:

namespace AppFormValidator;
use SymfonyComponentValidatorConstraint;
use SymfonyComponentValidatorConstraintValidator;
use SymfonyComponentValidatorExceptionUnexpectedTypeException;
class CustomSequentiallyValidator extends ConstraintValidator
{
/**
* {@inheritdoc}
*/
public function validate($value, Constraint $constraint)
{
if (!$constraint instanceof CustomSequentially) {
throw new UnexpectedTypeException($constraint, CustomSequentially::class);
}
$context = $this->context;
$validator = $context->getValidator()->inContext($context);
$originalCount = $validator->getViolations()->count();
foreach ($constraint->constraints as $c) {
if ($originalCount !== $validator->validate($value, $c)->getViolations()->count()) {
break;
}
}
}
}

并使用了这样的约束:

$constraints = new CustomSequentially([
'constraints' => [
new Regex([
'pattern' => '/((http|https|ftp|ftps)://)?((?!@)[a-zA-Z0-9-]*.)+[a-zA-Z0-9]{2,4}(/[a-zA-Z0-9=.?&-]*)?/',
'match'   => false,
'message' => $this->translator->trans('form.field.urlNotAllowed', ['%label%' => $label])
]),
new Regex([
'pattern' => '/[@]/',
'match'   => true,
'message' => 'It is an email'
]),
],
]);
return $constraints;

现在,如果我写了一个URL或一封电子邮件,它们都没有通过验证(一个简单的文本正在通过(。

这将允许任何字符串,但如果它是URL,它将使用regex进行检查。如果它检测到一个URL,它将通过检查该URL是否包含@符号并允许它来查看它是否是一个电子邮件地址

根据您的需要进行改进或迭代。

限制

namespace AppValidator;
use SymfonyComponentValidatorConstraint;
class NoUrl extends Constraint
{
public $urlMessage = 'This looks like a URL, this is not valid.';
}

验证器

namespace AppValidator;
use SymfonyComponentValidatorConstraint;
use SymfonyComponentValidatorConstraintValidator;
use SymfonyComponentValidatorExceptionUnexpectedTypeException;
use SymfonyComponentValidatorExceptionUnexpectedValueException;
class NoUrlValidator extends ConstraintValidator
{
public function validate($url, Constraint $constraint)
{
if (!$constraint instanceof NoUrl) {
throw new UnexpectedTypeException($constraint, NoUrl::class);
}
if (null === $url || '' === $url) {
return;
}
if (!is_string($url)) {
throw new UnexpectedValueException($url, 'string');
}
if (preg_match('/((http|https|ftp|ftps)://)?([a-zA-Z0-9-]*.)+[a-zA-Z0-9]{2,4}(/[a-zA-Z0-9=.?&-]*)?/', trim($url))) {
// str_contains() is PHP 8+, use strpos() for PHP <8
// String contains an @ symbol so just return as it must be an email address. You can add more checks if needed yourself.
if (str_contains($url, '@')) {
return;
}
$this->context->buildViolation($constraint->urlMessage)->addViolation();
}
}
}

在您的表单中

...
use AppValidatorNoUrl;
class YourFormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('yourfield', TextType::class, array(
'constraints' => array(
new NoUrl()
)
))
...

最新更新