Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GH-7007: Synchronized Service alternative, backwards compatible. #7707

Closed
wants to merge 7 commits into from

Conversation

beberlei
Copy link
Contributor

Q A
Bug fix? no
New feature? yes
BC breaks? no
Deprecations? no
Tests pass? yes
Fixed tickets GH-7007
License MIT
Doc PR none

Prototype for introducing a RequestContext in HttpKernel.

This PR keeps the synchronized services feature, however introduces a RequestContext object additionally, that allows to avoid using synchronized service when injecting request_context instead of request into a service. The FrameworkBundle is modified such that it does not depend on synchronized services anymore. Users however can still depend on request, activating the synchronized services feature.

Features:

  • Introduced REQUEST_FINSHED (name is up for grabs) event to handle global state and environment cleanup that should not be done in RESPONSE. Called in both exception or success case correctly
  • Changed listeners that were synchronized before to using onKernelRequestFinished and RequestContext to reset to the parent request (RouterListener + LocaleListener).
  • Changed FragmentHandler to use the RequestContext. Added some more tests for this class.
  • RequestStack is injected into the HttpKernel to handle the request finished event and push/pop the stack with requests.

Todos:

  • RequestContext name clashes with Routing components RequestContext. Keep or make unique?
  • Name for Kernel Request Finished Event could be improved.

@stof
Copy link
Member

stof commented Apr 18, 2013

@beberlei the issue when using onKernelResponse is that your service will be broken if a previous listener stops the propagation of the response. and you still have a broken state during the end of the request (after the listener is called while calling lower priority listeners)

@beberlei
Copy link
Contributor Author

@stof hm ok, that makes sense, didn't think about propagation. The state i tried to "fix" by making priority very low.

Maybe for the "stack->pop" case, we still need an event that is fired after kernel.response

@stof
Copy link
Member

stof commented Apr 18, 2013

@beberlei I think it indeed needs an event when leaving the subrequest

