23

In the controller, I could do

$this->get('service.name')

But in a custom class, how can I do that?

Jiew Meng
  • 84,767
  • 185
  • 495
  • 805

5 Answers5

26

Define your custom class as a service, and then inject dependencies into it.

Ex:

// services.yml
services:
   my.custom.service.id:
       class: My\Custom\Class
       arguments:
         - @service.name
         - @doctrine.orm.entity_manager

Your custom class' constructor would then get those services as arguments.

Be sure to read up on the Service Container in the official docs. It goes over all this in great detail.

Steven Mercatante
  • 24,757
  • 9
  • 65
  • 109
8

You were on the right track with ContainerAware.

$this->get('id') is actually a shortcut to $this->container->get('id'). And getting container into your class is as simple as implementing ContainerAwareInterface - putting this snippet into your class:

public function setContainer(\Symfony\Component\DependencyInjection\ContainerInterface $container = null)
{
    $this->container = $container;
}
Inoryy
  • 8,365
  • 2
  • 39
  • 40
  • 5
    To whoever put -1: I'd really like an explanation why do you think my answer was wrong and what is the right answer. Keep in mind that question was basically: "how to inject service container into custom class?" – Inoryy Dec 24 '11 at 19:41
  • 3
    I'm not the one who downvoted, but the original question was how to access a service in a custom class, not how to inject the service container (which is considered bad practice.) – Steven Mercatante Dec 24 '11 at 20:27
  • 5
    He asked how to access services in a custom class, not how to inject a certain service into it, he even gave an example from controller and was looking himself into ways to replicate the behaviour. Downvoting a perfectly right answer only because it is situationally bad practice is very wrong since we were not given a full use case to decide. So I really hope that wasn't the reasoning behind -1. – Inoryy Dec 24 '11 at 23:10
  • This is also kinda the right answer. $this->get() is from the container and if you have container available in your custom controller you can access services. Best practice is to inject container via "yourController extends ContainerAware". Thats it – TroodoN-Mike Apr 15 '13 at 10:42
  • *Best Practice* - collective agreement that X is the *best* know solution to problem Y. It's possible for them to change, though rarely, as in the case of the Service Locator (SL) pattern which was superseded by Dependency Injection (DI) Containers (DIC) with regards to dependency resolution. SL is even considered an anti-pattern by some Engineers. In this case configuring your controller as a service (Symfony not Web) practices DI, while the container aware approach practices SL. A controller like any object should receive it's dependencies from an external source via it's interface. – Lance Caraccioli Mar 15 '14 at 01:34
  • There are numerous use cases where injecting container itself is the better or sometimes even only solution (scopes, circular depedencies, performance issues). To claim that it is always a bad idea is to show your lack of experience in the topic. – Inoryy Mar 15 '14 at 15:26
  • @Inoryy that's not logically sound. They are Architecturally different solutions, but the mechanics are the same. Either dependencies are fetched and injected via an Object's interface (Dependency Injection), or the Object performs the same dependency fetching internally (Service Locator). Side Note: I have in depth experience with this topic; character assassination discredits your argument. "numerous use cases... the container is injected" == numerous cases of poor design. "Best Practice" is not my opinion, it's defined by the collective. Ctrl+F "always". – Lance Caraccioli Mar 29 '14 at 08:11
  • So where does the container come from if I do this? This doesn't really explain anything. – G_V Nov 17 '16 at 15:31
0

If you do not know the full list of dependencies that you need at the moment when the service is created, you can pass the container as the argument http://symfony.com/doc/current/book/service_container.html#using-the-expression-language

services:  
    service_name:  
        class: AppBundle\Class  
        arguments: ['@=container']
Dmitry
  • 53
  • 7
-2

Accessing the service container in a custom class (not in a service defined class)

This is not best practice to do, but it works. If your custom class is not set to be a service then you can access the service container using global variable $kernel:

class Helper {

    private $container;

    /**
     * Constructor assigns service container to private container. 
     */
    public function __construct() {

        global $kernel;
        $this->container = $kernel->getContainer();

    }

    function doSOmething() {
        $someService = $this->container->get('service.name');
        // do something with someService ...
    }

}
DevWL
  • 17,345
  • 6
  • 90
  • 86
-3

OK I suppose @Arms answer is a possible solution, I found by looking at the source to Controller, I could extend ContainerAware

Jiew Meng
  • 84,767
  • 185
  • 495
  • 805
  • 2
    Keep in mind that if you extend `ContainerAware` you need to manually set the container object. If you're instantiating your custom class somewhere that doesn't have access to the container, this won't be possible. – Steven Mercatante Dec 24 '11 at 05:06
  • 3
    Injecting the whole container is a bad idea. Inject each service you need in your service explicitly. – Elnur Abdurrakhimov Dec 24 '11 at 17:31