Completed
Push — master ( da62ab...2e0a22 )
by Thomas
09:51
created

generateToOneRelationshipAction()   B

Complexity

Conditions 2
Paths 2

Size

Total Lines 96
Code Lines 36

Duplication

Lines 23
Ratio 23.96 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 23
loc 96
ccs 0
cts 62
cp 0
rs 8.3859
cc 2
eloc 36
nc 2
nop 3
crap 6

How to fix   Long Method   

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
namespace keeko\tools\command;
3
4
use gossi\codegen\model\PhpClass;
5
use gossi\codegen\model\PhpMethod;
6
use gossi\swagger\collections\Definitions;
7
use gossi\swagger\collections\Paths;
8
use gossi\swagger\Swagger;
9
use keeko\core\schema\ActionSchema;
10
use keeko\tools\command\AbstractGenerateCommand;
11
use keeko\tools\generator\action\ToManyRelationshipAddActionGenerator;
12
use keeko\tools\generator\action\ToManyRelationshipReadActionGenerator;
13 20
use keeko\tools\generator\action\ToManyRelationshipRemoveActionGenerator;
14 20
use keeko\tools\generator\action\ToManyRelationshipUpdateActionGenerator;
15 20
use keeko\tools\generator\action\ToOneRelationshipReadActionGenerator;
16 20
use keeko\tools\generator\action\ToOneRelationshipUpdateActionGenerator;
17
use keeko\tools\generator\response\ToManyRelationshipJsonResponseGenerator;
18
use keeko\tools\generator\response\ToOneRelationshipJsonResponseGenerator;
19 20
use keeko\tools\utils\NameUtils;
20 20
use phootwork\file\File;
21
use phootwork\lang\Text;
22
use Propel\Generator\Model\ForeignKey;
23
use Propel\Generator\Model\Table;
24
use Symfony\Component\Console\Input\InputInterface;
25
use Symfony\Component\Console\Output\OutputInterface;
26
27
class GenerateApiCommand extends AbstractGenerateCommand {
28
29
	protected function configure() {
30
		$this
31
			->setName('generate:api')
32
			->setDescription('Generates the api for the module')
33
		;
34
		
35
		$this->configureGenerateOptions();
36
			
37
		parent::configure();
38
	}
39
	
40
	/**
41
	 * Checks whether api can be generated at all by reading composer.json and verify
42
	 * all required information are available
43
	 */
44
	private function preCheck() {
45
		$module = $this->packageService->getModule();
46
		if ($module === null) {
47
			throw new \DomainException('No module definition found in composer.json - please run `keeko init`.');
48
		}
49
	}
50
51
	protected function execute(InputInterface $input, OutputInterface $output) {
52
		$this->preCheck();
53
		
54
		// prepare models ?
55
		$this->prepareModels();
56
		
57
		// generate relationship actions
58
		$this->generateRelationshipActions();
59
		
60
		// generate api
61
		$api = new File($this->project->getApiFileName());
62
		
63
		// if generation is forced, generate new API from scratch
64
		if ($input->getOption('force')) {
65
			$swagger = new Swagger();
66
		}
67
		
68
		// ... anyway reuse existing one
69
		else {
70
			if (!$api->exists()) {
71
				$api->write('{}');
72
			}
73
			
74
			$swagger = Swagger::fromFile($this->project->getApiFileName());
75
		}
76
77
		$swagger->setVersion('2.0');
78
		$this->generatePaths($swagger);
79
		$this->generateDefinitions($swagger);
80
		
81
		$this->jsonService->write($api->getPathname(), $swagger->toArray());
82
		$this->io->writeln(sprintf('API for <info>%s</info> written at <info>%s</info>', $this->package->getFullName(), $api->getPathname()));
83
	}
84
	
85
	/**
86
	 * Adds the APIModelInterface to package models
87
	 * 
88
	 */
89
	protected function prepareModels() {
90
		$models = $this->modelService->getPackageModelNames();
91
		
92
		foreach ($models as $modelName) {
93
			$tableName = $this->modelService->getTableName($modelName);
94
			$model = $this->modelService->getModel($tableName);
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 5 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
95
			$class = new PhpClass(str_replace('\\\\', '\\', $model->getNamespace() . '\\' . $model->getPhpName()));
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 5 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
96
			$file = new File($this->codegenService->getFilename($class));
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 6 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
97
			
98
			if ($file->exists()) {
99
				$class = PhpClass::fromFile($this->codegenService->getFilename($class));
100
				if (!$class->hasInterface('APIModelInterface')) {
101
					$class->addUseStatement('keeko\\core\\model\\types\\APIModelInterface');
102
					$class->addInterface('APIModelInterface');
103
// 					$typeName =  $this->package->getCanonicalName() . '.' . NameUtils::dasherize($modelName);
0 ignored issues
show
Unused Code Comprehensibility introduced by
52% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
104
// 					$class->setMethod(PhpMethod::create('getAPIType')
105
// 						->setBody('return \''.$typeName . '\';')
106
// 					);
107
	
108
					$this->codegenService->dumpStruct($class, true);
109
				}
110
			}
111
		}
112
	}
113
114
	protected function generateRelationshipActions() {
115
		$models = $this->modelService->getPackageModelNames();
116
		
117
		foreach ($models as $modelName) {
118
			$model = $this->modelService->getModel($modelName);
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 9 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
119
			$relationships = $this->getRelationships($model);
1 ignored issue
show
Bug introduced by
It seems like $model defined by $this->modelService->getModel($modelName) on line 118 can be null; however, keeko\tools\command\Gene...and::getRelationships() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
120
			
121
			// to-one relationships
122
			foreach ($relationships['one'] as $one) {
123
				$fk = $one['fk'];
124
				$this->generateToOneRelationshipAction($model, $fk->getForeignTable(), $fk);
1 ignored issue
show
Bug introduced by
It seems like $model defined by $this->modelService->getModel($modelName) on line 118 can be null; however, keeko\tools\command\Gene...OneRelationshipAction() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
125
			}
126
		
127
			// to-many relationships
128
			foreach ($relationships['many'] as $many) {
129
				$fk = $many['fk'];
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 2 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
130
				$cfk = $many['cfk'];
131
				$this->generateToManyRelationshipAction($model, $fk->getForeignTable(), $cfk->getMiddleTable());
1 ignored issue
show
Bug introduced by
It seems like $model defined by $this->modelService->getModel($modelName) on line 118 can be null; however, keeko\tools\command\Gene...anyRelationshipAction() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
132
			}
133
		}
134
	}
135
	
136
	protected function getRelationships(Table $model) {
137
		// to-one relationships
138
		$one = [];
139
		$fks = $model->getForeignKeys();
140
		foreach ($fks as $fk) {
141
			$one[] = [
142
				'fk' => $fk
143
			];
144
		}
145
		
146
		// to-many relationships
147
		$many = [];
148
		$cfks = $model->getCrossFks();
149
		foreach ($cfks as $cfk) {
150
			foreach ($cfk->getMiddleTable()->getForeignKeys() as $fk) {
151
				if ($fk->getForeignTable() != $model) {
152
					$many[] = [
153
						'fk' => $fk,
154
						'cfk' => $cfk
155
					];
156
					break;
157
				}
158
			}
159
		}
160
		
161
		return [
162
			'one' => $one,
163
			'many' => $many
164
		];
165
	}
166
167
	protected function generateToOneRelationshipAction(Table $model, Table $foreign, ForeignKey $fk) {
0 ignored issues
show
Unused Code introduced by
The parameter $fk 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...
168
		$module = $this->package->getKeeko()->getModule();
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 11 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
169
		$fkModelName = $foreign->getPhpName();
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 6 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
170
		$actionNamePrefix = sprintf('%s-to-%s-relationship',
171
			NameUtils::dasherize($model->getPhpName()),
172
			NameUtils::dasherize($fkModelName));
173
		$actions = [];
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 10 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
174
		
175
		// response class name
176
		$response = sprintf('%s\\response\\%s%sJsonResponse',
177
			$this->modelService->getRootNamespace(),
178
			$model->getPhpName(),
179
			$fkModelName
180
		);
181
		
182
		$generators = [
183
			'read' => new ToOneRelationshipReadActionGenerator($this->service),
184
			'update' => new ToOneRelationshipUpdateActionGenerator($this->service)
185
		];
186
		$titles = [
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 5 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
187
			'read' => 'Reads the relationship of {model} to {foreign}',
188
			'update' => 'Updates the relationship of {model} to {foreign}'
189
		];
190
		
191 View Code Duplication
		foreach (array_keys($generators) as $type) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
192
			// generate fqcn
193
			$className = sprintf('%s%s%sAction', $model->getPhpName(), $fkModelName, ucfirst($type));
194
			$fqcn = $this->modelService->getRootNamespace() . '\\action\\' . $className;
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 6 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
195
				
196
			// generate action
197
			$action = new ActionSchema($actionNamePrefix . '-' . $type);
198
			$action->addAcl('admin');
199
			$action->setClass($fqcn);
200
			$action->setTitle(str_replace(
201
				['{model}', '{foreign}'],
202
				[$model->getOriginCommonName(), $foreign->getoriginCommonName()],
203
				$titles[$type])
204
			);
205
			$action->setResponse('json', $response);
206
			$module->addAction($action);
207
			$actions[$type] = $action;
208
				
209
			// generate class
210
			$generator = $generators[$type];
211
			$class = $generator->generate(new PhpClass($fqcn), $model, $foreign);
0 ignored issues
show
Bug introduced by
The call to generate() misses a required argument $fk.

This check looks for function calls that miss required arguments.

Loading history...
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 5 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
212
			$this->codegenService->dumpStruct($class, true);
213
		}
214
		
215
		// generate response class
216
		$generator = new ToOneRelationshipJsonResponseGenerator($this->service, $model, $foreign);
217
		$response = $generator->generate($actions['read']);
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 2 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
218
		$this->codegenService->dumpStruct($response, true);
219
220
// 		// generate read action
0 ignored issues
show
Unused Code Comprehensibility introduced by
55% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
221
// 		$className = sprintf('%s%sReadAction', $model->getPhpName(), $fkModelName);
222
// 		$fqcn = $this->modelService->getRootNamespace() . '\\action\\' . $className;
223
// 		$responseFqcn = str_replace(['action', 'Action'], ['response', 'JsonResponse'], $fqcn);
224
		
225
// 		$readAction = new ActionSchema($actionNamePrefix . '-read');
0 ignored issues
show
Unused Code Comprehensibility introduced by
61% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
226
// 		$readAction->addAcl('admin');
227
// 		$readAction->setClass($fqcn);
228
// 		$readAction->setTitle(sprintf('Reads the relationship of %s to %s', 
229
// 			$model->getCommonName(), $foreign->getCommonName())
230
// 		);
231
// 		$readAction->setResponse('json', $responseFqcn);
232
// 		$module->addAction($readAction);
233
		
234
// 		// generate read response
0 ignored issues
show
Unused Code Comprehensibility introduced by
57% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
235
// 		$generator = new ToOneRelationshipJsonResponseGenerator($this->service, $foreign);
236
// 		$response = $generator->generate($readAction);
237
// 		$this->codegenService->dumpStruct($response, true);
238
		
239
// 		// generate read class
0 ignored issues
show
Unused Code Comprehensibility introduced by
55% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
240
// 		$class = new PhpClass($fqcn);
241
// 		$generator = new ToOneRelationshipReadActionGenerator($this->service);
242
// 		$class = $generator->generate($class, $model);
243
// 		$this->codegenService->dumpStruct($class, true);
244
		
245
// 		// generate update action
0 ignored issues
show
Unused Code Comprehensibility introduced by
57% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
246
// 		$className = sprintf('%s%sUpdateAction', $model->getPhpName(), $fkModelName);
247
// 		$fqcn = $this->modelService->getRootNamespace() . '\\action\\' . $className;
248
// 		$updateAction = new ActionSchema($actionNamePrefix . '-update');
249
// 		$updateAction->addAcl('admin');
250
// 		$updateAction->setClass($fqcn);
251
// 		$updateAction->setTitle(sprintf('Updates the relationship of %s to %s',
252
// 			$model->getCommonName(), $foreign->getCommonName())
253
// 		);
254
// 		$updateAction->setResponse('json', $responseFqcn);
255
// 		$module->addAction($updateAction);
256
		
257
// 		// generate update class
0 ignored issues
show
Unused Code Comprehensibility introduced by
56% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
258
// 		$class = new PhpClass($fqcn);
259
// 		$generator = new ToOneRelationshipUpdateActionGenerator($this->service);
260
// 		$class = $generator->generate($class, $model, $foreign, $fk);
261
// 		$this->codegenService->dumpStruct($class, true);
262
	}
263
	
264
	protected function generateToManyRelationshipAction(Table $model, Table $foreign, Table $middle) {
265
		$module = $this->package->getKeeko()->getModule();
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 11 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
266
		$fkModelName = $foreign->getPhpName();
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 6 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
267
		$actionNamePrefix = sprintf('%s-to-%s-relationship',
268
			NameUtils::dasherize($model->getPhpName()),
269
			NameUtils::dasherize($fkModelName));
270
		$actions = [];
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 10 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
271
		
272
		// response class name
273
		$response = sprintf('%s\\response\\%s%sJsonResponse', 
274
			$this->modelService->getRootNamespace(),
275
			$model->getPhpName(),
276
			$fkModelName
277
		);
278
279
		$generators = [
280
			'read' => new ToManyRelationshipReadActionGenerator($this->service), 
281
			'update' => new ToManyRelationshipUpdateActionGenerator($this->service), 
282
			'add' => new ToManyRelationshipAddActionGenerator($this->service),
283
			'remove' => new ToManyRelationshipRemoveActionGenerator($this->service)
284
		];
285
		$titles = [
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 5 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
286
			'read' => 'Reads the relationship of {model} to {foreign}',
287
			'update' => 'Updates the relationship of {model} to {foreign}',
288
			'add' => 'Adds {foreign} as relationship to {model}',
289
			'remove' => 'Removes {foreign} as relationship of {model}'
290
		];
291
		
292 View Code Duplication
		foreach (array_keys($generators) as $type) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
293
			// generate fqcn
294
			$className = sprintf('%s%s%sAction', $model->getPhpName(), $fkModelName, ucfirst($type));
295
			$fqcn = $this->modelService->getRootNamespace() . '\\action\\' . $className;
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 6 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
296
			
297
			// generate action
298
			$action = new ActionSchema($actionNamePrefix . '-' . $type);
299
			$action->addAcl('admin');
300
			$action->setClass($fqcn);
301
			$action->setTitle(str_replace(
302
				['{model}', '{foreign}'],
303
				[$model->getOriginCommonName(), $foreign->getoriginCommonName()], 
304
				$titles[$type])
305
			);
306
			$action->setResponse('json', $response);
307
			$module->addAction($action);
308
			$actions[$type] = $action;
309
			
310
			// generate class
311
			$generator = $generators[$type];
312
			$class = $generator->generate(new PhpClass($fqcn), $model, $foreign, $middle);
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 5 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
313
			$this->codegenService->dumpStruct($class, true);
314
		}
315
		
316
		// generate response class
317
		$generator = new ToManyRelationshipJsonResponseGenerator($this->service, $model, $foreign);
318
		$response = $generator->generate($actions['read']);
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 2 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
319
		$this->codegenService->dumpStruct($response, true);
320
	}
321
	
322
	protected function generatePaths(Swagger $swagger) {
323
		$paths = $swagger->getPaths();
324
		
325
		foreach ($this->packageService->getModule()->getActionNames() as $name) {
326
			$this->generateOperation($paths, $name);
327
		}
328
	}
329
	
330
	protected function generateOperation(Paths $paths, $actionName) {
331
		$this->logger->notice('Generating Operation for: ' . $actionName);
332
333
		if (Text::create($actionName)->contains('relationship')) {
334
			$this->generateRelationshipOperation($paths, $actionName);
335
		} else {
336
			$this->generateCRUDOperation($paths, $actionName);
337
		}
338
	}
339
340
	protected function generateRelationshipOperation(Paths $paths, $actionName) {
341
		$this->logger->notice('Generating Relationship Operation for: ' . $actionName);
342
		$prefix = substr($actionName, 0, strrpos($actionName, 'relationship') + 12);
343
		$module = $this->packageService->getModule();
344
345
		// test for to-many relationship:
346
		$many = $module->hasAction($prefix . '-read') 
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 3 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
347
			&& $module->hasAction($prefix . '-update')
348
			&& $module->hasAction($prefix . '-add')
349
			&& $module->hasAction($prefix . '-remove')
350
		;
351
		$single = $module->hasAction($prefix . '-read') 
352
			&& $module->hasAction($prefix . '-update')
353
			&& !$many
354
		;
355
		
356
		if (!$many && !$single) {
357
			$this->io->writeln(sprintf('<comment>Couldn\'t detect whether %s is a to-one or to-many relationship, skin generating endpoints</comment>', $actionName));
358
			return;
359
		}
360
		
361
		// find model names
362
		$modelName = substr($actionName, 0, strpos($actionName, 'to') - 1);
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 8 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
363
		$start = strpos($actionName, 'to') + 3;
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 12 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
364
		$foreignModelName = substr($actionName, $start, strpos($actionName, 'relationship') - 1 - $start);
365
366
		// find relationship objects
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
367
// 		$model = $this->modelService->getModel(NameUtils::toSnakeCase($modelName));
368
// 		$foreignModel = $this->modelService->getModel(NameUtils::toSnakeCase($foreignModelName));
369
// 		$fk = null;
370
// 		foreach ($model->getForeignKeys() as $key) {
371
// 			if ($key->getForeignTable() == $foreignModel) {
372
// 				$fk = $key;
373
// 			}
374
// 		}
375
// 		$fkName = $fk->getLocalColumn()->getName();
376
		
377
		$action = $this->packageService->getAction($actionName);
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 3 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
378
		$type = substr($actionName, strrpos($actionName, '-') + 1);
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 5 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
379
		$method = $this->getMethod($type);
0 ignored issues
show
Unused Code introduced by
$method is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 3 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
380
		$endpoint = '/' . NameUtils::pluralize($modelName) . '/{id}/relationship/' . ($single ?
381
			$foreignModelName : NameUtils::pluralize($foreignModelName));
382
		
383
		$path = $paths->get($endpoint);
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 6 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
384
		$method = $this->getMethod($type);
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 4 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
385
		$operation = $path->getOperation($method);
386
		$operation->setDescription($action->getTitle());
387
		$operation->setOperationId($action->getName());
388
		
389
		$params = $operation->getParameters();
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 4 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
390
		$responses = $operation->getResponses();
391
		
392
		// general model related params
393
		// params
394
		$id = $params->getByName('id');
395
		$id->setIn('path');
396
		$id->setDescription(sprintf('The %s id', $modelName));
397
		$id->setRequired(true);
398
		$id->setType('integer');
399
		
400
		// response
401
		$invalid = $responses->get('400');
402
		$invalid->setDescription('Invalid ID supplied');
403
		
404
		$notfound = $responses->get('404');
405
		$notfound->setDescription(sprintf('No %s found', $modelName));
406
	}
407
	
408
	protected function generateCRUDOperation(Paths $paths, $actionName) {
409
		$this->logger->notice('Generating CRUD Operation for: ' . $actionName);
410
		$database = $this->modelService->getDatabase();
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 2 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
411
		$action = $this->packageService->getAction($actionName);
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 4 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
412
		$modelName = $this->modelService->getModelNameByAction($action);
0 ignored issues
show
Bug introduced by
It seems like $action defined by $this->packageService->getAction($actionName) on line 411 can be null; however, keeko\tools\services\Mod...:getModelNameByAction() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
413
		$tableName = $this->modelService->getTableName($modelName);
414
	
415
		if (!$database->hasTable($tableName)) {
416
			return $paths;
417
		}
418
	
419
		$type = $this->packageService->getActionType($actionName, $modelName);
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 12 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
420
		$modelObjectName = $database->getTable($tableName)->getPhpName();
421
		$modelPluralName = NameUtils::pluralize($modelName);
422
	
423
		// find path branch
424
		switch ($type) {
425
			case 'list':
426
			case 'create':
427
				$endpoint = '/' . $modelPluralName;
428
				break;
429
	
430
			case 'read':
431
			case 'update':
432
			case 'delete':
433
				$endpoint = '/' . $modelPluralName . '/{id}';
434
				break;
435
	
436
			default:
437
				throw new \RuntimeException(sprintf('type (%s) not found, can\'t continue.', $type));
438
				break;
0 ignored issues
show
Unused Code introduced by
break; does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
439
		}
440
441
		$path = $paths->get($endpoint);
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 6 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
442
		$method = $this->getMethod($type);
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 4 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
443
		$operation = $path->getOperation($method);
444
		$operation->setDescription($action->getTitle());
445
		$operation->setOperationId($action->getName());
446
	
447
		$params = $operation->getParameters();
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 4 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
448
		$responses = $operation->getResponses();
449
	
450
		switch ($type) {
451
			case 'list':
452
				$ok = $responses->get('200');
453
				$ok->setDescription(sprintf('Array of %s', $modelPluralName));
454
				$ok->getSchema()->setRef('#/definitions/' . 'Paged' . NameUtils::pluralize($modelObjectName));
455
				break;
456
	
457
			case 'create':
458
				// params
459
				$body = $params->getByName('body');
460
				$body->setName('body');
461
				$body->setIn('body');
462
				$body->setDescription(sprintf('The new %s', $modelName));
463
				$body->setRequired(true);
464
				$body->getSchema()->setRef('#/definitions/Writable' . $modelObjectName);
465
	
466
				// response
467
				$ok = $responses->get('201');
468
				$ok->setDescription(sprintf('%s created', $modelName));
469
				break;
470
	
471 View Code Duplication
			case 'read':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
472
				// response
473
				$ok = $responses->get('200');
474
				$ok->setDescription(sprintf('gets the %s', $modelName));
475
				$ok->getSchema()->setRef('#/definitions/' . $modelObjectName);
476
				break;
477
	
478 View Code Duplication
			case 'update':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
479
				// response
480
				$ok = $responses->get('200');
481
				$ok->setDescription(sprintf('%s updated', $modelName));
482
				$ok->getSchema()->setRef('#/definitions/' . $modelObjectName);
483
				break;
484
	
485
			case 'delete':
486
				// response
487
				$ok = $responses->get('204');
488
				$ok->setDescription(sprintf('%s deleted', $modelName));
489
				break;
490
		}
491
	
492
		if ($type == 'read' || $type == 'update' || $type == 'delete') {
493
			// params
494
			$id = $params->getByName('id');
495
			$id->setIn('path');
496
			$id->setDescription(sprintf('The %s id', $modelName));
497
			$id->setRequired(true);
498
			$id->setType('integer');
499
	
500
			// response
501
			$invalid = $responses->get('400');
502
			$invalid->setDescription('Invalid ID supplied');
503
				
504
			$notfound = $responses->get('404');
505
			$notfound->setDescription(sprintf('No %s found', $modelName));
506
		}
507
	
508
		// response - @TODO Error model
509
	}
