This repository has been archived on 2023-08-20. You can view files and clone it, but cannot push or open issues or pull requests.
symfony/src/Symfony/Component/HttpKernel
Fabien Potencier 74f96bfebf merged branch fabpot/contagious-services (PR #7007)
This PR was merged into the master branch.

Discussion
----------

[2.3] [WIP] Synchronized services...

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

Todo:

 - [x] update documentation
 - [x] find a better name than contagious (synchronized)?

refs #6932, refs #5012

This PR is a proof of concept that tries to find a solution for some problems we have with scopes and services depending on scoped services (mostly the request service in Symfony).

Basically, whenever you want to inject the Request into a service, you have two possibilities:

 * put your own service into the request scope (a new service will be created whenever a sub-request is run, and the service is not available outside the request scope);

 * set the request service reference as non-strict (your service is always available but the request you have depends on when the service is created the first time).

This PR addresses this issue by allowing to use the second option but you service still always has the right Request service (see below for a longer explanation on how it works).

There is another issue that this PR fixes: edge cases and weird behaviors. There are several bug reports about some weird behaviors, and most of the time, this is related to the sub-requests. That's because the Request is injected into several Symfony objects without being updated correctly when leaving the request scope. Let me explain that: when a listener for instance needs the Request object, it can listen to the `kernel.request` event and store the request somewhere. So, whenever you enter a sub-request, the listener will get the new one. But when the sub-request ends, the listener has no way to know that it needs to reset the request to the master one. In practice, that's not really an issue, but let me show you an example of this issue in practice:

 * You have a controller that is called with the English locale;
 * The controller (probably via a template) renders a sub-request that uses the French locale;
 *  After the rendering, and from the controller, you try to generate a URL. Which locale the router will use? Yes, the French locale, which is wrong.

To fix these issues, this PR introduces a new notion in the DIC: synchronized services. When a service is marked as synchronized, all method calls involving this service will be called each time this service is set. When in a scope, methods are also called to restore the previous version of the service when the scope leaves.

If you have a look at the router or the locale listener, you will see that there is now a `setRequest` method that will called whenever the request service changes (because the `Container::set()` method is called or because the service is changed by a scope change).

Commits
-------

17269e1 [DependencyInjection] fixed management of scoped services with an invalid behavior set to null
bb83b3e [HttpKernel] added a safeguard for when a fragment is rendered outside the context of a master request
5d7b835 [FrameworkBundle] added some functional tests
ff9d688 fixed Request management for FragmentHandler
1b98ad3 fixed Request management for LocaleListener
a7b2b7e fixed Request management for RequestListener
0892135 [HttpKernel] ensured that the Request is null when outside of the Request scope
2ffcfb9 [FrameworkBundle] made the Request service synchronized
ec1e7ca [DependencyInjection] added a way to automatically update scoped services
2013-03-23 14:07:03 +01:00
..
Bundle Fixed most of the docblocks/unused namespaces 2012-12-19 08:09:49 +01:00
CacheClearer fixed CS 2012-07-09 14:54:20 +02:00
CacheWarmer fixed CS 2012-07-09 14:54:20 +02:00
Config fixed phpdoc @param alignment 2012-05-15 22:19:31 +02:00
Controller renamed some classes and Twig functions to more descriptive names (refs #6871) 2013-02-01 15:17:20 +01:00
DataCollector [HttpKernel] fixed memory collector 2013-03-18 16:18:56 +01:00
Debug [HttpKernel] Updated TraceableEventDispatcher.php 2013-03-14 12:41:05 +01:00
DependencyInjection merged branch fabpot/contagious-services (PR #7007) 2013-03-23 14:07:03 +01:00
Event Remove array type hint from GetResponseForControllerResultEvent::setControllerResult() 2013-02-13 02:35:51 +01:00
EventListener fixed Request management for LocaleListener 2013-03-20 17:13:40 +01:00
Exception Fixed most of the docblocks/unused namespaces 2012-12-19 08:09:49 +01:00
Fragment merged branch fabpot/contagious-services (PR #7007) 2013-03-23 14:07:03 +01:00
HttpCache Merge branch '2.1' into 2.2 2013-03-15 11:54:52 +01:00
Log Fixed the NullLogger to implement the HttpKernel interface again 2013-01-30 20:59:27 +01:00
Profiler Merge branch '2.1' into 2.2 2013-03-11 18:18:44 +01:00
Tests merged branch fabpot/contagious-services (PR #7007) 2013-03-23 14:07:03 +01:00
.gitignore make it possible for bundles extensions to prepend settings into the application configuration of any Bundle 2012-12-07 10:45:48 +01:00
CHANGELOG.md updated various CHANGELOG files that were not updated when the PRs were merged 2013-03-23 08:35:36 +01:00
Client.php added Universal* classes in the list of deprecated classes for 3.0 2013-02-08 17:10:00 +01:00
composer.json changed dependencies to allow all 2.3 versions of the components (closes #6983) 2013-02-11 11:13:11 +01:00
HttpKernel.php Fugbix typo 2013-01-31 09:00:54 +01:00
HttpKernelInterface.php fixed CS 2012-07-09 14:54:20 +02:00
Kernel.php [HttpKernel] moved the Container compilation for more flexibility 2013-03-20 16:37:56 +01:00
KernelEvents.php Fixed typos 2012-07-28 22:02:29 +00:00
KernelInterface.php CS Fixes - Replaced "array of type" by "Type[]" in PHPDoc block 2012-11-19 13:58:52 +01:00
LICENSE updated license year 2013-01-04 17:59:43 +01:00
phpunit.xml.dist made usage of Composer autoloader for subtree-split unit tests 2012-11-09 14:10:06 +01:00
README.md made usage of Composer autoloader for subtree-split unit tests 2012-11-09 14:10:06 +01:00
TerminableInterface.php fixed CS 2012-07-09 14:54:20 +02:00
UriSigner.php tweaked previous commit 2013-02-01 22:56:52 +01:00

HttpKernel Component

HttpKernel provides the building blocks to create flexible and fast HTTP-based frameworks.

HttpKernelInterface is the core interface of the Symfony2 full-stack framework:

interface HttpKernelInterface
{
    /**
     * Handles a Request to convert it to a Response.
     *
     * @param  Request $request A Request instance
     *
     * @return Response A Response instance
     */
    function handle(Request $request, $type = self::MASTER_REQUEST, $catch = true);
}

It takes a Request as an input and should return a Response as an output. Using this interface makes your code compatible with all frameworks using the Symfony2 components. And this will give you many cool features for free.

Creating a framework based on the Symfony2 components is really easy. Here is a very simple, but fully-featured framework based on the Symfony2 components:

$routes = new RouteCollection();
$routes->add('hello', new Route('/hello', array('_controller' =>
    function (Request $request) {
        return new Response(sprintf("Hello %s", $request->get('name')));
    }
)));

$request = Request::createFromGlobals();

$context = new RequestContext();
$context->fromRequest($request);

$matcher = new UrlMatcher($routes, $context);

$dispatcher = new EventDispatcher();
$dispatcher->addSubscriber(new RouterListener($matcher));

$resolver = new ControllerResolver();

$kernel = new HttpKernel($dispatcher, $resolver);

$kernel->handle($request)->send();

This is all you need to create a flexible framework with the Symfony2 components.

Want to add an HTTP reverse proxy and benefit from HTTP caching and Edge Side Includes?

$kernel = new HttpKernel($dispatcher, $resolver);

$kernel = new HttpCache($kernel, new Store(__DIR__.'/cache'));

Want to functional test this small framework?

$client = new Client($kernel);
$crawler = $client->request('GET', '/hello/Fabien');

$this->assertEquals('Fabien', $crawler->filter('p > span')->text());

Want nice error pages instead of ugly PHP exceptions?

$dispatcher->addSubscriber(new ExceptionListener(function (Request $request) {
    $msg = 'Something went wrong! ('.$request->get('exception')->getMessage().')';

    return new Response($msg, 500);
}));

And that's why the simple looking HttpKernelInterface is so powerful. It gives you access to a lot of cool features, ready to be used out of the box, with no efforts.

Resources

You can run the unit tests with the following command:

$ cd path/to/Symfony/Component/HttpKernel/
$ composer.phar install --dev
$ phpunit