Skip to content

Commit 7c2f11f

Browse files
committed
Merge pull request #1 from pminnieur/post_response
[HttpKernel] Add Kernel::terminate() and HttpKernel::terminate() for post-response logic (without the BC break)
2 parents 7efe4bc + 9f4391f commit 7c2f11f

File tree

8 files changed

+157
-36
lines changed

8 files changed

+157
-36
lines changed

src/Symfony/Component/HttpKernel/Event/PostResponseEvent.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ class PostResponseEvent extends Event
2323
{
2424
/**
2525
* The kernel in which this event was thrown
26-
* @var Symfony\Component\HttpKernel\HttpKernelInterface
26+
* @var HttpKernelInterface
2727
*/
2828
private $kernel;
2929

@@ -35,10 +35,10 @@ public function __construct(HttpKernelInterface $kernel)
3535
/**
3636
* Returns the kernel in which this event was thrown
3737
*
38-
* @return Symfony\Component\HttpKernel\HttpKernelInterface
38+
* @return HttpKernelInterface
3939
*/
4040
public function getKernel()
4141
{
4242
return $this->kernel;
4343
}
44-
}
44+
}

src/Symfony/Component/HttpKernel/HttpCache/HttpCache.php

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
namespace Symfony\Component\HttpKernel\HttpCache;
1717

1818
use Symfony\Component\HttpKernel\HttpKernelInterface;
19+
use Symfony\Component\HttpKernel\TerminableInterface;
1920
use Symfony\Component\HttpFoundation\Request;
2021
use Symfony\Component\HttpFoundation\Response;
2122

@@ -26,7 +27,7 @@
2627
*
2728
* @api
2829
*/
29-
class HttpCache implements HttpKernelInterface
30+
class HttpCache implements HttpKernelInterface, TerminableInterface
3031
{
3132
private $kernel;
3233
private $store;
@@ -216,15 +217,15 @@ public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQ
216217
}
217218

218219
/**
219-
* Terminates a request/response cycle
220-
*
221-
* Should be called before shutdown, but after sending the response
220+
* {@inheritdoc}
222221
*
223222
* @api
224223
*/
225224
public function terminate()
226225
{
227-
$this->kernel->terminate();
226+
if ($this->getKernel() instanceof TerminableInterface) {
227+
$this->getKernel()->terminate();
228+
}
228229
}
229230

230231
/**

src/Symfony/Component/HttpKernel/HttpKernel.php

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
*
3131
* @api
3232
*/
33-
class HttpKernel implements HttpKernelInterface
33+
class HttpKernel implements HttpKernelInterface, TerminableInterface
3434
{
3535
private $dispatcher;
3636
private $resolver;
@@ -80,9 +80,7 @@ public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQ
8080
}
8181

8282
/**
83-
* Terminates a request/response cycle
84-
*
85-
* Should be called before shutdown, but after sending the response
83+
* {@inheritdoc}
8684
*
8785
* @api
8886
*/

src/Symfony/Component/HttpKernel/HttpKernelInterface.php

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,4 @@ interface HttpKernelInterface
4444
* @api
4545
*/
4646
function handle(Request $request, $type = self::MASTER_REQUEST, $catch = true);
47-
48-
/**
49-
* Terminates a request/response cycle
50-
*
51-
* Should be called after sending the response
52-
*/
53-
function terminate();
5447
}

src/Symfony/Component/HttpKernel/Kernel.php

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444
*
4545
* @api
4646
*/
47-
abstract class Kernel implements KernelInterface
47+
abstract class Kernel implements KernelInterface, TerminableInterface
4848
{
4949
protected $bundles;
5050
protected $bundleMap;
@@ -134,6 +134,22 @@ public function boot()
134134
$this->booted = true;
135135
}
136136

137+
/**
138+
* {@inheritdoc}
139+
*
140+
* @api
141+
*/
142+
public function terminate()
143+
{
144+
if (false === $this->booted) {
145+
return;
146+
}
147+
148+
if ($this->getHttpKernel() instanceof TerminableInterface) {
149+
$this->getHttpKernel()->terminate();
150+
}
151+
}
152+
137153
/**
138154
* Shutdowns the kernel.
139155
*
@@ -171,22 +187,6 @@ public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQ
171187
return $this->getHttpKernel()->handle($request, $type, $catch);
172188
}
173189

174-
/**
175-
* Terminates a request/response cycle
176-
*
177-
* Should be called before shutdown, but after sending the response
178-
*
179-
* @api
180-
*/
181-
public function terminate()
182-
{
183-
if (false === $this->booted) {
184-
throw new \LogicException('The kernel has been shutdown already');
185-
}
186-
187-
$this->getHttpKernel()->terminate();
188-
}
189-
190190
/**
191191
* Gets a http kernel from the container
192192
*
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\HttpKernel;
13+
14+
use Symfony\Component\HttpFoundation\Request;
15+
use Symfony\Component\HttpFoundation\Response;
16+
17+
/**
18+
* Terminable extends the Kernel request/response cycle with dispatching a post
19+
* response event after sending the response and before shutting down the kernel.
20+
*
21+
* @author Jordi Boggiano <[email protected]>
22+
* @author Pierre Minnieur <[email protected]>
23+
*
24+
* @api
25+
*/
26+
interface TerminableInterface
27+
{
28+
/**
29+
* Terminates a request/response cycle.
30+
*
31+
* Should be called after sending the response and before shutting down the kernel.
32+
*
33+
* @api
34+
*/
35+
function terminate();
36+
}

