vincent15000's avatar

Services used inside controllers

Hello,

What's the bests way of using services inside controller ?

    private $eventService;

    private $locationService;

    private $typeService;

    public function __construct()
    {
        $this->eventService = new EventService;
        $this->locationService = new LocationService;
        $this->typeService = new TypeService;
    }

This way the services are loaded at each request, but I don't need all services at each request.

So what's the best alternative ?

(new EventService)->someMethod();

or

app()->make(EventService::class)->someMethod();

Or is it all the way interesting to inject the service as a dependancy directly inside the constructor ?

Thanks for your response ;).

V

1 like
4 replies
LaryAI's avatar
Level 58

Great question! The best practice in Laravel for using services inside controllers is dependency injection. This allows Laravel’s service container to handle the resolution of dependencies, and you get the benefits of loose coupling, easier testing, and improved code clarity.

1. Constructor Injection (Recommended)

Pros:

  • Services are automatically resolved by the container.
  • Easy to mock for unit testing.
  • Clear code structure.

You can type-hint your services in the controller's constructor:

use App\Services\EventService;
use App\Services\LocationService;
use App\Services\TypeService;

class MyController extends Controller
{
    protected $eventService;
    protected $locationService;
    protected $typeService;

    public function __construct(
        EventService $eventService,
        LocationService $locationService,
        TypeService $typeService
    ) {
        $this->eventService = $eventService;
        $this->locationService = $locationService;
        $this->typeService = $typeService;
    }

    public function someMethod()
    {
        // Use $this->eventService as needed
    }
}

If you don't need all services for all actions, consider method injection instead:

2. Method Injection

Inject only the services you need into individual controller methods:

use App\Services\EventService;

public function store(Request $request, EventService $eventService)
{
    $eventService->someMethod();
}

This way, services are only resolved if/when that method is called.


3. Using app()->make(...)

app()->make(EventService::class)->someMethod();

This does work, but it's less clean, harder to test, and violates the principle of relying on abstractions instead of concrete classes. Avoid this for regular usage except in rare dynamic cases.

4. Instantiating services manually (new EventService)

Avoid this, as it binds you to the concrete class, and you lose out on the ability to inject dependencies into those services (e.g., services that need a repository, etc).


Summary:

  • Use constructor injection if you always need the services.
  • Use method injection if you only need them for some methods.
  • Prefer dependency injection over manually creating instances or using the service container for regular controller actions.

Let me know if you have more specific use-cases in mind!

JussiMannisto's avatar
Level 50

The first question is whether you should instantiate them in the controller or in the service container. The service container is better for testing because you can pass mock interfaces easily. If these are simple utility services that don't warrant mocking, it may not be necessary. I prefer dependency injection in general.

There's no reason to instantiate the services in the constructor if, like you said, you don't need them on every request. You don't need to keep them as properties either. You can inject them directly into the methods that need them:

public function index(Request $request, MyApi $api): Response 
{
...
}
1 like
vincent15000's avatar

I think that classes injected inside a controller constructor or method are also mockable.

JussiMannisto's avatar

Injected (or manually resolved) dependencies are easy to mock, whether you do it in a constructor or another method. If you instead instantiate the service objects directly in the controller, it gets a lot uglier. Mocking may still be possible with tricks like reflection, but there's no reason to go there. It's simple if you use dependencies.

1 like

Please or to participate in this conversation.