JMSDiExtraBundle icon indicating copy to clipboard operation
JMSDiExtraBundle copied to clipboard

[doc] Can't use @Observe in controllers?

Open qpleple opened this issue 12 years ago • 3 comments
trafficstars

I feel like we can't use @Observe in controllers.

Here is my controller:

class DefaultController extends Controller {
    /** @DI\Inject */
    private $event_dispatcher;

    /**
     * @Route("/toy/{name}")
     * @Template()
     */
    public function indexAction($name) {
        $this->event_dispatcher->dispatch("my_event");

        return array('name' => $name);
    }

    /** @DI\Observe("my_event") */
    public function onMyEvent(Event $event) {
        echo "The @Observe in the controller class. <br>";
    }
}

And I have a non-controller class with the exact same @Observe listener:

/** @DI\Service("my_service") */
class MyService {
    /** @DI\Observe("my_event") */
    public function onMyEvent(Event $event) {
        echo "The @Observe in a non-controller class. <br>";
    }
}

When visiting /toy/john, it displays

The @Observe in a non-controller class. 
Hello john!

It looks like indeed we can't use @Observe in controllers:

  • the config is correct because the annotation @Inject is resolved in the controller
  • the event dispatcher setup works because the listener in MyService is called
  • the syntax and setup for @DI\Observe is correct because it's called in MyService but the listener in the controller is not called.

qpleple avatar May 09 '13 17:05 qpleple

Listeners have to be services. your controller is not a service.

Btw, if your controller method is considered as a listener, you have a big issue about the responsibility of your controller class.

stof avatar May 09 '13 22:05 stof

@stof, thanks for your answer. JMSDiExtraBundle's documentation says we can use all DI annotations on controllers, even if they are not services:

Yes, no services, but don’t worry you can still use all of the DIC’s features, and even some more.

Is the documentation misleading on that point or am I missing something?


As for the responsibility, I'm researching implementing with Symfony2 a design pattern that is experimented in the Rails community (here and here) where basically everything that is not parsing HTTP arguments or building HTTP response is outside the controller, but in some core classes. So there has to be some kind of callback mechanism for the core classes to return to the controller. In Rails, they would call some small methods of the controller that returns the HTTP response:

def card_updated(card)
  redirect_to card_path(card), notice: 'Card saved'
end

def card_update_failed(card)
  render action: 'new', alert: 'Ooops!', locals: { card: card }
end

But I feel it is not really possible in Symfony2 as a controller must return a Response object. So it looks like the render or redirect cannot be done by another method than the controller itself.

qpleple avatar May 10 '13 00:05 qpleple

@qpleple a kernel.request listener can set a RedirectResponse in the event if you want (returning it has no effect though).

For the doc, I guess this sentence has been written before implementing Observe

stof avatar May 10 '13 07:05 stof