tests/Symfony/Tests/Component/HttpKernel/HttpCache/HttpCacheTest.php

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,43 @@
1111

1212
namespace Symfony\Tests\Component\HttpKernel\HttpCache;
1313

14+
use Symfony\Component\HttpKernel\HttpCache\HttpCache;
15+
use Symfony\Component\HttpKernel\HttpCache\StoreInterface;
16+
use Symfony\Component\HttpKernel\HttpKernelInterface;
1417
require_once __DIR__.'/HttpCacheTestCase.php';
1518

1619
class HttpCacheTest extends HttpCacheTestCase
1720
{
21+
public function testTerminateDelegatesTerminationOnlyForTerminableInterface()
22+
{
23+
$storeMock = $this->getMockBuilder('Symfony\\Component\\HttpKernel\\HttpCache\\StoreInterface')
24+
->disableOriginalConstructor()
25+
->getMock();
26+
27+
// does not implement TerminableInterface
28+
$kernelMock = $this->getMockBuilder('Symfony\\Component\\HttpKernel\\HttpKernelInterface')
29+
->disableOriginalConstructor()
30+
->getMock();
31+
32+
$kernelMock->expects($this->never())
33+
->method('terminate');
34+
35+
$kernel = new HttpCache($kernelMock, $storeMock);
36+
$kernel->terminate();
37+
38+
// implements TerminableInterface
39+
$kernelMock = $this->getMockBuilder('Symfony\\Component\\HttpKernel\\Kernel')
40+
->disableOriginalConstructor()
41+
->setMethods(array('terminate', 'registerBundles', 'registerContainerConfiguration'))
42+
->getMock();
43+
44+
$kernelMock->expects($this->once())
45+
->method('terminate');
46+
47+
$kernel = new HttpCache($kernelMock, $storeMock);
48+
$kernel->terminate();
49+
}
50+
1851
public function testPassesOnNonGetHeadRequests()
1952
{
2053
$this->setNextResponse(200);

tests/Symfony/Tests/Component/HttpKernel/KernelTest.php

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -652,6 +652,66 @@ public function testInitializeBundleThrowsExceptionWhenABundleExtendsItself()
652652
$kernel->initializeBundles();
653653
}
654654

655+
public function testTerminateReturnsSilentlyIfKernelIsNotBooted()
656+
{
657+
$kernel = $this->getMockBuilder('Symfony\Tests\Component\HttpKernel\KernelForTest')
658+
->disableOriginalConstructor()
659+
->setMethods(array('getHttpKernel'))
660+
->getMock();
661+
662+
$kernel->expects($this->never())
663+
->method('getHttpKernel');
664+
665+
$kernel->setIsBooted(false);
666+
$kernel->terminate();
667+
}
668+
669+
public function testTerminateDelegatesTerminationOnlyForTerminableInterface()
670+
{
671+
// does not implement TerminableInterface
672+
$httpKernelMock = $this->getMockBuilder('Symfony\Component\HttpKernel\HttpKernelInterface')
673+
->disableOriginalConstructor()
674+
->getMock();
675+
676+
$httpKernelMock
677+
->expects($this->never())
678+
->method('terminate');
679+
680+
$kernel = $this->getMockBuilder('Symfony\Tests\Component\HttpKernel\KernelForTest')
681+
->disableOriginalConstructor()
682+
->setMethods(array('getHttpKernel'))
683+
->getMock();
684+
685+
$kernel->expects($this->once())
686+
->method('getHttpKernel')
687+
->will($this->returnValue($httpKernelMock));
688+
689+
$kernel->setIsBooted(true);
690+
$kernel->terminate();
691+
692+
// implements TerminableInterface
693+
$httpKernelMock = $this->getMockBuilder('Symfony\Component\HttpKernel\HttpKernel')
694+
->disableOriginalConstructor()
695+
->setMethods(array('terminate'))
696+
->getMock();
697+
698+
$httpKernelMock
699+
->expects($this->once())
700+
->method('terminate');
701+
702+
$kernel = $this->getMockBuilder('Symfony\Tests\Component\HttpKernel\KernelForTest')
703+
->disableOriginalConstructor()
704+
->setMethods(array('getHttpKernel'))
705+
->getMock();
706+
707+
$kernel->expects($this->exactly(2))
708+
->method('getHttpKernel')
709+
->will($this->returnValue($httpKernelMock));
710+
711+
$kernel->setIsBooted(true);
712+
$kernel->terminate();
713+
}
714+
655715
protected function getBundle($dir = null, $parent = null, $className = null, $bundleName = null)
656716
{
657717
$bundle = $this

0 commit comments

Comments
 (0)