Почему ошибка
У меня была эта ошибка в Symfony 4, но это проблема для всех Symfony от 3.3 и nevest.
In DefinitionErrorExceptionPass.php line 54:
Cannot autowire service "App\Command\AppUserCreateCommand": argument "$user
Manipulator" of method "__construct()" references class "FOS\UserBundle\Uti
l\UserManipulator" but no such service exists. You should maybe alias this
class to the existing "fos_user.util.user_manipulator" service.
, потому что из Symfony 3.3 сервисы являются частными по умолчанию иautowired.Чтобы исправить это, вы должны описать свой частный аргумент конструктора команды в services.yml
.
. Этот код должен решить проблему:
App\Command\AppUserCreateCommand:
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
Как я решил эту проблему?
В моем случае я отказался от использования FOS\UserBundle\Util\UserManipulator
, поскольку его метод create
слишком ограничен.Я создаю класс, который расширяет его:
src/Util/AppUserManipulator.php
<?php
namespace App\Util;
use App\Entity\User;
use FOS\UserBundle\Event\UserEvent;
use FOS\UserBundle\FOSUserEvents;
use FOS\UserBundle\Model\UserManagerInterface;
use FOS\UserBundle\Util\UserManipulator;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Request;
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 \FOS\UserBundle\Model\UserInterface
*/
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 App\Command;
use App\Util\AppUserManipulator;
use FOS\UserBundle\Command\CreateUserCommand;
use FOS\UserBundle\Util\UserManipulator;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Question\Question;
use Symfony\Component\Console\Style\SymfonyStyle;
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
note : при использовании моего решения вы не должны изменять services.yaml
, поскольку службы, определенные мной как AppUserManipulator
, по умолчанию подключаются автоматически.