510
	
511
	private function getMethod($type) {
512
		$methods = [
513
			'list' => 'GET',
514
			'create' => 'POST',
515
			'read' => 'GET',
516
			'update' => 'PATCH',
517
			'delete' => 'DELETE',
518
			'add' => 'POST',
519
			'remove' => 'DELETE'
520
		];
521
	
522
		return $methods[$type];
523
	}
524
525
	protected function generateDefinitions(Swagger $swagger) {
526
		$definitions = $swagger->getDefinitions();
527
		
528
		// general definitions
529
		$this->generatePagedMeta($definitions);
530
		$this->generateResourceIdentifier($definitions); 
531
532
		// models
533
		$modelName = $this->modelService->getModelName();
534
		if ($modelName !== null) {
535
			$definitions = $this->generateDefinition($definitions, $modelName);
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $definitions is correct as $this->generateDefinitio...efinitions, $modelName) (which targets keeko\tools\command\Gene...d::generateDefinition()) seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
Unused Code introduced by
$definitions is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
536
		} else {
537
			foreach ($this->modelService->getModels() as $model) {
538
				$definitions = $this->generateDefinition($definitions, $model->getName());
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $definitions is correct as $this->generateDefinitio...ons, $model->getName()) (which targets keeko\tools\command\Gene...d::generateDefinition()) seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
Bug introduced by
It seems like $definitions defined by $this->generateDefinitio...ons, $model->getName()) on line 538 can be null; however, keeko\tools\command\Gene...d::generateDefinition() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
539
			}
