Completed
Pull Request — master (#138)
by Abdul Malik
02:24
created

App::run()   A

Complexity

Conditions 2
Paths 3

Size

Total Lines 18
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 2

Importance

Changes 9
Bugs 0 Features 2
Metric Value
c 9
b 0
f 2
dl 0
loc 18
ccs 11
cts 11
cp 1
rs 9.4286
cc 2
eloc 12
nc 3
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 36
    public function __construct(ContainerInterface $container = null)
30
    {
31 36
        if ($container === null) {
32 4
            $container = Container\PHPDiFactory::buildContainer(Loader::load());
33 2
        }
34
35 36
        if ($container->has('router') === false) {
36 2
            throw new Exception('Define router config');
37
        }
38
39 36
        $this->container = $container;
40 36
    }
41
42
    /**
43
     * Container getter.
44
     *
45
     * @return ContainerInterface
46
     */
47 36
    public function getContainer()
48
    {
49 36
        return $this->container;
50
    }
51
52
    /**
53
     * Penny dispatcher getter.
54
     *
55
     * @return Dispatcher
56
     */
57 30
    private function getDispatcher()
58
    {
59 30
        $dispatcher = $this->container->get('dispatcher');
60 30
        if (!is_callable($dispatcher)) {
61 2
            throw new \RuntimeException('Dispatcher must be a callable');
62
        }
63
64 28
        return $dispatcher;
65
    }
66
67
    /**
68
     * Penny HTTP flow event getter.
69
     *
70
     * @return PennyEvmInterface
71
     */
72 28
    private function getEventManager()
73
    {
74 28
        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 32
    private function setUpEventWithRequestResponse($request, $response)
88
    {
89 32
        $event = $this->getContainer()->get('http_flow_event');
90 32
        if (!$event instanceof PennyEventInterface) {
91 2
            throw new RuntimeException('This event did not supported');
92
        }
93
94 30
        if ($request !== null) {
95 30
            $event->setRequest($request);
96 15
        }
97 30
        if ($response !== null) {
98 30
            $event->setResponse($response);
99 15
        }
100
101 30
        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 32
    public function run($request = null, $response = null)
115
    {
116 32
        $event = $this->setUpEventWithRequestResponse($request, $response);
117
118 30
        $dispatcher   = $this->getDispatcher();
119 28
        $eventManager = $this->getEventManager();
120
121
        try {
122 28
            $routeInfo = $dispatcher($event->getRequest());
123 22
            $this->handleRoute($routeInfo, $dispatcher, $eventManager, $event);
0 ignored issues
show
Documentation introduced by
$dispatcher is of type callable, but the function expects a object<Penny\Dispatcher>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
124 18
        } catch (Exception $exception) {
125 7
            return $this->triggerWithException($eventManager, $event, 'dispatch_error', $exception)
126 7
                        ->getResponse();
127
        }
128 20
        $this->handleResponse($eventManager, $event, $routeInfo);
129
130 18
        return $event->getResponse();
131
    }
132
133
    /**
134
     * Handle Route.
135
     *
136
     * @param RouteInfoInterface $routeInfo
137
     * @param Dispatcher $dispatcher
138
     * @param PennyEvmInterface $eventManager
139
     * @param PennyEventInterface $event
140
     *
141
     * @throws RuntimeException if dispatch does not return RouteInfo object.
142
     */
143 20
    private function handleRoute(
144 1
        RouteInfoInterface $routeInfo,
145
        Dispatcher $dispatcher,
0 ignored issues
show
Unused Code introduced by
The parameter $dispatcher is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
146
        PennyEvmInterface $eventManager,
0 ignored issues
show
Unused Code introduced by
The parameter $eventManager is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
147
        PennyEventInterface $event
148
    ) {
149 20
        if (!$routeInfo instanceof RouteInfoInterface) {
150
            throw new RuntimeException('Dispatch does not return RouteInfo object');
151
        }
152
153 20
        $event->setRouteInfo($routeInfo);
154 20
        $event->setName($routeInfo->getName());
155 20
    }
156
157
    /**
158
     * Handle Response.
159
     *
160
     * @param PennyEvmInterface $eventManager
161
     * @param PennyEventInterface $event
162
     * @param RouteInfoInterface $routeInfo
163
     */
164
    private function handleResponse(
165
        PennyEvmInterface $eventManager,
166
        PennyEventInterface $event,
167
        RouteInfoInterface $routeInfo
168
    ) {
169 20
        $eventManager->attach($event->getName(), function ($event) use ($routeInfo) {
170 18
            $event->setResponse(call_user_func_array(
171 18
                $routeInfo->getCallable(),
172 18
                [$event->getRequest(), $event->getResponse()] + $routeInfo->getParams()
173 9
            ));
174 20
        }, 0);
175
176
        try {
177 20
            $eventManager->trigger($event);
178 11
        } catch (Exception $exception) {
179 2
            $this->triggerWithException($eventManager, $event, $routeInfo->getName().'_error', $exception);
180
        }
181 18
    }
182
183
    /**
184
     * Event Manager trigger with exception
185
     *
186
     * @param PennyEvmInterface $eventManager
187
     * @param PennyEventInterface $event
188
     * @param string $name
189
     * @param Exception $exception
190
     *
191
     * @return PennyEventInterface
192
     */
193 9
    private function triggerWithException(
194
        PennyEvmInterface $eventManager,
195
        PennyEventInterface $event,
196
        $name,
197
        Exception $exception
198
    ) {
199 9
        $event->setName($name);
200 9
        $event->setException($exception);
201 9
        $eventManager->trigger($event);
202
203 7
        return $event;
204
    }
205
}
206