App   A
last analyzed

Complexity

Total Complexity 18

Size/Duplication

Total Lines 190
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 6

Test Coverage

Coverage 100%

Importance

Changes 20
Bugs 5 Features 3
Metric Value
wmc 18
c 20
b 5
f 3
lcom 1
cbo 6
dl 0
loc 190
ccs 63
cts 63
cp 1
rs 10

9 Methods

Rating   Name   Duplication   Size   Complexity  
A getContainer() 0 4 1
A getEventManager() 0 4 1
A setUpEventWithRequestResponse() 0 16 4
A __construct() 0 12 3
A getDispatcher() 0 9 2
A run() 0 20 2
A handleRoute() 0 9 2
A handleResponse() 0 19 2
A triggerWithException() 0 12 1
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 2
        }
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 17
    public function getContainer()
48
    {
49 17
        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
64 15
        return $dispatcher;
65
    }
66
67
    /**
68
     * Penny HTTP flow event getter.
69
     *
70
     * @return EventManagerInterface
71
     */
72 15
    private function getEventManager()
73
    {
74 15
        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 17
    private function setUpEventWithRequestResponse($request, $response)
88
    {
89 17
        $event = $this->container->get('http_flow_event');
90 17
        if (!$event instanceof EventInterface) {
91 1
            throw new RuntimeException('This event did not supported');
92
        }
93
94 16
        if ($request !== null) {
95 15
            $event->setRequest($request);
96 15
        }
97 16
        if ($response !== null) {
98 15
            $event->setResponse($response);
99 15
        }
100
101 16
        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 17
    public function run($request = null, $response = null)
115
    {
116 17
        $event = $this->setUpEventWithRequestResponse($request, $response);
117
118 16
        $dispatcher   = $this->getDispatcher();
119 15
        $eventManager = $this->getEventManager();
120
121 15
        $eventManager->trigger($event);
122
123
        try {
124 15
            $routeInfo = call_user_func($dispatcher, $event->getRequest());
125 12
            $this->handleRoute($routeInfo, $event);
126 15
        } catch (Exception $exception) {
127 4
            return $this->triggerWithException($eventManager, $event, 'dispatch_error', $exception)
128 4
                        ->getResponse();
129
        }
130 11
        $this->handleResponse($eventManager, $event, $routeInfo);
131
132 10
        return $event->getResponse();
133
    }
134
135
    /**
136
     * Handle Route.
137
     *
138
     * @param mixed $routeInfo
139
     * @param EventInterface $event
140
     *
141
     * @throws RuntimeException if dispatch does not return RouteInfo object.
142
     */
143 12
    private function handleRoute($routeInfo, EventInterface $event)
144
    {
145 12
        if (!$routeInfo instanceof RouteInfoInterface) {
146 1
            throw new RuntimeException('Dispatch does not return RouteInfo object');
147
        }
148
149 11
        $event->setRouteInfo($routeInfo);
150 11
        $event->setName($routeInfo->getName());
151 11
    }
152
153
    /**
154
     * Handle Response.
155
     *
156
     * @param EventManagerInterface $eventManager
157
     * @param EventInterface $event
158
     * @param RouteInfoInterface $routeInfo
159
     */
160 11
    private function handleResponse(
161
        EventManagerInterface $eventManager,
162
        EventInterface $event,
163
        RouteInfoInterface $routeInfo
164
    ) {
165 11
        $eventName = $event->getName();
166 11
        $eventManager->attach($eventName, function ($event) use ($routeInfo) {
167 10
            $event->setResponse(call_user_func_array(
168 10
                $routeInfo->getCallable(),
169 10
                [$event->getRequest(), $event->getResponse()] + $routeInfo->getParams()
170 10
            ));
171 11
        }, 0);
172
173
        try {
174 11
            $eventManager->trigger($event);
175 11
        } catch (Exception $exception) {
176 1
            $this->triggerWithException($eventManager, $event, $eventName.'_error', $exception);
177
        }
178 10
    }
179
180
    /**
181
     * Event Manager trigger with exception
182
     *
183
     * @param EventManagerInterface $eventManager
184
     * @param EventInterface $event
185
     * @param string $name
186
     * @param Exception $exception
187
     *
188
     * @return EventInterface
189
     */
190 5
    private function triggerWithException(
191
        EventManagerInterface $eventManager,
192
        EventInterface $event,
193
        $name,
194
        Exception $exception
195
    ) {
196 5
        $event->setName($name);
197 5
        $event->setException($exception);
198 5
        $eventManager->trigger($event);
199
200 4
        return $event;
201
    }
202
}
203