public static function getSubscribedEvents()
{
return array(
// must be registered after the Router to have access to the _locale
KernelEvents::REQUEST => array(array('onKernelRequest', 16)),
// should be registered very late
KernelEvents::RESPONSE => array(array('onKernelResponse', -255)),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are reintroducing the exact same bug as we had before synchronized services. Using the response event is not an option here as it is not always called (think of a sub-request that throws an exception for instance).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry my ignorance, It slipped me that it worked this way before. I thought this was viable to get rid of the explicit event for leaving the scope and remove the dependency on EventDispatcher in the RequestStack, but I guess I have to reintroduce this then.

I will rethink my approach.

@stof
Copy link
Member

stof commented Apr 18, 2013

Not supporting the request stack in the normal HttpKernel will break Silex as it does not use the ContainerAware kernel but uses the listeners.

@beberlei
Copy link
Contributor Author

@stof yes, but the problem is that __construct of HttpKernel is tagged with @Api so i cannot inject it there. I would really like to add it there, because it doesn't depend on the container.

@fabpot
Copy link
Member

fabpot commented Apr 18, 2013

@beberlei As this is a constructor, if you add an optional argument at the end, that won't break anything.

@beberlei
Copy link
Contributor Author

Updated the PR introducing a REQUEST_FINISHED event. For now its only in filterResponse in HttpKernel, maybe it needs to be added in other places as well.

I tried to avoid adding another event, but it seems for cleanup of global state + environment it makes sense to add this one.

@beberlei
Copy link
Contributor Author

@fabpot Have rethought this and cannot come up with a better solution. What do you think?

Thumbs up or down?

@fabpot
Copy link
Member

fabpot commented Apr 22, 2013

The RequestContext can also probably be used to fix another problem that we have: see #7453 (current PR on this topic #7461)

@beberlei
Copy link
Contributor Author

Yes, i could extend the PR to have a create() method on the context.

@beberlei
Copy link
Contributor Author

I can work on this tomorrow, is that timely enough?

@beberlei
Copy link
Contributor Author

Btw I am not sure it makes sense to integrate the create() method, a dedicated factory follows the single responsibility principle much more. However I think the code in #7461 is too generic, using call_user_func_array().

@beberlei
Copy link
Contributor Author

@fabpot @stof Updated the PR, adding fragment handler support, so that synchronized services are not used anymore at all in the core. Added more tests and fixed some bugs (Fragment Handler Subcontroller Functional Test was very helpful here).

I removed the WIP flag to open it up for discussion about a potential merge before 2.3 Beta 2

/**
* The REQUEST_FINISHED event occurs when a response was generated for a request.
*
* This event allows you to reset the global and envioronmental state of
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo envioronmental => environmental

$stack->push($request);

$this->assertSame($request, $stack->getCurrentRequest());
$this->assertSame($request, $stack->getCurrentRequest());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this duplication intentional? To verify that getCurrentRequest does not mutate anything?

*/
public function __construct(EventDispatcherInterface $dispatcher, ContainerInterface $container, ControllerResolverInterface $controllerResolver)
public function __construct(EventDispatcherInterface $dispatcher, ContainerInterface $container, ControllerResolverInterface $controllerResolver, RequestStack $requestStack)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should accept null by default for BC.

@fabpot
Copy link
Member

fabpot commented Aug 23, 2013

@beberlei If you don't mind, I'm going to rebase this PR (which has a lot of conflicts now), apply some of the changes mentioned in my comments above and resubmit a new PR for discussion before merging.

@fabpot
Copy link
Member

fabpot commented Aug 31, 2013

rebased version is at #8904

@fabpot fabpot closed this Aug 31, 2013
fabpot added a commit that referenced this pull request Sep 8, 2013
This PR was merged into the master branch.

Discussion
----------

Synchronized Service alternative, backwards compatible

This is a rebased version #7707.

| Q             | A
| ------------- | ---
| Bug fix?      | no
| New feature?  | yes
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | #7707
| License       | MIT
| Doc PR        | symfony/symfony-docs#2956

Todo/Questions

 - [x] do we deprecate the synchronize feature (and removed it in 3.0)?
 - [x] deal with BC for listeners
 - [x] rename RequestContext as we already have a class with the same name in the Routing component?
 - [x] move RequestStack and RequestContext to HttpFoundation?
 - [x] update documentation

Prototype for introducing a ``RequestContext`` in HttpKernel.

This PR keeps the synchronized services feature, however introduces a ``RequestContext`` object additionally, that allows to avoid using synchronized service when injecting ``request_context`` instead of ``request`` into a service. The FrameworkBundle is modified such that it does not depend on synchronized services anymore. Users however can still depend on ``request``, activating the synchronized services feature.

Features:

* Introduced ``REQUEST_FINSHED`` (name is up for grabs) event to handle global state and environment cleanup that should not be done in ``RESPONSE``. Called in both exception or success case correctly
* Changed listeners that were synchronized before to using ``onKernelRequestFinished`` and ``RequestContext`` to reset to the parent request (RouterListener + LocaleListener).
* Changed ``FragmentHandler`` to use the RequestContext. Added some more tests for this class.

* ``RequestStack`` is injected into the ``HttpKernel`` to handle the request finished event and push/pop the stack with requests.

Todos:
* RequestContext name clashes with Routing components RequestContext. Keep or make unique?
* Name for Kernel Request Finished Event could be improved.

Commits
-------

1b2ef74 [Security] made sure that the exception listener is always removed from the event dispatcher at the end of the request
b1a062d moved RequestStack to HttpFoundation and removed RequestContext
93e60ea [HttpKernel] modified listeners to be BC with Symfony <2.4
018b719 [HttpKernel] tweaked the code
f9b10ba [HttpKernel] renamed the kernel finished event
a58a8a6 [HttpKernel] changed request_stack to a private service
c55f1ea added a RequestStack class
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants