How exactly can I define a controller as service u

2019-05-17 08:42发布

This seems to be the fastest and simpliest way to use a controller as service, but I am still missing a step because it doesn't work.

Here is my code:

Controller/service:

// Test\TestBundle\Controller\TestController.php

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;

/**
 * @Route(service="test_service")
 */
class TestController extends Controller {
  // My actions
}

Use :

// Test\TestBundle\Controller\UseController.php

// ...
public function useAction() {
  $testService = $this->get('test_service');
}

When I do that, I get the error

You have requested a non-existent service "test_service".

When I check the list of services with app/console container:debug, I don't see my newly created service.

What am I missing?

2条回答
一夜七次
2楼-- · 2019-05-17 09:33

From Controller as Service in SensioFrameworkExtraBundle:

The @Route annotation on a controller class can also be used to assign the controller class to a service so that the controller resolver will instantiate the controller by fetching it from the DI container instead of calling new PostController() itself:

/**
 * @Route(service="my_post_controller_service")
 */
class PostController
{
    // ...
}

The service attribute in the annotation is just to tell Symfony it should use the specified service, instead of instantiating the controller with the new statement. It does not register the service on its own.

Given your controller:

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;

/**
 * @Route(service="test_service")
 */
class TestController
{
    public function myAction()
    {
    }
}

You need to actually register the controller as a service with the test_service id:

services:
    test_service:
        class: Test\TestBundle\Controller\TestController

The advantage of this approach is that you can inject your dependencies into the constructor by specifying them in the service definition, and you don't need to extend the base Controller class.

See How to define controllers as services and Controller as Service in SensioFrameworkExtraBundle.

查看更多
一夜七次
3楼-- · 2019-05-17 09:48

For future folks, if you decide to use controller-as-a-service, you should better inject your services into the controller via the constructor instead of getting them through a service locator. The former is considered to be an antipattern, while the latter allows easy unit testing and is simply more verbose.

So instead of:

public function useAction() {
    $testService = $this->get('test_service');
}

You should:

private $yourService;

public function __construct(YourService $yourService)
{
    $this->yourService = $yourService;
}

public function useAction()
{
    $this->yourService->use(...);
}

Don't create shortcuts, write solid, maintainable code.

查看更多
登录 后发表回答