这是以下代码,它实例化从路由传递的控制器:
protected function createController($controller)
{
if (false === strpos($controller, '::')) {
throw new \InvalidArgumentException(sprintf('Unable to find controller "%s".', $controller));
}
list($class, $method) = explode('::', $controller, 2);
if (!class_exists($class)) {
throw new \InvalidArgumentException(sprintf('Class "%s" does not exist.', $class));
}
return array(new $class(), $method);
}
正如你在最后一行所看到的,这总是在没有传递参数的情况下实例化,所以我必须重写这个方法以这种方式注入一些东西。感觉非常hacky。
我正在试图弄清楚如何使用Symfony组件将服务注入动态路由中定义的自定义控制器(例如不完整的堆栈框架)。
请注意,我不使用完整的堆栈框架,并且我没有使用他们的DemoBundle src代码。我有一个需要组件的composer.json
文件,因此我有一个自定义index.php
文件,该文件与此处详述的文件大致相同:
我有以下内容:
$routes = new RouteCollection();
$routes->add(
'some route name',
new Route(
'a route path',
array(
'_controller' => 'App\MyBundle\Controller\MyController::handle'
)
)
);
然后我在App/MyBundle/DependencyInjection/MyExtension.php
内有以下内容:
public function load(array $configs, ContainerBuilder $container) {
$loader = new XmlFileLoader(
$container,
new FileLocator(__DIR__.'/../Resource/config')
);
$loader->load('services.xml');
}
App/MyBundle/Resources/config/services.xml
:
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services
http://symfony.com/schema/dic/services/services-1.0.xsd">
<services>
<service id="templating" class="Symfony\Component\Templating\EngineInterface" />
<service id="navigation" class="App\MyBundle\Controller\MyController">
<argument type="service" id="templating" />
</service>
</services>
</container>
我基本上试图将模板服务注入MyController
构造函数,我的理解是应该自动加载MyExtension
文件。我假设因为我没有使用完整的堆栈框架,这就是原因,但我怎么能让它工作呢?
答案 0 :(得分:2)
覆盖ControllerResolver没有错。完整的堆栈框架也是如此。否则控制器就不能成为ContainerAware。
我也使用没有完整堆栈框架的Symfony组件,并且部分复制完整的堆栈框架,我最终得到了这个以便在我的控制器中注入容器
class ControllerResolver extends SymfonyControllerResolver
{
protected $container;
public function __construct(ContainerInterface $container, LoggerInterface $logger = null)
{
$this->container = $container;
parent::__construct($logger);
}
protected function createController($controller)
{
if (false === strpos($controller, '::')) {
throw new \InvalidArgumentException(sprintf('Unable to find controller "%s".', $controller));
}
list($class, $method) = explode('::', $controller, 2);
$class = "Namespace\\Controllers\\" . $class;
if (!class_exists($class)) {
throw new \InvalidArgumentException(sprintf('Class "%s" does not exist.', $class));
}
$controller = new $class();
if ($controller instanceof ContainerAwareInterface) {
$controller->setContainer($this->container);
}
return array($controller, $method);
}
}
如果您想添加将控制器定义为可以替换的服务的可能性
if (!class_exists($class)) {
throw new \InvalidArgumentException(sprintf('Class "%s" does not exist.', $class));
}
$controller = new $class();
if ($controller instanceof ContainerAwareInterface) {
$controller->setContainer($this->container);
}
类似
if (!class_exists($class)) {
if (!$this->container->has($class)) {
throw new \Exception( ... );
}
$controller = $this->container->get($class);
return array($controller, $method);
}
$controller = new $class();
if ($controller instanceof ContainerAwareInterface) {
$controller->setContainer($this->container);
}
return array($controller, $method);
答案 1 :(得分:0)
Symfony\Bundle\FrameworkBundle\Controller\Controller
,它会注入一个空洞容器。这意味着您可以像这样访问templating
服务:
public function myAction()
{
$templating = $this->get('templating');
}
但Symfony2也为您提供了将控制器创建为服务的可能性。这意味着您从默认的Controller
中删除了扩展,而不仅仅是注入您需要的服务(通常是request
和response
)。更多信息可以在Richard Miller的this great post中找到
您还可以阅读Lukas Kahwe Smith撰写的this post,其中他谈到了为什么他认为服务是最佳实践&#39; (请注意,Symfony项目的前Fabien不同意这一点。)