Test Failed
Push — master ( f8889b...b2d9fd )
by Sergio
02:58
created

TestDocGenerator::mergeRequestBodiesToEndpoint()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 24
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 18
nc 2
nop 2
dl 0
loc 24
rs 9.6666
c 0
b 0
f 0
1
<?php
2
/**
3
 * Created by PhpStorm.
4
 * User: sergio.rodenas
5
 * Date: 2019-02-12
6
 * Time: 10:44
7
 */
8
9
namespace Rodenastyle\TestDoc;
10
11
use Illuminate\Http\Request;
0 ignored issues
show
Bug introduced by
The type Illuminate\Http\Request was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
12
13
class TestDocGenerator
14
{
15
	private $specification = [];
16
17
	public function registerEndpoint(Request $request, $response) : void
18
	{
19
		$this->loadCurrentSpecification();
20
		$this->registerDefaults();
21
22
		$this->addOrUpdateEndpoint($request, $response);
23
	}
24
25
	private function loadCurrentSpecification() : void
26
	{
27
		$this->specification = json_decode(
28
			@file_get_contents(base_path('public/docs/specification.json')) ?: "",
0 ignored issues
show
Bug introduced by
The function base_path was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

28
			@file_get_contents(/** @scrutinizer ignore-call */ base_path('public/docs/specification.json')) ?: "",
Loading history...
29
			true
30
		);
31
	}
32
33
	private function registerDefaults() : void
34
	{
35
		$this->specification['openapi'] = '3.0.0';
36
		$this->specification['components']['securitySchemes']['bearerAuth'] = [
37
			'type' => 'http',
38
			'scheme' => 'bearer',
39
			'bearerFormat' => 'JWT'
40
		];
41
	}
42
43
	private function addOrUpdateEndpoint(Request $request, $response): void
44
	{
45
		if($this->endpointExistsOnSpecification($request)){
46
			$this->updateSpecificationEndpoint($request, $response);
47
		} else {
48
			$this->addSpecificationEndpoint($request, $response);
49
		}
50
	}
51
52
	private function endpointExistsOnSpecification(Request $request):bool{
53
		return isset($this->specification['paths']
54
			[$this->getInternalRouteDeclaredFormat($request)]
55
			[$this->getRouteMethodForSpecification($request)]);
56
	}
57
58
	private function addSpecificationEndpoint(Request $request, $response){
59
		//TODO: Config
60
		if(str_contains($this->getInternalRouteDeclaredFormat($request), 'internal')) return;
61
62
		$this->specification['paths']
63
		[$this->getInternalRouteDeclaredFormat($request)]
64
		[$this->getRouteMethodForSpecification($request)] = [
65
			'responses' => [
66
				'200' => [
67
					'description' => ''
68
				]
69
			],
70
			'security' => $this->getOperationSecurity($request),
71
			'tags' => [
72
				ucfirst($this->getRouteSpecificationGroup($request))
73
			]
74
		];
75
76
		$this->updateSpecificationEndpoint($request, $response);
77
	}
78
79
	private function updateSpecificationEndpoint(Request $request, $response){
80
		$this->mergeResponseToEndpoint($request, $response);
81
82
		if(in_array($this->getRouteMethodForSpecification($request), ['post', 'patch', 'delete'])){
83
			$this->mergeRequestBodiesToEndpoint($request, $response);
84
		} else {
85
			$this->mergeParamsToEndpoint($request, $response);
86
		}
87
88
		$this->saveSpecification();
89
	}
90
91
	private function mergeResponseToEndpoint(Request $request, $response){
92
		$this->specification['paths']
93
		[$this->getInternalRouteDeclaredFormat($request)]
94
		[$this->getRouteMethodForSpecification($request)]
95
		['responses']
96
		[$response->getStatusCode()] = [
97
			'description' => '',
98
			'content' => [
99
				'application/json' => [
100
					'schema' => [
101
						'type' => 'string',
102
						'example' => $response->getContent()
103
					]
104
				]
105
			]
106
		];
107
	}
108
109
	private function mergeParamsToEndpoint(Request $request, $response){
0 ignored issues
show
Unused Code introduced by
The parameter $response is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

109
	private function mergeParamsToEndpoint(Request $request, /** @scrutinizer ignore-unused */ $response){

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

Loading history...
110
		collect($request->query->all())->keys()->each(function($param)use($request){
111
			$this->specification['paths']
112
			[$this->getInternalRouteDeclaredFormat($request)]
113
			[$this->getRouteMethodForSpecification($request)]
114
			['parameters'][] = [
115
				'in' => 'query',
116
				'name' => $param,
117
				'schema' => ['type' => 'string']
118
			];
119
		});
120
	}
121
122
	private function mergeRequestBodiesToEndpoint(Request $request, $response){
0 ignored issues
show
Unused Code introduced by
The parameter $response is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

122
	private function mergeRequestBodiesToEndpoint(Request $request, /** @scrutinizer ignore-unused */ $response){

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

Loading history...
123
		if( ! isset($this->specification['paths']
124
			[$this->getInternalRouteDeclaredFormat($request)]
125
			[$this->getRouteMethodForSpecification($request)]
126
			['requestBody'])){
127
128
			$this->specification['paths']
129
			[$this->getInternalRouteDeclaredFormat($request)]
130
			[$this->getRouteMethodForSpecification($request)]
131
			['requestBody']['content']['application/json'] = [
132
				'schema' => [
133
					'type' => 'object',
134
					'properties' => []
135
				],
136
				'required' => false
137
			];
138
		}
139
140
		collect($request->json()->all())->keys()->each(function($bodyKey)use($request){
141
			$this->specification['paths']
142
			[$this->getInternalRouteDeclaredFormat($request)]
143
			[$this->getRouteMethodForSpecification($request)]
144
			['requestBody']['content']['application/json']['schema']['properties'][$bodyKey] = [
145
				'type' => 'string'
146
			];
147
		});
148
	}
149
150
	private function getRouteMethodForSpecification(Request $request){
151
		return strtolower($request->getMethod());
152
	}
153
154
	private function getInternalRoute(Request $request){
155
		if( ! isset($request->route()[1]['as'])) return null;
156
		return route($request->route()[1]['as']);
0 ignored issues
show
Bug introduced by
The function route was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

156
		return /** @scrutinizer ignore-call */ route($request->route()[1]['as']);
Loading history...
157
	}
158
159
	private function getInternalRouteDeclaredFormat(Request $request){
160
		$uri = parse_url($this->getInternalRoute($request) ?: $request->getRequestUri());
161
		return $uri['path'];
162
	}
163
164
	private function getRouteSpecificationGroup(Request $request){
165
		return $this->getRouteSpecificationGroupByRouteName($request) ?:
166
			$this->getRouteSpecificationGroupByRequestUri($request);
167
	}
168
169
	private function getRouteSpecificationGroupByRouteName(Request $request){
170
		if( ! isset($request->route()[1]['as'])) return null;
171
172
		$internalRoute = $request->route()[1]['as'];
173
		$tag = explode('.', $internalRoute);
174
175
		return $tag[count($tag) - 2];
176
	}
177
178
	private function getRouteSpecificationGroupByRequestUri(Request $request){
0 ignored issues
show
Unused Code introduced by
The parameter $request is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

178
	private function getRouteSpecificationGroupByRequestUri(/** @scrutinizer ignore-unused */ Request $request){

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

Loading history...
179
		return "other";
180
	}
181
182
	private function saveSpecification() : void{
183
		file_put_contents(base_path('public/docs/specification.json'), json_encode($this->specification));
0 ignored issues
show
Bug introduced by
The function base_path was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

183
		file_put_contents(/** @scrutinizer ignore-call */ base_path('public/docs/specification.json'), json_encode($this->specification));
Loading history...
184
	}
185
186
	private function getOperationSecurity(Request $request) : array{
187
		return (
188
			isset($request->route()[1]['middleware']) &&
189
			in_array('auth', $request->route()[1]['middleware'], true)
190
		) ? ['bearerAuth' => []] : [];
191
	}
192
}