Issue #3431203 by kim.pepper, alexpott, smustgrave, longwave: Deprecate user_validate_name() and replace with service
parent
644d8f2abd
commit
8e7d3e0f52
|
@ -8,8 +8,9 @@ use Drupal\Core\Form\ConfigFormBase;
|
|||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Locale\CountryManagerInterface;
|
||||
use Drupal\Core\Site\Settings;
|
||||
use Drupal\user\UserStorageInterface;
|
||||
use Drupal\user\UserInterface;
|
||||
use Drupal\user\UserStorageInterface;
|
||||
use Drupal\user\UserNameValidator;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
|
@ -67,13 +68,26 @@ class SiteConfigureForm extends ConfigFormBase {
|
|||
* The module installer.
|
||||
* @param \Drupal\Core\Locale\CountryManagerInterface $country_manager
|
||||
* The country manager.
|
||||
* @param \Drupal\user\UserNameValidator|null $userNameValidator
|
||||
* The user validator.
|
||||
*/
|
||||
public function __construct($root, $site_path, UserStorageInterface $user_storage, ModuleInstallerInterface $module_installer, CountryManagerInterface $country_manager) {
|
||||
public function __construct(
|
||||
$root,
|
||||
$site_path,
|
||||
UserStorageInterface $user_storage,
|
||||
ModuleInstallerInterface $module_installer,
|
||||
CountryManagerInterface $country_manager,
|
||||
protected ?UserNameValidator $userNameValidator = NULL,
|
||||
) {
|
||||
$this->root = $root;
|
||||
$this->sitePath = $site_path;
|
||||
$this->userStorage = $user_storage;
|
||||
$this->moduleInstaller = $module_installer;
|
||||
$this->countryManager = $country_manager;
|
||||
if (!$userNameValidator) {
|
||||
@\trigger_error('Calling ' . __METHOD__ . ' without the $userNameValidator argument is deprecated in drupal:10.3.0 and will be required in drupal:11.0.0. See https://www.drupal.org/node/3431205', E_USER_DEPRECATED);
|
||||
$this->userNameValidator = \Drupal::service('user.name_validator');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -85,7 +99,8 @@ class SiteConfigureForm extends ConfigFormBase {
|
|||
$container->getParameter('site.path'),
|
||||
$container->get('entity_type.manager')->getStorage('user'),
|
||||
$container->get('module_installer'),
|
||||
$container->get('country_manager')
|
||||
$container->get('country_manager'),
|
||||
$container->get('user.name_validator'),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -253,8 +268,9 @@ class SiteConfigureForm extends ConfigFormBase {
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
public function validateForm(array &$form, FormStateInterface $form_state) {
|
||||
if ($error = user_validate_name($form_state->getValue(['account', 'name']))) {
|
||||
$form_state->setErrorByName('account][name', $error);
|
||||
$violations = $this->userNameValidator->validateName($form_state->getValue(['account', 'name']));
|
||||
if ($violations->count() > 0) {
|
||||
$form_state->setErrorByName('account][name', $violations[0]->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ namespace Drupal\user\Form;
|
|||
|
||||
use Drupal\Component\Utility\EmailValidatorInterface;
|
||||
use Drupal\Core\Config\ConfigFactory;
|
||||
use Drupal\Core\Field\BaseFieldDefinition;
|
||||
use Drupal\Core\DependencyInjection\DeprecatedServicePropertyTrait;
|
||||
use Drupal\Core\Flood\FloodInterface;
|
||||
use Drupal\Core\Form\FormBase;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
|
@ -13,6 +13,7 @@ use Drupal\Core\Render\Element\Email;
|
|||
use Drupal\Core\TypedData\TypedDataManagerInterface;
|
||||
use Drupal\user\UserInterface;
|
||||
use Drupal\user\UserStorageInterface;
|
||||
use Drupal\user\UserNameValidator;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
|
@ -24,6 +25,15 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
|
|||
*/
|
||||
class UserPasswordForm extends FormBase {
|
||||
|
||||
use DeprecatedServicePropertyTrait;
|
||||
|
||||
/**
|
||||
* The deprecated properties.
|
||||
*/
|
||||
protected array $deprecatedProperties = [
|
||||
'typedDataManager' => 'typed_data_manager',
|
||||
];
|
||||
|
||||
/**
|
||||
* The user storage.
|
||||
*
|
||||
|
@ -45,13 +55,6 @@ class UserPasswordForm extends FormBase {
|
|||
*/
|
||||
protected $flood;
|
||||
|
||||
/**
|
||||
* The typed data manager.
|
||||
*
|
||||
* @var \Drupal\Core\TypedData\TypedDataManagerInterface
|
||||
*/
|
||||
protected $typedDataManager;
|
||||
|
||||
/**
|
||||
* The email validator service.
|
||||
*
|
||||
|
@ -70,18 +73,28 @@ class UserPasswordForm extends FormBase {
|
|||
* The config factory.
|
||||
* @param \Drupal\Core\Flood\FloodInterface $flood
|
||||
* The flood service.
|
||||
* @param \Drupal\Core\TypedData\TypedDataManagerInterface $typed_data_manager
|
||||
* The typed data manager.
|
||||
* @param \Drupal\user\UserNameValidator|\Drupal\Core\TypedData\TypedDataManagerInterface $userNameValidator
|
||||
* The user validator service.
|
||||
* @param \Drupal\Component\Utility\EmailValidatorInterface $email_validator
|
||||
* The email validator service.
|
||||
*/
|
||||
public function __construct(UserStorageInterface $user_storage, LanguageManagerInterface $language_manager, ConfigFactory $config_factory, FloodInterface $flood, TypedDataManagerInterface $typed_data_manager, EmailValidatorInterface $email_validator) {
|
||||
public function __construct(
|
||||
UserStorageInterface $user_storage,
|
||||
LanguageManagerInterface $language_manager,
|
||||
ConfigFactory $config_factory,
|
||||
FloodInterface $flood,
|
||||
protected UserNameValidator|TypedDataManagerInterface $userNameValidator,
|
||||
EmailValidatorInterface $email_validator,
|
||||
) {
|
||||
$this->userStorage = $user_storage;
|
||||
$this->languageManager = $language_manager;
|
||||
$this->configFactory = $config_factory;
|
||||
$this->flood = $flood;
|
||||
$this->typedDataManager = $typed_data_manager;
|
||||
$this->emailValidator = $email_validator;
|
||||
if (!$userNameValidator instanceof UserNameValidator) {
|
||||
@\trigger_error('Passing $userNameValidator as \Drupal\Core\TypedData\TypedDataManagerInterface to ' . __METHOD__ . ' () is deprecated in drupal:10.3.0 and is removed in drupal:10.0.0. Pass a Drupal\user\UserValidator instead. See https://www.drupal.org/node/3431205', E_USER_DEPRECATED);
|
||||
$this->userNameValidator = \Drupal::service('user.name_validator');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -93,8 +106,8 @@ class UserPasswordForm extends FormBase {
|
|||
$container->get('language_manager'),
|
||||
$container->get('config.factory'),
|
||||
$container->get('flood'),
|
||||
$container->get('typed_data_manager'),
|
||||
$container->get('email.validator')
|
||||
$container->get('user.name_validator'),
|
||||
$container->get('email.validator'),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -161,11 +174,7 @@ class UserPasswordForm extends FormBase {
|
|||
$this->flood->register('user.password_request_ip', $flood_config->get('ip_window'));
|
||||
// First, see if the input is possibly valid as a username.
|
||||
$name = trim($form_state->getValue('name'));
|
||||
$definition = BaseFieldDefinition::create('string')
|
||||
->addConstraint('UserName', []);
|
||||
$data = $this->typedDataManager->create($definition);
|
||||
$data->setValue($name);
|
||||
$violations = $data->validate();
|
||||
$violations = $this->userNameValidator->validateName($name);
|
||||
// Usernames have a maximum length shorter than email addresses. Only print
|
||||
// this error if the input is not valid as a username or email address.
|
||||
if ($violations->count() > 0 && !$this->emailValidator->isValid($name)) {
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace Drupal\user\Plugin\Validation\Constraint;
|
||||
|
||||
use Drupal\Core\Field\FieldItemListInterface;
|
||||
use Drupal\user\UserInterface;
|
||||
use Symfony\Component\Validator\Constraint;
|
||||
use Symfony\Component\Validator\ConstraintValidator;
|
||||
|
@ -15,11 +16,11 @@ class UserNameConstraintValidator extends ConstraintValidator {
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
public function validate($items, Constraint $constraint): void {
|
||||
if (!isset($items) || !$items->value) {
|
||||
if (empty($items) || ($items instanceof FieldItemListInterface && $items->isEmpty())) {
|
||||
$this->context->addViolation($constraint->emptyMessage);
|
||||
return;
|
||||
}
|
||||
$name = $items->first()->value;
|
||||
$name = $items instanceof FieldItemListInterface ? $items->first()->value : $items;
|
||||
if (str_starts_with($name, ' ')) {
|
||||
$this->context->addViolation($constraint->spaceBeginMessage);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\user;
|
||||
|
||||
use Drupal\Core\Validation\BasicRecursiveValidatorFactory;
|
||||
use Drupal\Core\Validation\ConstraintManager;
|
||||
use Symfony\Component\Validator\ConstraintViolationListInterface;
|
||||
|
||||
/**
|
||||
* Provides a username validator.
|
||||
*
|
||||
* This validator re-uses the UserName constraint plugin but does not require a
|
||||
* User entity.
|
||||
*/
|
||||
class UserNameValidator {
|
||||
|
||||
public function __construct(
|
||||
protected readonly BasicRecursiveValidatorFactory $validatorFactory,
|
||||
protected readonly ConstraintManager $constraintManager,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Validates a user name.
|
||||
*
|
||||
* @return \Symfony\Component\Validator\ConstraintViolationListInterface
|
||||
* The list of constraint violations.
|
||||
*/
|
||||
public function validateName(string $name): ConstraintViolationListInterface {
|
||||
$validator = $this->validatorFactory->createValidator();
|
||||
$constraint = $this->constraintManager->create('UserName', []);
|
||||
return $validator->validate($name, $constraint);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\user\Kernel;
|
||||
|
||||
use Drupal\KernelTests\KernelTestBase;
|
||||
use Drupal\user\UserInterface;
|
||||
use Drupal\user\UserNameValidator;
|
||||
|
||||
/**
|
||||
* Verify that user validity checks behave as designed.
|
||||
*
|
||||
* @group user
|
||||
*/
|
||||
class UserNameValidatorTest extends KernelTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['user'];
|
||||
|
||||
/**
|
||||
* The user validator under test.
|
||||
*/
|
||||
protected UserNameValidator $userValidator;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
$this->userValidator = $this->container->get('user.name_validator');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests valid user name validation.
|
||||
*
|
||||
* @dataProvider validUsernameProvider
|
||||
*/
|
||||
public function testValidUsernames($name): void {
|
||||
$violations = $this->userValidator->validateName($name);
|
||||
$this->assertEmpty($violations);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests invalid user name validation.
|
||||
*
|
||||
* @dataProvider invalidUserNameProvider
|
||||
*/
|
||||
public function testInvalidUsernames($name, $expectedMessage): void {
|
||||
$violations = $this->userValidator->validateName($name);
|
||||
$this->assertNotEmpty($violations);
|
||||
$this->assertEquals($expectedMessage, $violations[0]->getMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides valid user names.
|
||||
*/
|
||||
public static function validUsernameProvider(): array {
|
||||
// cSpell:disable
|
||||
return [
|
||||
'lowercase' => ['foo'],
|
||||
'uppercase' => ['FOO'],
|
||||
'contains space' => ['Foo O\'Bar'],
|
||||
'contains @' => ['foo@bar'],
|
||||
'allow email' => ['foo@example.com'],
|
||||
'allow invalid domain' => ['foo@-example.com'],
|
||||
'allow special chars' => ['þòøÇߪř€'],
|
||||
'allow plus' => ['foo+bar'],
|
||||
'utf8 runes' => ['ᚠᛇᚻ᛫ᛒᛦᚦ'],
|
||||
];
|
||||
// cSpell:enable
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides invalid user names.
|
||||
*/
|
||||
public static function invalidUserNameProvider(): array {
|
||||
return [
|
||||
'starts with space' => [' foo', 'The username cannot begin with a space.'],
|
||||
'ends with space' => ['foo ', 'The username cannot end with a space.'],
|
||||
'contains 2 spaces' => ['foo bar', 'The username cannot contain multiple spaces in a row.'],
|
||||
'empty string' => ['', 'You must enter a username.'],
|
||||
'invalid chars' => ['foo/', 'The username contains an illegal character.'],
|
||||
// NULL.
|
||||
'contains chr(0)' => ['foo' . chr(0) . 'bar', 'The username contains an illegal character.'],
|
||||
// CR.
|
||||
'contains chr(13)' => ['foo' . chr(13) . 'bar', 'The username contains an illegal character.'],
|
||||
'excessively long' => [str_repeat('x', UserInterface::USERNAME_MAX_LENGTH + 1),
|
||||
'The username xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx is too long: it must be 60 characters or less.',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
}
|
|
@ -38,6 +38,8 @@ class UserValidationTest extends KernelTestBase {
|
|||
|
||||
/**
|
||||
* Tests user name validation.
|
||||
*
|
||||
* @group legacy
|
||||
*/
|
||||
public function testUsernames() {
|
||||
// cSpell:disable
|
||||
|
@ -66,6 +68,7 @@ class UserValidationTest extends KernelTestBase {
|
|||
'foo' . chr(13) . 'bar' => ['Invalid username containing chr(13)', 'assertNotNull'],
|
||||
str_repeat('x', UserInterface::USERNAME_MAX_LENGTH + 1) => ['Invalid excessively long username', 'assertNotNull'],
|
||||
];
|
||||
$this->expectDeprecation('user_validate_name() is deprecated in drupal:10.3.0 and is removed from drupal:12.0.0. Use \Drupal\user\UserValidator::validateName() instead. See https://www.drupal.org/node/3431205');
|
||||
// cSpell:enable
|
||||
foreach ($test_cases as $name => $test_case) {
|
||||
[$description, $test] = $test_case;
|
||||
|
|
|
@ -14,7 +14,6 @@ use Drupal\Core\Asset\AttachedAssetsInterface;
|
|||
use Drupal\Core\Batch\BatchBuilder;
|
||||
use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\Core\Field\BaseFieldDefinition;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Render\Element;
|
||||
use Drupal\Core\Routing\RouteMatchInterface;
|
||||
|
@ -206,13 +205,15 @@ function user_load_by_name($name) {
|
|||
* @return string|null
|
||||
* A translated violation message if the name is invalid or NULL if the name
|
||||
* is valid.
|
||||
*
|
||||
* @deprecated in drupal:10.3.0 and is removed from drupal:12.0.0. Use
|
||||
* \Drupal\user\UserValidator::validateName() instead.
|
||||
*
|
||||
* @see https://www.drupal.org/node/3431205
|
||||
*/
|
||||
function user_validate_name($name) {
|
||||
$definition = BaseFieldDefinition::create('string')
|
||||
->addConstraint('UserName', []);
|
||||
$data = \Drupal::typedDataManager()->create($definition);
|
||||
$data->setValue($name);
|
||||
$violations = $data->validate();
|
||||
@trigger_error(__METHOD__ . '() is deprecated in drupal:10.3.0 and is removed from drupal:12.0.0. Use \Drupal\user\UserValidator::validateName() instead. See https://www.drupal.org/node/3431205', E_USER_DEPRECATED);
|
||||
$violations = \Drupal::service('user.name_validator')->validateName($name);
|
||||
if (count($violations) > 0) {
|
||||
return $violations[0]->getMessage();
|
||||
}
|
||||
|
|
|
@ -73,3 +73,7 @@ services:
|
|||
user.module_permissions_link_helper:
|
||||
class: Drupal\user\ModulePermissionsLinkHelper
|
||||
arguments: ['@user.permissions', '@access_manager', '@extension.list.module']
|
||||
user.name_validator:
|
||||
class: Drupal\user\UserNameValidator
|
||||
arguments: ['@validation.basic_recursive_validator_factory', '@validation.constraint']
|
||||
Drupal\user\UserNameValidator: '@user.name_validator'
|
||||
|
|
Loading…
Reference in New Issue