540
		}
541
	}
542
	
543
	protected function generatePagedMeta(Definitions $definitions) {
544
		$props = $definitions->get('PagedMeta')->setType('object')->getProperties();
545
		$names = ['total', 'first', 'next', 'previous', 'last'];
546
		
547
		foreach ($names as $name) {
548
			$props->get($name)->setType('integer');
549
		}
550
	}
551
	
552
	protected function generateResourceIdentifier(Definitions $definitions) {
553
		$props = $definitions->get('ResourceIdentifier')->setType('object')->getProperties();
554
		$this->generateIdentifier($props);
555
	}
556
	
557
	protected function generateIdentifier(Definitions $props) {
558
		$props->get('id')->setType('string');
559
		$props->get('type')->setType('string');
560
	}
561
	
562
	protected function generateResourceData(Definitions $props) {
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
563
		$data = $props->get('data')->setType('object')->getProperties();
564
		$this->generateIdentifier($data);
565
		return $data;
566
	}
567
568
	protected function generateDefinition(Definitions $definitions, $modelName) {
569
		$this->logger->notice('Generating Definition for: ' . $modelName);
570
		$model = $this->modelService->getModel($modelName);
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 11 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
571
		$modelObjectName = $model->getPhpName();
572
		
573
		// paged model
574
		$pagedModel = 'Paged' . NameUtils::pluralize($modelObjectName);
575
		$paged = $definitions->get($pagedModel)->setType('object')->getProperties();
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 6 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
576
		$paged->get('data')
577
			->setType('array')
578
			->getItems()->setRef('#/definitions/' . $modelObjectName);
579
		$paged->get('meta')->setRef('#/definitions/PagedMeta');
580
		
581
		// writable model
582
		$writable = $definitions->get('Writable' . $modelObjectName)->setType('object')->getProperties();
583
		$this->generateModelProperties($writable, $model, true);
1 ignored issue
show
Bug introduced by
It seems like $model defined by $this->modelService->getModel($modelName) on line 570 can be null; however, keeko\tools\command\Gene...nerateModelProperties() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
584
585
		// readable model
586
		$readable = $definitions->get($modelObjectName)->setType('object')->getProperties();
587
		$this->generateModelProperties($readable, $model, false);
1 ignored issue
show
Bug introduced by
It seems like $model defined by $this->modelService->getModel($modelName) on line 570 can be null; however, keeko\tools\command\Gene...nerateModelProperties() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
588
	}
