Pax
Pax

Reputation: 183

Use custom service in a Symfony Command

I have created a class with a PHP function I would like to run from the command windows.

Therefore I have created a class extending command but I'm having trouble because I have to call the EntityManagerInterface and the UserPasswordHasherInterface.

If I put them in the constructor and create a new instance, I'm asked to provide the two parameters, which I cannot I guess. So what would be a solution to use those 2 interfaces when I call my method ?

Here my 2 files : TestHashPassword

<?php

namespace App;

use App\Entity\User;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;

class TestHashPassword
{
    private $entityManager;
    private $passwordHasher;

    public function __construct(EntityManagerInterface $em,UserPasswordHasherInterface $passwordHasherInterface){
        $this->entityManager = $em;
        $this->passwordHasher = $passwordHasherInterface;

        parent::__construct();
    }

    public function hashPassword(){
        $em = $this->entityManager; // will throw an error  "Using $this when not in object context"
        $userAll = $em
            ->getRepository(User::class)
            ->findAll();
        echo("coucou");


        foreach($userAll as $user){
            $comb = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890';
            $pass = array();
            $combLen = strlen($comb) - 1;
            for ($i = 0; $i < 8; $i++) {
                $n = rand(0, $combLen);
                $pass[] = $comb[$n];
            };
            echo("coucou");
            $user->setDescription($pass);
            $hashedPassword = $this->passwordHasher->hashPassword(
                $user,
                $pass
            );
            $user->setPassword($hashedPassword);
            $this->entityManager->persist($user);
            $this->entityManager->flush();
        }
    }
}

TestHashPasswordCommand.php

<?php

namespace App\Command;

use App\Entity\User;
use App\TestHashPassword;
use Doctrine\ORM\EntityManagerInterface;
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\Style\SymfonyStyle;
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;

class TestHashPasswordCommand extends Command
{
    protected static $defaultName = 'test-hash-password';
    protected static $defaultDescription = 'Add a short description for your command';

    protected function configure(): void
    {
        $this
            ->addArgument('arg1', InputArgument::OPTIONAL, 'Argument description')
            ->addOption('option1', null, InputOption::VALUE_NONE, 'Option description')
        ;
    }

    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $io = new SymfonyStyle($input, $output);
        $arg1 = $input->getArgument('arg1');

        if ($arg1) {
            $io->note(sprintf('You passed an argument: %s', $arg1));
        }

        if ($input->getOption('option1')) {
            // ...
        }

        $io->success('You have a new command! Now make it your own! Pass --help to see your options.');
        $foobar = new TestHashPassword();  // 2 parameters necessary
        $foobar->hashPassword();
//        TestHashPassword::hashPassword(); // will give an error saying I cannot use $this there
        return Command::SUCCESS;
    }
}

And I run in the command CLI : php .\bin\console test-hash-password

Upvotes: 1

Views: 1033

Answers (2)

Ninja FaZe
Ninja FaZe

Reputation: 11

i use a similar structure for my message generator service used in flash messages

<?php

namespace App\Service;
use Psr\Log\LoggerInterface;

class MessageGenerator
{
    public function __construct(private LoggerInterface $logger)

    {
        $this->messages = [
            'well done',
            'keep it up',
        ];
    }


    public function getMessage(): string
    {
        $this->logger->info(' message has been generated!');
        $index = array_rand($this->messages);
        return $this->messages[$index];
    }

}

i also use the following loop to display the flash messages in my base.html.twig:

   {% for message in app.flashes('success') %}
            <div class="alert alert-success">{{ message }}</div>
        {% endfor %}

finally to call the service i use following code in my controller classes:

$message = $messageGenerator->getMessage();
            $this->addFlash('success', $message);

Upvotes: 0

Dylan KAS
Dylan KAS

Reputation: 5713

You should be able to use autowiring for your command as well (with default services.yaml configuration).

Instead of creating a new TestHashPassword();, use auto wiring to inject it as a service.

Add in your command a __construct:

use App\TestHashPassword;
class TestHashPasswordCommand extends Command
{
    protected $testHashPassword;
    protected static $defaultName = 'test-hash-password';
    protected static $defaultDescription = 'Add a short description for your command';

    public function __construct(TestHashPassword $testHashPassword)
    {
        $this->testHashPassword = $testHashPassword;
    }
    

And then use it with your initialized variable :

$this->testHashPassword->hashPassword();

PS: Why do you have parent::__construct(); in your service constructor if it does not extend a class ?

Upvotes: 3

Related Questions