自2.4以来服务上的Ajax错误:自定义事件+请求范围

时间:2014-03-24 10:53:18

标签: php symfony

自从我从Symfony 2.1升级到2.4后,我遇到了一个非常意想不到的错误。现在我只能推测它发生的原因:

[2014-03-24 10:32:19] emergency.EMERGENCY: Uncaught exception 'Symfony\Component\DependencyInjection\Exception\InactiveScopeException' with message 'You cannot create a service ("form.type.daterange") of an inactive scope ("request").' in D:\Users\abousquet\workspace\eportal\app\cache\dev\appDevDebugProjectContainer.php:1231
Stack trace:
#0 D:\Users\abousquet\workspace\eportal\app\bootstrap.php.cache(2033): appDevDebugProjectContainer->getForm_Type_DaterangeService()
#1 D:\Users\abousquet\workspace\eportal\app\cache\dev\classes.php(1842): Symfony\Component\DependencyInjection\Container->get('form.type.dater...')
#2 D:\Users\abousquet\workspace\eportal\app\cache\dev\classes.php(1807): Symfony\Component\EventDispatcher\ContainerAwareEventDispatcher->lazyLoad('resources.autol...')
#3 D:\Users\abousquet\workspace\eportal\vendor\symfony\symfony\src\Symfony\Component\HttpKernel\Debug\TraceableEventDispatcher.php(106): Symfony\Component\EventDispatcher\ContainerAwareEventDispatcher->getListeners(NULL)
#4 D:\Users\abousquet\workspace\eportal\vendor\symfony\sy {"type":1,"file":"D:\\Users\\abousquet\\workspace\\eportal\\app\\cache\\dev\\appDevDebugProjectContainer.php","line":1231} []

每当我尝试使用Ajax访问任何页面时,都会在DEV中触发错误。它在页面呈现后触发(控制器的操作正确完成,之后发生错误)。这使得在错误产生时很难理解。

服务 form.type.dateRange 是一种自定义表单类型,也是注册为事件订阅者。这是它的服务定义:

<service id="form.type.dateRange" class="eportal\CoreBundle\Form\DateRangeType" scope="request">
    <argument type="service" id="calendar.conf.reader" />
    <tag name="form.type" alias="dateRange" />
    <tag name="kernel.event_subscriber" />
</service>

此服务在自定义事件 resources.autoload 上注册,该事件在呈现页面之前在我的主控制器中触发 - 但从未使用过Ajax页面。

正如日志所说,似乎请求服务在请求此服务时不可用。但何时以及为什么要求它?在我看来,删除那个神秘的电话会解决我的问题。

如果我取消订阅事件注册或扩大范围,则不会弹出错误。我坚信自定义事件+请求范围的组合在某种程度上是我的问题的根源。

当我阻止 form.type.dateRange 上的错误时,在具有相同范围的同一事件上注册的某些其他服务将失败。因此,我班上的编码错误似乎不太可能。

最后一个有趣的事实:当实际使用这些失败的服务时,错误会在页面上触发。

修改

触发我的自定义事件的代码。它是 render()方法的重写:

abstract class HTMLControllerAbstract extends CoreControllerAbstract
{
    ...

    public function render($view, array $parameters = array(), Response $response = null)
    {
        $event = new FilterControllerEvent(
            $this->get('kernel'),
            array($this, 'render'),
            $this->getRequest(),
            HttpKernelInterface::MASTER_REQUEST
        );

        $this->get('event_dispatcher')->dispatch(StoreEvents::RESOURCES_AUTOLOAD, $event);

        $this->setReplacement('breadcrumb', $this->breadcrumb->getView());
        $this->setReplacement('javascripts', $this->javascriptResources);
        $this->setReplacement('stylesheets', $this->CSSResources);
        $this->setReplacement('see_also', $this->_getSeeAlso());

        return parent::render($view, $parameters, $response);
    }

    ...
}

修改

什么有效:删除&#39;请求&#39;使用自定义事件的所有服务的范围。不会记录任何错误,但我仍然担心连续两个页面会被同一个请求服务实例处理。

我仍觉得解决方案有点不满意。没有明确的理由说明请求范围会因自定义事件而失败。

接受的回复:

正如我所怀疑的那样,问题发生在一个隐藏的子呼叫中,到目前为止我仍然无法完全理解。解决方案? Manolo Salsas 提供的解决方案最终是正确的,但我当时不知道应该写出这两个loc的位置。现在我知道,它必须在app / AppKernel.php中:

class AppKernel extends Kernel
{
    ...

    public function registerBundles()
    {
        ...
    }

    public function registerContainerConfiguration(LoaderInterface $loader)
    {
        ...
    }

    protected function initializeContainer()
    {
        parent::initializeContainer();
        $this->getContainer()->enterScope('request'); 
        $this->getContainer()->set('request', new \Symfony\Component\HttpFoundation\Request(), 'request');
    }
}

在我的特定情况下适用的另一种解决方案是从崩溃的表单类型中删除请求参数。由于请求用于自动填充某些表单选项,因此解决方案是从订阅自定义事件的服务以外的任何位置手动填充这些选项。

1 个答案:

答案 0 :(得分:0)

如果您想访问Request对象,可以扩展ContainerAware并:

$this->getContainer()->enterScope('request');
$this->getContainer()->set('request', new Request(), 'request');