Skip to content

Commit 1ce447b

Browse files
committed
Return a response will shortcut the action
* Shortcut on Response type
1 parent fb09164 commit 1ce447b

File tree

8 files changed

+182
-12
lines changed

8 files changed

+182
-12
lines changed

spec/AppSpec.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@ function it_should_execute_matched_route(
2727
) {
2828
$matched = ["controller" => "A", "action" => "B"];
2929
$matcher->matchRequest(Argument::Any())->willReturn($matched);
30-
$executor->execute(Argument::Any(), Argument::Any(), $matched)->shouldBeCalledTimes(1);
30+
$executor->execute(Argument::Any(), Argument::Any(), $matched)
31+
->willReturn($response)
32+
->shouldBeCalledTimes(1);
3133

3234
$this->run($request, $response)->shouldBe($response);
3335
}

src/App.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public function run(Request $request, Response $response)
2828

2929
try {
3030
$matched = $this->getRouter()->matchRequest($request);
31-
$this->getExecutor()->execute($request, $response, $matched);
31+
$response = $this->getExecutor()->execute($request, $response, $matched);
3232
} catch (ResourceNotFoundException $e) {
3333
$response->setStatusCode(404);
3434
call_user_func_array($this->errorHandler, [$request, $response, $e]);

src/Exception/ShortcutException.php

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php
2+
namespace Corley\Middleware\Exception;
3+
4+
use Exception;
5+
use Symfony\Component\HttpFoundation\Response;
6+
7+
class ShortcutException extends Exception
8+
{
9+
private $response;
10+
11+
public function __construct(Response $response)
12+
{
13+
$this->response = $response;
14+
}
15+
16+
public function getResponse()
17+
{
18+
return $this->response;
19+
}
20+
}

src/Executor/AnnotExecutor.php

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use Corley\Middleware\Annotations\Before;
88
use Corley\Middleware\Annotations\After;
99
use Interop\Container\ContainerInterface;
10+
use Corley\Middleware\Exception\ShortcutException;
1011

1112
class AnnotExecutor
1213
{
@@ -31,15 +32,21 @@ public function execute(Request $request, Response $response, array $matched)
3132
$action = $matched["action"];
3233
$controller = $matched["controller"];
3334

34-
$this->limiter = [];
35-
$this->executeActionsFor($controller, $action, Before::class, $matched, false);
35+
try {
36+
$this->limiter = [];
37+
$this->executeActionsFor($controller, $action, Before::class, $matched, false);
3638

37-
$controller = $this->getContainer()->get($controller);
38-
$data = array_diff_key($matched, array_flip(["annotation", "_route", "controller", "action"]));
39-
$actionReturn = call_user_func_array([$controller, $action], array_merge([$request, $response], $data));
39+
$controller = $this->getContainer()->get($controller);
40+
$data = array_diff_key($matched, array_flip(["annotation", "_route", "controller", "action"]));
41+
$actionReturn = $this->call([$controller, $action], array_merge([$request, $response], $data));
4042

41-
$this->limiter = [];
42-
$this->executeActionsFor($controller, $action, After::class, $actionReturn, true);
43+
$this->limiter = [];
44+
$this->executeActionsFor($controller, $action, After::class, $actionReturn, true);
45+
} catch (ShortcutException $e) {
46+
$response = $e->getResponse();
47+
}
48+
49+
return $response;
4350
}
4451

4552
private function executeActionsFor($controller, $action, $filterClass, $data = null, $after = false)
@@ -59,10 +66,10 @@ private function executeSteps(array $annotations, callable $method, $filterClass
5966
if (!$after) {
6067
$method($annotation->targetClass, $annotation->targetMethod, $filterClass, $data, $after);
6168
}
69+
6270
$newController = $this->getContainer()->get($annotation->targetClass);
63-
call_user_func_array([$newController, $annotation->targetMethod], [
64-
$this->request, $this->response, $data
65-
]);
71+
$this->call([$newController, $annotation->targetMethod], [ $this->request, $this->response, $data ]);
72+
6673
if ($after) {
6774
$method($annotation->targetClass, $annotation->targetMethod, $filterClass, $data, $after);
6875
}
@@ -71,6 +78,17 @@ private function executeSteps(array $annotations, callable $method, $filterClass
7178
}
7279
}
7380

81+
private function call(callable $method, array $params)
82+
{
83+
$response = call_user_func_array($method, $params);
84+
85+
if ($response instanceOf Response) {
86+
throw new ShortcutException($response);
87+
}
88+
89+
return $response;
90+
}
91+
7492
public function getContainer()
7593
{
7694
return $this->container;

tests/AppTest.php

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,4 +181,54 @@ public function testExceptionHandling()
181181

182182
$this->assertSame(1, $count);
183183
}
184+
185+
public function testFlowShortCircuitOnResponse()
186+
{
187+
$request = Request::create("/deny");
188+
$response = new Response();
189+
190+
ob_start();
191+
$this->app->run($request, $response);
192+
$content = ob_get_contents();
193+
ob_end_clean();
194+
195+
$this->assertEquals(401, $response->getStatusCode());
196+
$this->assertEquals("", $content);
197+
}
198+
199+
public function testShortCircuitOnActions()
200+
{
201+
$request = Request::create("/close-direct");
202+
$response = new Response();
203+
204+
ob_start();
205+
$this->app->run($request, $response);
206+
$content = ob_get_contents();
207+
ob_end_clean();
208+
209+
$this->assertEquals(202, $response->getStatusCode());
210+
$this->assertEquals(<<<EOF
211+
Corley\\Demo\\Controller\\Tests\\Seven::action
212+
213+
EOF
214+
, $content);
215+
}
216+
217+
public function testShortCircuitDuringAfterSteps()
218+
{
219+
$request = Request::create("/close-after");
220+
$response = new Response();
221+
222+
ob_start();
223+
$this->app->run($request, $response);
224+
$content = ob_get_contents();
225+
ob_end_clean();
226+
227+
$this->assertEquals(401, $response->getStatusCode());
228+
$this->assertEquals(<<<EOF
229+
Corley\\Demo\\Controller\\Tests\\Seven::pass
230+
231+
EOF
232+
, $content);
233+
}
184234
}

