php - Why my interface is not instantiable when handle a command?
Laravel CQRS
I am applying CQRS in Laravel just to learn how to use it.
I created a simple user registration and a controller that creates a command to dispatch the handle and use the right use case.
When Trying to use the interface in the controller, it looks like that I need to bind the interface and the implementation because it doesn't know which one to use but in this case I don't really understand how to bind the interface.
CreateUserController.php
<?php
    
    declare(strict_types=1);
    
    namespace App\Http\Controllers\User;
    use App\Http\Controllers\Controller;
    use App\Http\Requests\Users\CreateUserRequest;
    use Illuminate\Http\RedirectResponse;
    
    class CreateUserController extends Controller
    {
        public function __construct(private \Src\User\Infrastructure\CreateUserController $userController)
        {
        }
    
        public function __invoke(CreateUserRequest $request): RedirectResponse
        {
            $this->userController->__invoke($request);
    
            return redirect()->route('verify');
        }
    }
Src\User\Infrastructure\CreateUserController
<?php
declare(strict_types=1);
namespace Src\User\Infrastructure;
use App\Http\Requests\Users\CreateUserRequest;
use Src\Shared\Domain\Bus\Command\CommandBus;
use Src\User\Application\Create\CreateUserCommand;    
final class CreateUserController
{    
    public function __construct(private CommandBus $commandBus)
    {
    }
    public function __invoke(CreateUserRequest $request)
    {
        $name = $request->name;
        $email = $request->email;
        $password = $request->password;
        $command = new CreateUserCommand($name, $email, $password);
        $this->commandBus->dispatch($command);
    }
}
CommandBus
<?php
declare(strict_types=1);
namespace Src\Shared\Domain\Bus\Command;
interface CommandBus
{
    public function dispatch(Command $command): void;
}
Command
<?php
declare(strict_types=1);
namespace Src\Shared\Domain\Bus\Command;
interface Command
{
}
CreateUserCommandHandler
<?php
declare(strict_types=1);
namespace Src\User\Application\Create;
use Src\User\Domain\ValueObjects\UserEmail;
use Src\User\Domain\ValueObjects\UserName;
use Src\User\Domain\ValueObjects\UserPassword;
final class CreateUserCommandHandler
{
    public function __construct(
        private UserCreator $creator
    )
    {
    }
    public function __invoke(CreateUserCommand $command)
    {
        $name = new UserName($command->name());
        $email = new UserEmail($command->email());
        $password = new UserPassword($command->password());
        $this->creator->__invoke($name, $email, $password);
    }
}
The Error
I tried this:
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Src\Shared\Domain\Bus\Command\Command;
use Src\User\Application\Create\CreateUserCommand;
class AppServiceProvider extends ServiceProvider
{
    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        $this->app->bind(
            Command::class,
            CreateUserCommand::class
        );
    }
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        //
    }
}
Answer
Solution:
Here is how you can bind with the interface.
Create a class in app/Providers folder. You can give any name to this class. Eg. InterfaceServiceProvider. extends it with Illuminate\Support\ServiceProvider
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class InterfaceServiceProvider extends ServiceProvider
{
    /**
     * Register services.
     *
     * @return void
     */
    public function register()
    {
        $this->app->bind(YourInterFace::class, YourController::class);
    }
    /**
     * Bootstrap services.
     *
     * @return void
     */
    public function boot()
    {
        //
    }
}
Add this
InterfaceServiceProviderinconfig/app.phpinprovidersarray Eg.
'providers' => [
App\Providers\InterfaceServiceProvider::class,
]
Source