Completed
Push — master ( 3830bc...2c9d17 )
by Samuel
02:31
created

Api::run()   B

Complexity

Conditions 5
Paths 4

Size

Total Lines 26
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 5.0061

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 26
ccs 15
cts 16
cp 0.9375
rs 8.439
cc 5
eloc 16
nc 4
nop 1
crap 5.0061
1
<?php
2
3
namespace Kelemen\ApiNette;
4
5
use Kelemen\ApiNette\Exception\UnresolvedHandlerException;
6
use Kelemen\ApiNette\Exception\UnresolvedRouteException;
7
use Kelemen\ApiNette\Exception\ValidationFailedException;
8
use Kelemen\ApiNette\Route\RouteResolverInterface;
9
use Kelemen\ApiNette\Route\Route;
10
use Kelemen\ApiNette\Route\RouteContainer;
11
use Kelemen\ApiNette\Validator\Input\CustomInput;
12
use Kelemen\ApiNette\Validator\Validator;
13
use Kelemen\ApiNette\Validator\ValidatorInterface;
14
use Nette\Application\IResponse;
15
use Nette\DI\Container;
16
use Nette\DI\MissingServiceException;
17
use Nette\Http\Request;
18
use Nette\Http\Response;
19
20
class Api
21
{
22
    /** @var RouteResolverInterface */
23
    private $routeResolver;
24
25
    /** @var RouteContainer */
26
    private $routes;
27
28
    /** @var Request */
29
    private $request;
30
31
    /** @var Response */
32
    private $response;
33
34
    /** @var Container */
35
    private $container;
36
37
    /** @var ValidatorInterface */
38
    private $validator;
39
40
    /**
41
     * @param RouteResolverInterface $routeResolver
42
     * @param Request $request
43
     * @param Response $response
44
     * @param Container $container
45
     * @param ValidatorInterface $validator
46
     */
47 12
    public function __construct(
48
        RouteResolverInterface $routeResolver,
49 1
        Request $request,
50
        Response $response,
51
        Container $container,
52
        ValidatorInterface $validator = null
53
    ) {
54 12
        $this->routeResolver = $routeResolver;
55 12
        $this->request = $request;
56 12
        $this->response = $response;
57 12
        $this->container = $container;
58 12
        $this->validator = $validator ?: new Validator();
59 12
        $this->routes = new RouteContainer();
60 12
    }
61
62
    /**
63
     * Add api call
64
     * @param string $method
65
     * @param string $pattern
66
     * @param string $handler
67
     * @param array $params
68
     */
69 12
    public function add($method, $pattern, $handler, $params = [])
70
    {
71 12
        $this->routes->add(new Route($method, $pattern, $handler, $params));
72 12
    }
73
74
    /**
75
     * Add get api call
76
     * @param string $pattern
77
     * @param string $handler
78
     * @param array $params
79
     */
80 10
    public function get($pattern, $handler, $params = [])
81
    {
82 10
        $this->add('get', $pattern, $handler, $params);
83 10
    }
84
85
    /**
86
     * Add post api call
87
     * @param string $pattern
88
     * @param string $handler
89
     * @param array $params
90
     */
91 2
    public function post($pattern, $handler, $params = [])
92
    {
93 2
        $this->add('post', $pattern, $handler, $params);
94 2
    }
95
96
    /**
97
     * Add put api call
98
     * @param string $pattern
99
     * @param string $handler
100
     * @param array $params
101
     */
102
    public function put($pattern, $handler, $params = [])
103
    {
104
        $this->add('put', $pattern, $handler, $params);
105
    }
106
107
    /**
108
     * Add patch api call
109
     * @param string $pattern
110
     * @param string $handler
111
     * @param array $params
112
     */
113
    public function patch($pattern, $handler, $params = [])
114
    {
115
        $this->add('patch', $pattern, $handler, $params);
116
    }
117
118
    /**
119
     * Add delete api call
120
     * @param string $pattern
121
     * @param string $handler
122
     * @param array $params
123
     */
124
    public function delete($pattern, $handler, $params = [])
125
    {
126
        $this->add('delete', $pattern, $handler, $params);
127
    }
128
129
    /**
130
     * Add options api call
131
     * @param string $pattern
132
     * @param string $handler
133
     * @param array $params
134
     */
135
    public function options($pattern, $handler, $params = [])
136
    {
137
        $this->add('options', $pattern, $handler, $params);
138
    }
139
140
    /**
141
     * @param string $url
142
     * @return IResponse
143
     * @throws UnresolvedHandlerException
144
     * @throws UnresolvedRouteException
145
     * @throws ValidationFailedException
146
     */
147 12
    public function run($url)
148
    {
149 12
        $resolvedRoute = $this->routeResolver->resolve($this->routes, $url);
150 12
        if (!$resolvedRoute) {
151 2
            throw new UnresolvedRouteException();
152
        }
153
154 10
        $handler = $this->getFromContainer($resolvedRoute->getRoute()->getHandler());
155 10
        if (!$handler) {
156 4
            throw new UnresolvedHandlerException('Handler ' . $resolvedRoute->getRoute()->getHandler() . ' not found in container');
157
        }
158
159 6
        $this->validator->setInput('path', new CustomInput($resolvedRoute->getParams()));
160 6
        $this->validator->validate($handler->validate());
161
162 6
        if (!$this->validator->isValid()) {
163 2
            throw new ValidationFailedException($this->validator);
164
        }
165
166 4
        $handler->setValidatedValues($this->validator->getValues());
167
168 4
        $middleware = $resolvedRoute->getRoute()->getConfig('middleware');
169 4
        $runner = new Runner($middleware ?: [], $handler, $this->container);
170 4
        $response = $runner($this->request, $this->response);
171
        return $response;
172
    }
173
174
    /**
175
     * Get service by type or name from container
176
     * @param string $entry
177
     * @return bool|object
178
     */
179 10 View Code Duplication
    private function getFromContainer($entry)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
180
    {
181
        try {
182 10
            if (substr($entry, 0, 1) === '#') {
183 10
                return $this->container->getService(substr($entry, 1));
184
            }
185
186
            return $this->container->getByType($entry);
187 4
        } catch (MissingServiceException $e) {
188 4
            return false;
189
        }
190
    }
191
}
192