tests/app/Controller/Tests/Http.php

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php
2+
namespace Corley\Demo\Controller\Tests;
3+
4+
use Corley\Middleware\Annotations\Route;
5+
use Symfony\Component\HttpFoundation\Request;
6+
use Symfony\Component\HttpFoundation\Response;
7+
use Corley\Middleware\Annotations\After;
8+
use Corley\Middleware\Annotations\Before;
9+
use Zend\EventManager\EventManager;
10+
11+
class Http
12+
{
13+
public function deny(Request $request, Response $response)
14+
{
15+
$response->setStatusCode(401);
16+
return $response;
17+
}
18+
}
19+
20+

tests/app/Controller/Tests/Seven.php

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
namespace Corley\Demo\Controller\Tests;
3+
4+
use Corley\Middleware\Annotations\Route;
5+
use Symfony\Component\HttpFoundation\Request;
6+
use Symfony\Component\HttpFoundation\Response;
7+
use Corley\Middleware\Annotations\After;
8+
use Corley\Middleware\Annotations\Before;
9+
use Zend\EventManager\EventManager;
10+
11+
class Seven
12+
{
13+
/**
14+
* @Route("/close-direct")
15+
* @After(targetClass="Corley\Demo\Controller\Tests\Six", targetMethod="action")
16+
*/
17+
public function action(Request $request, Response $response)
18+
{
19+
echo __CLASS__ . "::" . __FUNCTION__ . PHP_EOL;
20+
21+
$response->setStatusCode(202);
22+
return $response;
23+
}
24+
25+
/**
26+
* @Route("/close-after")
27+
* @After(targetClass="Corley\Demo\Controller\Tests\Http", targetMethod="deny")
28+
* @After(targetClass="Corley\Demo\Controller\Tests\Seven", targetMethod="action")
29+
*/
30+
public function pass(Request $request, Response $response)
31+
{
32+
echo __CLASS__ . "::" . __FUNCTION__ . PHP_EOL;
33+
}
34+
}
35+
36+

tests/app/Controller/Tests/Six.php

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php
2+
namespace Corley\Demo\Controller\Tests;
3+
4+
use Corley\Middleware\Annotations\Route;
5+
use Symfony\Component\HttpFoundation\Request;
6+
use Symfony\Component\HttpFoundation\Response;
7+
use Corley\Middleware\Annotations\After;
8+
use Corley\Middleware\Annotations\Before;
9+
use Zend\EventManager\EventManager;
10+
11+
/**
12+
* @Before(targetClass="Corley\Demo\Controller\Tests\Http", targetMethod="deny")
13+
*/
14+
class Six
15+
{
16+
/**
17+
* @Route("/deny")
18+
*/
19+
public function action()
20+
{
21+
echo __CLASS__ . "::" . __FUNCTION__ . PHP_EOL;
22+
}
23+
}
24+

0 commit comments

Comments
 (0)