Completed
Pull Request — master (#141)
by Abdul Malik
01:58
created

App::handleRoute()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 2

Importance

Changes 3
Bugs 1 Features 0
Metric Value
c 3
b 1
f 0
dl 0
loc 9
ccs 6
cts 6
cp 1
rs 9.6667
cc 2
eloc 5
nc 2
nop 2
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 2
        }
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 15
        }
97 15
        if ($response !== null) {
98 15
            $event->setResponse($response);
99 15
        }
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 14
        } catch (Exception $exception) {
125 4
            return $this->triggerWithException($eventManager, $event, 'dispatch_error', $exception)
126 4
                        ->getResponse();
127
        }
128 10
        $this->handleResponse($eventManager, $event, $routeInfo);
129
130 9
        return $event->getResponse();
131
    }
132
133
    /**
134
     * Handle Route.
135
     *
136
     * @param $routeInfo
137
     * @param PennyEventInterface $event
138
     *
139
     * @throws RuntimeException if dispatch does not return RouteInfo object.
140
     */
141 11
    private function handleRoute($routeInfo, PennyEventInterface $event)
142
    {
143 11
        if (!$routeInfo instanceof RouteInfoInterface) {
144 1
            throw new RuntimeException('Dispatch does not return RouteInfo object');
145
        }
146
147 10
        $event->setRouteInfo($routeInfo);
148 10
        $event->setName($routeInfo->getName());
149 10
    }
150
151
    /**
152
     * Handle Response.
153
     *
154
     * @param PennyEvmInterface $eventManager
155
     * @param PennyEventInterface $event
156
     * @param RouteInfoInterface $routeInfo
157
     */
158
    private function handleResponse(
159
        PennyEvmInterface $eventManager,
160
        PennyEventInterface $event,
161
        RouteInfoInterface $routeInfo
162
    ) {
163 10
        $eventManager->attach($event->getName(), function ($event) use ($routeInfo) {
164 9
            $event->setResponse(call_user_func_array(
165 9
                $routeInfo->getCallable(),
166 9
                [$event->getRequest(), $event->getResponse()] + $routeInfo->getParams()
167 9
            ));
168 10
        }, 0);
169
170
        try {
171 10
            $eventManager->trigger($event);
172 10
        } catch (Exception $exception) {
173 1
            $this->triggerWithException($eventManager, $event, $routeInfo->getName().'_error', $exception);
174
        }
175 9
    }
176
177
    /**
178
     * Event Manager trigger with exception
179
     *
180
     * @param PennyEvmInterface $eventManager
181
     * @param PennyEventInterface $event
182
     * @param string $name
183
     * @param Exception $exception
184
     *
185
     * @return PennyEventInterface
186
     */
187 5
    private function triggerWithException(
188
        PennyEvmInterface $eventManager,
189
        PennyEventInterface $event,
190
        $name,
191
        Exception $exception
192
    ) {
193 5
        $event->setName($name);
194 5
        $event->setException($exception);
195 5
        $eventManager->trigger($event);
196
197 4
        return $event;
198
    }
199
}
200