Completed
Pull Request — master (#149)
by Abdul Malik
02:03
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 6
Bugs 2 Features 0
Metric Value
c 6
b 2
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\EventManagerInterface;
9
use Penny\Event\EventInterface;
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 19
    public function __construct(ContainerInterface $container = null)
30
    {
31 19
        if ($container === null) {
32 2
            $container = Container\PHPDiFactory::buildContainer(Loader::load());
33
        }
34
35 19
        if ($container->has('router') === false) {
36 1
            throw new Exception('Define router config');
37
        }
38
39 19
        $this->container = $container;
40 19
    }
41
42
    /**
43
     * Container getter.
44
     *
45
     * @return ContainerInterface
46
     */
47 19
    public function getContainer()
48
    {
49 19
        return $this->container;
50
    }
51
52
    /**
53
     * Penny dispatcher getter.
54
     *
55
     * @return Dispatcher
56
     */
57 16
    private function getDispatcher()
58
    {
59 16
        $dispatcher = $this->container->get('dispatcher');
60 16
        if (!is_callable($dispatcher)) {
61 1
            throw new RuntimeException('Dispatcher must be a callable');
62
        }
63 15
        if (!$dispatcher instanceof Dispatcher) {
64 1
            throw new RuntimeException(sprintf(
65 1
                'Dispatcher must be an instance of %s\Dispatcher class',
66 1
                __NAMESPACE__
67
            ));
68
        }
69
70 14
        return $dispatcher;
71
    }
72
73
    /**
74
     * Penny HTTP flow event getter.
75
     *
76
     * @return EventManagerInterface
77
     */
78 14
    private function getEventManager()
79
    {
80 14
        return $this->container->get('event_manager');
81
    }
82
83
    /**
84
     * Setup event with Request and Response provided
85
     *
86
     * @param mixed|null $request  Representation of an outgoing,
87
     *  client-side request.
88
     * @param mixed|null $response Representation of an incoming,
89
     *  server-side response.
90
     *
91
     * @throws RuntimeException if event did not supported.
92
     */
93 17
    private function setUpEventWithRequestResponse($request, $response)
94
    {
95 17
        $event = $this->getContainer()->get('http_flow_event');
96 17
        if (!$event instanceof EventInterface) {
97 1
            throw new RuntimeException('This event did not supported');
98
        }
99
100 16
        if ($request !== null) {
101 15
            $event->setRequest($request);
102
        }
103 16
        if ($response !== null) {
104 15
            $event->setResponse($response);
105
        }
106
107 16
        return $event;
108
    }
109
110
    /**
111
     * Application execution.
112
     *
113
     * @param mixed|null $request  Representation of an outgoing,
114
     *  client-side request.
115
     * @param mixed|null $response Representation of an incoming,
116
     *  server-side response.
117
     *
118
     * @return mixed
119
     */
120 17
    public function run($request = null, $response = null)
121
    {
122 17
        $event = $this->setUpEventWithRequestResponse($request, $response);
123
124 16
        $dispatcher   = $this->getDispatcher();
125 14
        $eventManager = $this->getEventManager();
126
127 14
        $eventManager->trigger($event);
128
129
        try {
130 14
            $routeInfo = call_user_func($dispatcher, $event->getRequest());
131 11
            $event->setRouteInfo($routeInfo);
132 11
            $event->setName($routeInfo->getName());
133 3
        } catch (Exception $exception) {
134 3
            return $this->triggerWithException($eventManager, $event, 'dispatch_error', $exception)
135 3
                        ->getResponse();
136
        }
137 11
        $this->handleResponse($eventManager, $event, $routeInfo);
138
139 9
        return $event->getResponse();
140
    }
141
142
    /**
143
     * Handle Response.
144
     *
145
     * @param EventManagerInterface $eventManager
146
     * @param EventInterface $event
147
     * @param RouteInfoInterface $routeInfo
148
     */
149
    private function handleResponse(
150
        EventManagerInterface $eventManager,
151
        EventInterface $event,
152
        RouteInfoInterface $routeInfo
153
    ) {
154 11
        $eventManager->attach($event->getName(), function ($event) use ($routeInfo) {
155 10
            $event->setResponse(call_user_func_array(
156 10
                $routeInfo->getCallable(),
157 10
                [$event->getRequest(), $event->getResponse()] + $routeInfo->getParams()
158
            ));
159 11
        }, 0);
160
161
        try {
162 11
            $eventManager->trigger($event);
163 2
        } catch (Exception $exception) {
164 1
            $this->triggerWithException($eventManager, $event, $routeInfo->getName().'_error', $exception);
165
        }
166 9
    }
167
168
    /**
169
     * Event Manager trigger with exception
170
     *
171
     * @param EventManagerInterface $eventManager
172
     * @param EventInterface $event
173
     * @param string $name
174
     * @param Exception $exception
175
     *
176
     * @return EventInterface
177
     */
178 4
    private function triggerWithException(
179
        EventManagerInterface $eventManager,
180
        EventInterface $event,
181
        $name,
182
        Exception $exception
183
    ) {
184 4
        $event->setName($name);
185 4
        $event->setException($exception);
186 4
        $eventManager->trigger($event);
187
188 3
        return $event;
189
    }
190
}
191