Completed
Pull Request — develop (#575)
by
unknown
102:40 queued 37:52
created

ApiService::findMatchedService()   C

Complexity

Conditions 12
Paths 29

Size

Total Lines 54
Code Lines 32

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 54
rs 6.7848
c 0
b 0
f 0
cc 12
eloc 32
nc 29
nop 2

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * Created by PhpStorm.
4
 * User: taachja1
5
 * Date: 04.04.17
6
 * Time: 09:50
7
 */
8
9
namespace Graviton\ApiBundle\Service;
10
11
12
use Graviton\ApiBundle\Manager\DatabaseManager;
13
use Graviton\ExceptionBundle\Exception\NotFoundException;
14
use Graviton\JsonSchemaBundle\Validator\InvalidJsonException;
15
use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
16
use Symfony\Component\HttpFoundation\RequestStack;
17
18
class ApiService
19
{
20
    /** @var string Where services are located */
21
    protected $dirService;
22
23
    /** @var string Where we will cache definitions trees */
24
    protected $dirCache;
25
26
    /** @var DatabaseManager */
27
    protected $dbManager;
28
29
    /** @var SchemaService Schema Definition */
30
    private $schemaService;
31
32
    /** @var ConfigService Config Definition */
33
    private $configService;
34
35
    /** @var MappingService Config Definition */
36
    private $mappingService;
37
38
    /** @var RequestStack */
39
    protected $requestStack;
40
41
    /** @var string Host and Schema */
42
    private $baseUri;
43
44
    /** @var string Service Definition */
45
    private $requestedService;
46
47
    /** @var string Requested class id */
48
    private $classId;
49
50
    /** @var string Requested collection id */
51
    private $collectionId;
52
53
54
    public function __construct(
55
        RequestStack $requestStack,
56
        ConfigService $configService,
57
        SchemaService $schemaService,
58
        MappingService $mappingService,
59
        DatabaseManager $dbManager
60
    )
61
    {
0 ignored issues
show
Coding Style introduced by
The closing parenthesis and the opening brace of a multi-line function declaration must be on the same line
Loading history...
62
        $this->requestStack = $requestStack;
63
        $this->schemaService = $schemaService;
64
        $this->configService = $configService;
65
        $this->mappingService = $mappingService;
66
        $this->dbManager = $dbManager;
67
        $this->init();
68
    }
69
70
    /**
71
     * Staring the needed params.
72
     */
73
    private function init()
74
    {
75
        $request = $this->requestStack->getMasterRequest();
76
        $this->baseUri = $request->getSchemeAndHttpHost() . $request->getPathInfo();
77
        $this->requestedService = $request->get('service');
78
79
        $this->extractServiceRequest();
80
    }
81
82
    public function getRoutes()
83
    {
84
        $routes = $this->configService->getJsonFromFile('routes.json');
85
86
        // Remove trailing slash
87
        $baseUri = rtrim($this->baseUri, '/');
88
        $services = [];
89
90
        foreach ($routes as $route) {
91
            $services[] = [
92
                '$ref' => $baseUri . '/' . $route,
93
                'profile' => $baseUri . '/schema/' . $route . '/collection'
94
            ];
95
        }
96
97
98
        return ['services' => $services];
99
    }
100
101
    public function getSchema()
102
    {
103
        return $this->schemaService->getSchema($this->classId);
104
    }
105
106
    public function getData()
107
    {
108
        $schema = $this->getSchema();
109
        if ($this->collectionId) {
110
            $data = $this->dbManager->findOne($schema->{'x-documentClass'}, $this->collectionId);
111
            if (!$data) {
112
                throw new NotFoundException('Entry with id not found!');
113
            }
114
        } else {
115
            $data = $this->dbManager->findAll($schema->{'x-documentClass'});
116
        }
117
        return $this->mappingService->mapData($data, $schema);
118
    }
119
120
    /**
121
     * Will extract and set variables for
122
     *
123
     * @param string $requestService Requested service call
0 ignored issues
show
Bug introduced by
There is no parameter named $requestService. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
124
     */
125
    private function extractServiceRequest()
126
    {
127
        if (!$this->requestedService) {
128
            return;
129
        }
130
        $requestService = trim($this->requestedService, "/");
131
        $routes = $this->configService->getJsonFromFile('routes.json');
132
        $matchedRoute = $this->findMatchedService($requestService, $routes);
133
134
        $serviceRoute = reset($matchedRoute);
135
        $serviceId = (array_keys($matchedRoute));
136
137
        if ($id = substr($requestService, strlen($serviceRoute))) {
138
            $this->collectionId = trim($id, '/');
139
        }
140
141
        $this->classId = $serviceId[0];
0 ignored issues
show
Documentation Bug introduced by
It seems like $serviceId[0] can also be of type integer. However, the property $classId is declared as type string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
142
    }
143
144
    /**
145
     * Will return the must accurate requested Service match.
146
     * request service may be:
147
     * foo
148
     * foo/bar
149
     * foo/bar/one
150
     * for/bar/two
151
     * for/{id}
152
     * for/bar/{id}
153
     * for/bar/one/{id}
154
     *
155
     * @param $requestService
156
     * @param $routes
157
     * @return array
158
     */
159
    private function findMatchedService($requestService, $routes)
160
    {
161
        $matched = [];
162
        $routes = (array) $routes;
163
        $match = array_search($requestService, $routes);
164
165
        // Fast matching return
166
        if ($match && strlen($routes[$match]) === strlen($requestService)) {
167
            $matched[$match] = $requestService;
168
            return $matched;
169
        }
170
171
        // When id is given in request
172
        foreach ($routes as $serviceId => $route) {
173
            if ($this->startsWith($route, $requestService)) {
174
                $matched[$serviceId] = $route;
175
            } elseif ($this->startsWith($requestService, $route)) {
176
                $matched[$serviceId] = $route;
177
            }
178
        }
179
180
        // Some routes have same start, but we do not control definition load
181
        if (count($matched) > 1) {
182
            $score = [];
183
            foreach ($matched as $serviceId => $route) {
184
                if (strpos($requestService, $route) !== false) {
185
                    $sbResult = substr($requestService, strlen($route));
186
                    $score[strlen($sbResult)] = $serviceId;
187
                }
188
            }
189
            if (!empty($score)) {
190
                ksort($score);
191
                $score = reset($score);
192
                $matched = [$score => $matched[$score]];
193
            } else {
194
                throw new NotFoundException(
195
                    sprintf('Sorry, no route matched. Did you mean: %s', implode(', ', $matched))
196
                );
197
            }
198
        }
199
200
        // Can happen we match a route that's incomplete
201
        $matchedUrl = reset($matched);
202
        if (strlen($matchedUrl) > strlen($requestService)) {
203
            throw new NotFoundException(
204
                sprintf('Sorry, no route matched. Did you mean: %s', $matchedUrl)
205
            );
206
        }
207
208
        if (empty($matched)) {
209
            throw new NotFoundException('Service not found with given url');
210
        }
211
        return $matched;
212
    }
213
214
    /**
215
     * @param $haystack
216
     * @param $needle
217
     * @return bool
218
     */
219
    private function startsWith($haystack, $needle)
0 ignored issues
show
Coding Style introduced by
function startsWith() does not seem to conform to the naming convention (^(?:is|has|should|may|supports)).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
220
    {
221
        $length = strlen($needle);
222
        return (substr($haystack, 0, $length) === $needle);
223
    }
224
225
}