Completed
Push — master ( 309e79...fc03a4 )
by Gianluca
02:01
created

App::handleResponse()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 18
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 18
ccs 9
cts 9
cp 1
rs 9.4286
cc 2
eloc 13
nc 2
nop 3
crap 2
1
<?php
2
3
namespace Penny;
4
5
use Exception;
6
use RuntimeException;
7
use Penny\Config\Loader;
8
use Penny\Event\PennyEvmInterface;
9
use Penny\Event\PennyEventInterface;
10
use Penny\Route\RouteInfoInterface;
11
use Interop\Container\ContainerInterface;
12
13
class App
14
{
15
    /**
16
     * Dependency Injection container.
17
     *
18
     * @var ContainerInterface
19
     */
20
    private $container;
21
22
    /**
23
     * Application initialization.
24
     *
25
     * @param ContainerInterface $container Dependency Injection container.
26
     *
27
     * @throws Exception If no router is defined.
28
     */
29 18
    public function __construct(ContainerInterface $container = null)
30
    {
31 18
        if ($container === null) {
32 2
            $container = Container\PHPDiFactory::buildContainer(Loader::load());
33
        }
34
35 18
        if ($container->has('router') === false) {
36 1
            throw new Exception('Define router config');
37
        }
38
39 18
        $this->container = $container;
40 18
    }
41
42
    /**
43
     * Container getter.
44
     *
45
     * @return ContainerInterface
46
     */
47 18
    public function getContainer()
48
    {
49 18
        return $this->container;
50
    }
51
52
    /**
53
     * Penny dispatcher getter.
54
     *
55
     * @return Dispatcher
56
     */
57 15
    private function getDispatcher()
58
    {
59 15
        $dispatcher = $this->container->get('dispatcher');
60 15
        if (!is_callable($dispatcher)) {
61 1
            throw new \RuntimeException('Dispatcher must be a callable');
62
        }
63
64 14
        return $dispatcher;
65
    }
66
67
    /**
68
     * Penny HTTP flow event getter.
69
     *
70
     * @return PennyEvmInterface
71
     */
72 14
    private function getEventManager()
73
    {
74 14
        return $this->container->get('event_manager');
75
    }
76
77
    /**
78
     * Setup event with Request and Response provided
79
     *
80
     * @param mixed|null $request  Representation of an outgoing,
81
     *  client-side request.
82
     * @param mixed|null $response Representation of an incoming,
83
     *  server-side response.
84
     *
85
     * @throws RuntimeException if event did not supported.
86
     */
87 16
    private function setUpEventWithRequestResponse($request, $response)
88
    {
89 16
        $event = $this->getContainer()->get('http_flow_event');
90 16
        if (!$event instanceof PennyEventInterface) {
91 1
            throw new RuntimeException('This event did not supported');
92
        }
93
94 15
        if ($request !== null) {
95 15
            $event->setRequest($request);
96
        }
97 15
        if ($response !== null) {
98 15
            $event->setResponse($response);
99
        }
100
101 15
        return $event;
102
    }
103
104
    /**
105
     * Application execution.
106
     *
107
     * @param mixed|null $request  Representation of an outgoing,
108
     *  client-side request.
109
     * @param mixed|null $response Representation of an incoming,
110
     *  server-side response.
111
     *
112
     * @return mixed
113
     */
114 16
    public function run($request = null, $response = null)
115
    {
116 16
        $event = $this->setUpEventWithRequestResponse($request, $response);
117
118 15
        $dispatcher   = $this->getDispatcher();
119 14
        $eventManager = $this->getEventManager();
120
121
        try {
122 14
            $routeInfo = call_user_func($dispatcher, $event->getRequest());
123 11
            $this->handleRoute($routeInfo, $event);
124 4
        } catch (Exception $exception) {
125 3
            return $this->triggerWithException($eventManager, $event, 'dispatch_error', $exception)
126 3
                        ->getResponse();
127
        }
128 10
        $this->handleResponse($eventManager, $event, $routeInfo);
129
130 9
        return $event->getResponse();
131
    }
132
133
    /**
134
     * Handle Route.
135
     *
136
     * @param RouteInfoInterface $routeInfo
137
     * @param PennyEventInterface $event
138
     *
139
     * @throws RuntimeException if dispatch does not return RouteInfo object.
140
     */
141 10
    private function handleRoute(
142
        RouteInfoInterface $routeInfo,
143
        PennyEventInterface $event
144
    ) {
145 10
        if (!$routeInfo instanceof RouteInfoInterface) {
146
            throw new RuntimeException('Dispatch does not return RouteInfo object');
147
        }
148
149 10
        $event->setRouteInfo($routeInfo);
150 10
        $event->setName($routeInfo->getName());
151 10
    }
152
153
    /**
154
     * Handle Response.
155
     *
156
     * @param PennyEvmInterface $eventManager
157
     * @param PennyEventInterface $event
158
     * @param RouteInfoInterface $routeInfo
159
     */
160
    private function handleResponse(
161
        PennyEvmInterface $eventManager,
162
        PennyEventInterface $event,
163
        RouteInfoInterface $routeInfo
164
    ) {
165 10
        $eventManager->attach($event->getName(), function ($event) use ($routeInfo) {
166 9
            $event->setResponse(call_user_func_array(
167 9
                $routeInfo->getCallable(),
168 9
                [$event->getRequest(), $event->getResponse()] + $routeInfo->getParams()
169
            ));
170 10
        }, 0);
171
172
        try {
173 10
            $eventManager->trigger($event);
174 1
        } catch (Exception $exception) {
175 1
            $this->triggerWithException($eventManager, $event, $routeInfo->getName().'_error', $exception);
176
        }
177 9
    }
178
179
    /**
180
     * Event Manager trigger with exception
181
     *
182
     * @param PennyEvmInterface $eventManager
183
     * @param PennyEventInterface $event
184
     * @param string $name
185
     * @param Exception $exception
186
     *
187
     * @return PennyEventInterface
188
     */
189 4
    private function triggerWithException(
190
        PennyEvmInterface $eventManager,
191
        PennyEventInterface $event,
192
        $name,
193
        Exception $exception
194
    ) {
195 4
        $event->setName($name);
196 4
        $event->setException($exception);
197 4
        $eventManager->trigger($event);
198
199 3
        return $event;
200
    }
201
}
202