589
	
590
	protected function generateModelProperties(Definitions $props, Table $model, $write = false) {
591
		// links
592 View Code Duplication
		if (!$write) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
593
			$links = $props->get('links')->setType('object')->getProperties();
594
			$links->get('self')->setType('string');
595
		}
596
		
597
		// data
598
		$data = $this->generateResourceData($props);
599
		
600
		// attributes
601
		$attrs = $data->get('attributes');
602
		$attrs->setType('object');
603
		$this->generateModelAttributes($attrs->getProperties(), $model, $write);
604
605
		// relationships
606
		if ($this->hasRelationships($model)) {
607
			$relationships = $data->get('relationships')->setType('object')->getProperties();
608
			$this->generateModelRelationships($relationships, $model, $write);
609
		}
610
	}
611
	
612
	protected function generateModelAttributes(Definitions $props, Table $model, $write = false) {
613
		$modelName = $model->getOriginCommonName();
614
		$filter = $write 
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 4 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
615
			? $this->codegenService->getCodegen()->getWriteFilter($modelName)
616
			: $this->codegenService->getCodegen()->getReadFilter($modelName);
617
618
		if ($write) {
619
			$filter = array_merge($filter, $this->codegenService->getComputedFields($model));
620
		}
621
		
622
		// no id, already in identifier
623
		$filter[] = 'id';
624
		
625
		foreach ($model->getColumns() as $col) {
626
			$prop = $col->getName();
627
			
628
			if (!in_array($prop, $filter)) {
629
				$props->get($prop)->setType($col->getPhpType());
630
			}
631
		}
632
633
		return $props;
634
	}
