#php #symfony #fosuserbundle
#php #symfony #fosuserbundle
Вопрос:
Я пытаюсь переопределить команду создания пользователя FOSUser bundle.
Я следовал этому руководству: https://blog.overnetcity.com/2012/10/15/symfony2-fosuserbundle-comment-etendre-la-commande-par-defaut-de-creation-dun-utilisateur/
Но когда я запускаю свою новую команду, я получаю эту ошибку:
Не удается выполнить автоматическое подключение службы «Site PagesBundleCommandCreateUserCommand»: аргумент «$userManipulator» метода «FOS UserBundleCommandCreateUserCommand::__construct()» ссылается на класс «FOS UserBundleUtil UserManipulator» но такой службы не существует. Возможно, вам следует присвоить этот класс существующему сервису «fos_user.util.user_manipulator».
Кажется, что ни у кого не было этой проблемы до меня. Тем не менее, я уважал руководство, импорт, все, что было необходимо.
Я показываю вам свой код:
<?php
namespace SitePagesBundleCommand;
use SymfonyComponentConsoleInputInputArgument;
use SymfonyComponentConsoleInputInputOption;
use SymfonyComponentConsoleInputInputInterface;
use SymfonyComponentConsoleOutputOutputInterface;
use FOSUserBundleModelUser;
use FOSUserBundleCommandCreateUserCommand as BaseCommand;
class CreateUserCommand extends BaseCommand
{
/**
* @see Command
*/
protected function configure()
{
parent::configure();
$this
->setName('atelech:user:create')
->getDefinition()->addArguments(array(
new InputArgument('nom', InputArgument::REQUIRED, 'Le nom'),
new InputArgument('prenom', InputArgument::REQUIRED, 'Le prenom')
))
;
$this->setHelp(<<<EOT
// L'aide qui va bien
EOT
);
}
/**
* @see Command
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$username = $input->getArgument('username');
$email = $input->getArgument('email');
$password = $input->getArgument('password');
$nom = $input->getArgument('nom');
$prenom = $input->getArgument('prenom');
$inactive = $input->getOption('inactive');
$superadmin = $input->getOption('super-admin');
/** @var FOSUserBundleModelUserManager $user_manager */
$user_manager = $this->getContainer()->get('fos_user.user_manager');
/** @var AcmeAcmeUserBundleEntityUser $user */
$user = $user_manager->createUser();
$user->setUsername($username);
$user->setEmail($email);
$user->setPlainPassword($password);
$user->setEnabled((Boolean) !$inactive);
$user->setSuperAdmin((Boolean) $superadmin);
$user->setNom($nom);
$user->setPrenom($prenom);
$user_manager->updateUser($user);
$output->writeln(sprintf('Created user <comment>%s</comment>', $username));
}
/**
* @see Command
*/
protected function interact(InputInterface $input, OutputInterface $output)
{
parent::interact($input, $output);
if (!$input->getArgument('nom')) {
$nom = $this->getHelper('dialog')->askAndValidate(
$output,
'Please choose a nom:',
function($nom) {
if (empty($nom)) {
throw new Exception('nom can not be empty');
}
return $nom;
}
);
$input->setArgument('nom', $nom);
}
if (!$input->getArgument('prenom')) {
$prenom = $this->getHelper('dialog')->askAndValidate(
$output,
'Please choose a prenom:',
function($prenom) {
if (empty($prenom)) {
throw new Exception('prenom can not be empty');
}
return $prenom;
}
);
$input->setArgument('prenom', $prenom);
}
}
}
Я хотел добавить два атрибута «name» и «first name»
Спасибо за вашу помощь!
Комментарии:
1. Я никогда не использовал FOSUserBundle, но руководство действительно старое и связано с версией symfony2, а не с 3.4 (большие изменения между этими версиями).
2. Да, я знаю, но это было просто для мелочи ^^
Ответ №1:
итак..
проверено на Symfony 3.4.24 и friendsofsymfony / user-bundle (2.0)
и следующий код соответствует источникам fosuserbundle:
<?php
namespace AppBundleCommand;
use SymfonyComponentConsoleInputInputArgument;
use SymfonyComponentConsoleInputInputInterface;
use SymfonyComponentConsoleOutputOutputInterface;
use FOSUserBundleCommandCreateUserCommand as BaseCommand;
use SymfonyComponentConsoleQuestionQuestion;
class CreateUserCommand extends BaseCommand
{
/**
* @see Command
*/
protected function configure()
{
parent::configure();
$this
->setName('atelech:user:create')
->getDefinition()->addArguments(
array(
new InputArgument('nom', InputArgument::REQUIRED, 'Le nom'),
new InputArgument('prenom', InputArgument::REQUIRED, 'Le prenom'),
)
);
$this->setHelp(
<<<EOT
// L'aide qui va bien
EOT
);
}
/**
* @see Command
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$username = $input->getArgument('username');
$email = $input->getArgument('email');
$password = $input->getArgument('password');
$nom = $input->getArgument('nom');
$prenom = $input->getArgument('prenom');
$inactive = $input->getOption('inactive');
$superadmin = $input->getOption('super-admin');
$userManager = $this->getContainer()->get('fos_user.user_manager');
/** @var AcmeAcmeUserBundleEntityUser $user */
$user = $userManager->createUser();
$user->setUsername($username);
$user->setEmail($email);
$user->setPlainPassword($password);
$user->setEnabled((Boolean)!$inactive);
$user->setSuperAdmin((Boolean)$superadmin);
$user->setNom($nom);
$user->setPrenom($prenom);
$userManager->updateUser($user);
$output->writeln(sprintf('Created user <comment>%s</comment>', $username));
}
/**
* {@inheritdoc}
*/
protected function interact(InputInterface $input, OutputInterface $output)
{
parent::interact($input, $output);
$questions = array();
foreach (['nom', 'prenom'] as $key) {
if (!$input->getArgument($key)) {
$question = new Question("Please choose a $key:");
$question->setValidator(
function ($username) use ($key) {
if (empty($username)) {
throw new Exception("$key can not be empty");
}
return $username;
}
);
$questions[$key] = $question;
}
}
foreach ($questions as $name => $question) {
$answer = $this->getHelper('question')->ask($input, $output, $question);
$input->setArgument($name, $answer);
}
}
}
и ничего в service.yml — все автоматически подключено правильно
проверьте ваше пространство имен, пожалуйста 🙂
Комментарии:
1. Теперь, когда я пишу свою команду в CMD, у меня возникает эта ошибка: вспомогательный «диалог» не определен : / Я думаю, это из-за моей версии symfony (3.4)… И я не знаю, как я могу перезаписать свою команду создания в этой версии FOSUserBundle:/ (извините за мой плохой английский, я француз)
2. ну, вспомогательный диалог был удален из symfony 3.0, насколько я помню. попробуйте использовать это вместо — symfony.com/doc/current/components/console/helpers /…
3. также можете ли вы показать свою версию FOSBundle? почему вы не можете ее обновить?
4. В моем composer.json есть: «friendsofsymfony / user-bundle»: «~ 2.0». Это хорошо? Спасибо за вашу ссылку! Я прочитаю это
5. Большое вам спасибо! 🙂 По минусам, если я обновлю пакет, это не нарушит все, что я сделал до сих пор? (перегрузка некоторых методов, регистрация и т.д.)?
Ответ №2:
Почему ошибка
У меня была эта ошибка в symfony 4, но это проблема для всех symfony из 3.3 и nevest.
In DefinitionErrorExceptionPass.php line 54:
Cannot autowire service "AppCommandAppUserCreateCommand": argument "$user
Manipulator" of method "__construct()" references class "FOSUserBundleUti
lUserManipulator" but no such service exists. You should maybe alias this
class to the existing "fos_user.util.user_manipulator" service.
это потому, что из Symfony 3.3 службы по умолчанию являются частными и автоматически подключаются. Для исправления вы должны описать свой личный аргумент конструктора команды в services.yml
.
Этот код должен устранить проблему:
AppCommandAppUserCreateCommand:
arguments: ['@fos_user.util.user_manipulator']
Вторая причина этой ошибки. Вы не переопределяете конструктор, но если конструктор расширяемого класса не объявлен, php использует конструктор родительского класса. Этот:
public function __construct(UserManipulator $userManipulator)
{
$this->userManipulator = $userManipulator;
}
таким образом, даже если вы ее не ввели, UserManipulator
используется, и это является причиной ошибки.
Если вы хотите узнать больше, я рекомендую руководство:https://symfonycasts.com/screencast/symfony-3.3/autowiring-aliases
Как я решил эту проблему?
В моем случае я отказался от использования, FOSUserBundleUtilUserManipulator
потому что его метод create
слишком ограничен. Я создаю класс, который ее расширяет:
src/Util/AppUserManipulator.php
<?php
namespace AppUtil;
use AppEntityUser;
use FOSUserBundleEventUserEvent;
use FOSUserBundleFOSUserEvents;
use FOSUserBundleModelUserManagerInterface;
use FOSUserBundleUtilUserManipulator;
use SymfonyComponentEventDispatcherEventDispatcherInterface;
use SymfonyComponentHttpFoundationRequestStack;
use SymfonyComponentHttpFoundationRequest;
class AppUserManipulator extends UserManipulator
{
/**
* User manager.
*
* @var UserManagerInterface
*/
private $userManager;
/**
* @var EventDispatcherInterface
*/
private $dispatcher;
/**
* @var RequestStack
*/
private $requestStack;
/**
* UserManipulator constructor.
*
* @param UserManagerInterface $userManager
* @param EventDispatcherInterface $dispatcher
* @param RequestStack $requestStack
*/
public function __construct(UserManagerInterface $userManager, EventDispatcherInterface $dispatcher, RequestStack $requestStack)
{
parent::__construct($userManager, $dispatcher, $requestStack);
$this->userManager = $userManager;
$this->dispatcher = $dispatcher;
$this->requestStack = $requestStack;
}
/**
* Creates a user and returns it.
*
* @param string $username
* @param string $password
* @param string $email
* @param bool $active
* @param bool $superadmin
* @param string $firstName
* @param string $lastName
* @param string $phoneNumber
*
* @return FOSUserBundleModelUserInterface
*/
public function createAppUser($username, $password, $email, $active, $superadmin, $firstName, $lastName, $phoneNumber)
{
/**
* @var User
*/
$user = $this->userManager->createUser();
if($user instanceof User) {
$user->setUsername($username);
$user->setEmail($email);
$user->setPlainPassword($password);
$user->setEnabled((bool)$active);
$user->setSuperAdmin((bool)$superadmin);
$user->setFirstName($firstName);
$user->setLastName($lastName);
$user->setPhoneNumber($phoneNumber);
$this->userManager->updateUser($user);
$event = new UserEvent($user, $this->getRequest());
$this->dispatcher->dispatch(FOSUserEvents::USER_CREATED, $event);
}
return $user;
}
/**
* @return Request
*/
private function getRequest()
{
return $this->requestStack->getCurrentRequest();
}
}
Команда, которую я создал, содержит код src/Command/AppUserCreateCommand.php
<?php
namespace AppCommand;
use AppUtilAppUserManipulator;
use FOSUserBundleCommandCreateUserCommand;
use FOSUserBundleUtilUserManipulator;
use SymfonyComponentConsoleCommandCommand;
use SymfonyComponentConsoleInputInputArgument;
use SymfonyComponentConsoleInputInputInterface;
use SymfonyComponentConsoleInputInputOption;
use SymfonyComponentConsoleOutputOutputInterface;
use SymfonyComponentConsoleQuestionQuestion;
use SymfonyComponentConsoleStyleSymfonyStyle;
class AppUserCreateCommand extends CreateUserCommand
{
const PROPERTIES = [
'first_name' => 'First Name',
'last_name' => 'Last Name',
'phone_number' => 'Phone Number'
];
protected static $defaultName = 'app:user:create';
private $userManipulator;
public function __construct(AppUserManipulator $userManipulator)
{
parent::__construct($userManipulator);
$this->userManipulator = $userManipulator;
}
/**
* {@inheritdoc}
*/
protected function configure()
{
parent::configure();
$this->setName('app:user:create')
->setHelp(preg_replace('/fos:user:create/', 'app:user:create', $this->getHelp()));
foreach (self::PROPERTIES as $name => $description) {
$this->addArgument($name, InputArgument::REQUIRED, $description);
}
}
/**
* {@inheritdoc}
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
// code from parent start
$username = $input->getArgument('username');
$email = $input->getArgument('email');
$password = $input->getArgument('password');
$inactive = $input->getOption('inactive');
$superadmin = $input->getOption('super-admin');
// code from parent end
foreach (self::PROPERTIES as $name => $description) {
${$name} = $input->getArgument($name);
}
$this->userManipulator->createAppUser($username, $password, $email, !$inactive, $superadmin, ...array_keys(self::PROPERTIES));
$output->writeln(sprintf('Created user <comment>%s</comment>', $username));
}
/**
* {@inheritdoc}
*/
protected function interact(InputInterface $input, OutputInterface $output)
{
parent::interact($input, $output);
$questions = array();
foreach (self::PROPERTIES as $name => $description) {
if (!$input->getArgument($name)) {
$question = new Question("Please choose a $name:");
$question->setValidator(function ($property) use ($name){
if (empty($property)) {
throw new Exception("$name can not be empty");
}
return $property;
});
$questions[$name] = $question;
}
}
foreach ($questions as $name => $question) {
$answer = $this->getHelper('question')->ask($input, $output, $question);
$input->setArgument($name, $answer);
}
}
}
для использования введите
./bin/console app:user:create
примечание: используя мое решение, вы не должны изменять, services.yaml
поскольку службы, определенные мной, например, AppUserManipulator
, по умолчанию автоматически подключаются.