635
	
636
	protected function hasRelationships(Table $model) {
637
		return (count($model->getForeignKeys()) + count($model->getCrossFks())) > 0;
638
	}
639
	
640
	protected function generateModelRelationships(Definitions $props, Table $model, $write = false) {
641
		$relationships = $this->getRelationships($model);
642
		
643
		// to-one
644
		foreach ($relationships['one'] as $one) {
645
			$fk = $one['fk'];
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 7 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
646
			$typeName = NameUtils::dasherize($fk->getForeignTable()->getOriginCommonName());
647
			$rel = $props->get($typeName)->setType('object')->getProperties();
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 6 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
648
			
649
			// links
650 View Code Duplication
			if (!$write) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
651
				$links = $rel->get('links')->setType('object')->getProperties();
652
				$links->get('self')->setType('string');
653
			}
654
			
655
			// data
656
			$this->generateResourceData($rel);
657
		}
658
		
659
		// to-many
660
		foreach ($relationships['many'] as $many) {
661
			$fk = $many['fk'];
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 11 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
662
			$foreignModel = $fk->getForeignTable();
663
			$typeName = NameUtils::pluralize(NameUtils::dasherize($foreignModel->getOriginCommonName()));
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 5 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
664
			$rel = $props->get($typeName)->setType('object')->getProperties();
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 10 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
665
			
666
			// links
667 View Code Duplication
			if (!$write) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
668
				$links = $rel->get('links')->setType('object')->getProperties();
669
				$links->get('self')->setType('string');
670
			}
671
			
672
			// data
673
			$rel->get('data')
674
				->setType('array')
675
				->getItems()->setRef('#/definitions/ResourceIdentifier');
676
		}
677
	}
678
679
}