Completed
Push — master ( 2e0a22...66405f )
by Thomas
05:23
created

GenerateApiCommand::generateRelationshipActions()   B

Complexity

Conditions 4
Paths 5

Size

Total Lines 23
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 23
ccs 0
cts 18
cp 0
rs 8.7972
cc 4
eloc 13
nc 5
nop 0
crap 20
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
use gossi\swagger\Tag;
27
28
class GenerateApiCommand extends AbstractGenerateCommand {
29
30
	protected function configure() {
31
		$this
32
			->setName('generate:api')
33
			->setDescription('Generates the api for the module')
34
		;
35
		
36
		$this->configureGenerateOptions();
37
			
38
		parent::configure();
39
	}
40
	
41
	/**
42
	 * Checks whether api can be generated at all by reading composer.json and verify
43
	 * all required information are available
44
	 */
45
	private function preCheck() {
46
		$module = $this->packageService->getModule();
47
		if ($module === null) {
48
			throw new \DomainException('No module definition found in composer.json - please run `keeko init`.');
49
		}
50
	}
51
52
	protected function execute(InputInterface $input, OutputInterface $output) {
53
		$this->preCheck();
54
		
55
		// prepare models ?
56
		$this->prepareModels();
57
		
58
		// generate relationship actions
59
		$this->generateRelationshipActions();
60
		
61
		// generate api
62
		$api = new File($this->project->getApiFileName());
63
		
64
		// if generation is forced, generate new API from scratch
65
		if ($input->getOption('force')) {
66
			$swagger = new Swagger();
67
		}
68
		
69
		// ... anyway reuse existing one
70
		else {
71
			if (!$api->exists()) {
72
				$api->write('{}');
73
			}
74
			
75
			$swagger = Swagger::fromFile($this->project->getApiFileName());
76
		}
77
78
		$module = $this->package->getKeeko()->getModule();
79
		$swagger->setVersion('2.0');
80
		$swagger->getInfo()->setTitle($module->getTitle() . ' API');
81
		$swagger->getTags()->clear();
82
		$swagger->getTags()->add(new Tag(['name' => $module->getSlug()]));
83
		
84
		$this->generatePaths($swagger);
85
		$this->generateDefinitions($swagger);
86
		
87
		$this->jsonService->write($api->getPathname(), $swagger->toArray());
88
		$this->io->writeln(sprintf('API for <info>%s</info> written at <info>%s</info>', $this->package->getFullName(), $api->getPathname()));
89
	}
90
	
91
	/**
92
	 * Adds the APIModelInterface to package models
93
	 * 
94
	 */
95
	protected function prepareModels() {
96
		$models = $this->modelService->getPackageModelNames();
97
		
98
		foreach ($models as $modelName) {
99
			$tableName = $this->modelService->getTableName($modelName);
100
			$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...
101
			$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...
102
			$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...
103
			
104
			if ($file->exists()) {
105
				$class = PhpClass::fromFile($this->codegenService->getFilename($class));
106
				if (!$class->hasInterface('APIModelInterface')) {
107
					$class->addUseStatement('keeko\\core\\model\\types\\APIModelInterface');
108
					$class->addInterface('APIModelInterface');
109
// 					$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...
110
// 					$class->setMethod(PhpMethod::create('getAPIType')
111
// 						->setBody('return \''.$typeName . '\';')
112
// 					);
113
	
114
					$this->codegenService->dumpStruct($class, true);
115
				}
116
			}
117
		}
118
	}
119
120
	protected function generateRelationshipActions() {
121
		$models = $this->modelService->getPackageModelNames();
122
		
123
		foreach ($models as $modelName) {
124
			$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...
125
			$relationships = $this->modelService->getRelationships($model);
1 ignored issue
show
Bug introduced by
It seems like $model defined by $this->modelService->getModel($modelName) on line 124 can be null; however, keeko\tools\services\Mod...ice::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...
126
			
127
			// to-one relationships
128
			foreach ($relationships['one'] as $one) {
129
				$fk = $one['fk'];
130
				$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 124 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...
131
			}
132
		
133
			// to-many relationships
134
			foreach ($relationships['many'] as $many) {
135
				$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...
136
				$cfk = $many['cfk'];
137
				$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 124 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...
138
			}
139
		}
140
		
141
		$this->packageService->savePackage();
142
	}
143
	
144
// 	protected function getRelationships(Table $model) {
0 ignored issues
show
Unused Code Comprehensibility introduced by
48% 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...
145
// 		// to-one relationships
146
// 		$one = [];
147
// 		$fks = $model->getForeignKeys();
148
// 		foreach ($fks as $fk) {
149
// 			$one[] = [
150
// 				'fk' => $fk
151
// 			];
152
// 		}
153
		
154
// 		// to-many relationships
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...
155
// 		$many = [];
156
// 		$cfks = $model->getCrossFks();
157
// 		foreach ($cfks as $cfk) {
158
// 			foreach ($cfk->getMiddleTable()->getForeignKeys() as $fk) {
159
// 				if ($fk->getForeignTable() != $model) {
160
// 					$many[] = [
161
// 						'fk' => $fk,
162
// 						'cfk' => $cfk
163
// 					];
164
// 					break;
165
// 				}
166
// 			}
167
// 		}
168
		
169
// 		return [
0 ignored issues
show
Unused Code Comprehensibility introduced by
47% 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...
170
// 			'one' => $one,
171
// 			'many' => $many
172
// 		];
173
// 	}
174
175
	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...
176
		$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...
177
		$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...
178
		$actionNamePrefix = sprintf('%s-to-%s-relationship',
179
			NameUtils::dasherize($model->getPhpName()),
180
			NameUtils::dasherize($fkModelName));
181
		$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...
182
		
183
		// response class name
184
		$response = sprintf('%s\\response\\%s%sJsonResponse',
185
			$this->modelService->getRootNamespace(),
186
			$model->getPhpName(),
187
			$fkModelName
188
		);
189
		
190
		$generators = [
191
			'read' => new ToOneRelationshipReadActionGenerator($this->service),
192
			'update' => new ToOneRelationshipUpdateActionGenerator($this->service)
193
		];
194
		$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...
195
			'read' => 'Reads the relationship of {model} to {foreign}',
196
			'update' => 'Updates the relationship of {model} to {foreign}'
197
		];
198
		
199 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...
200
			// generate fqcn
201
			$className = sprintf('%s%s%sAction', $model->getPhpName(), $fkModelName, ucfirst($type));
202
			$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...
203
				
204
			// generate action
205
			$action = new ActionSchema($actionNamePrefix . '-' . $type);
206
			$action->addAcl('admin');
207
			$action->setClass($fqcn);
208
			$action->setTitle(str_replace(
209
				['{model}', '{foreign}'],
210
				[$model->getOriginCommonName(), $foreign->getoriginCommonName()],
211
				$titles[$type])
212
			);
213
			$action->setResponse('json', $response);
214
			$module->addAction($action);
215
			$actions[$type] = $action;
216
				
217
			// generate class
218
			$generator = $generators[$type];
219
			$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...
220
			$this->codegenService->dumpStruct($class, true);
221
		}
222
		
223
		// generate response class
224
		$generator = new ToOneRelationshipJsonResponseGenerator($this->service, $model, $foreign);
225
		$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...
226
		$this->codegenService->dumpStruct($response, true);
227
228
// 		// 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...
229
// 		$className = sprintf('%s%sReadAction', $model->getPhpName(), $fkModelName);
230
// 		$fqcn = $this->modelService->getRootNamespace() . '\\action\\' . $className;
231
// 		$responseFqcn = str_replace(['action', 'Action'], ['response', 'JsonResponse'], $fqcn);
232
		
233
// 		$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...
234
// 		$readAction->addAcl('admin');
235
// 		$readAction->setClass($fqcn);
236
// 		$readAction->setTitle(sprintf('Reads the relationship of %s to %s', 
237
// 			$model->getCommonName(), $foreign->getCommonName())
238
// 		);
239
// 		$readAction->setResponse('json', $responseFqcn);
240
// 		$module->addAction($readAction);
241
		
242
// 		// 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...
243
// 		$generator = new ToOneRelationshipJsonResponseGenerator($this->service, $foreign);
244
// 		$response = $generator->generate($readAction);
245
// 		$this->codegenService->dumpStruct($response, true);
246
		
247
// 		// 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...
248
// 		$class = new PhpClass($fqcn);
249
// 		$generator = new ToOneRelationshipReadActionGenerator($this->service);
250
// 		$class = $generator->generate($class, $model);
251
// 		$this->codegenService->dumpStruct($class, true);
252
		
253
// 		// 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...
254
// 		$className = sprintf('%s%sUpdateAction', $model->getPhpName(), $fkModelName);
255
// 		$fqcn = $this->modelService->getRootNamespace() . '\\action\\' . $className;
256
// 		$updateAction = new ActionSchema($actionNamePrefix . '-update');
257
// 		$updateAction->addAcl('admin');
258
// 		$updateAction->setClass($fqcn);
259
// 		$updateAction->setTitle(sprintf('Updates the relationship of %s to %s',
260
// 			$model->getCommonName(), $foreign->getCommonName())
261
// 		);
262
// 		$updateAction->setResponse('json', $responseFqcn);
263
// 		$module->addAction($updateAction);
264
		
265
// 		// 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...
266
// 		$class = new PhpClass($fqcn);
267
// 		$generator = new ToOneRelationshipUpdateActionGenerator($this->service);
268
// 		$class = $generator->generate($class, $model, $foreign, $fk);
269
// 		$this->codegenService->dumpStruct($class, true);
270
	}
271
	
272
	protected function generateToManyRelationshipAction(Table $model, Table $foreign, Table $middle) {
273
		$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...
274
		$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...
275
		$actionNamePrefix = sprintf('%s-to-%s-relationship',
276
			NameUtils::dasherize($model->getPhpName()),
277
			NameUtils::dasherize($fkModelName));
278
		$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...
279
		
280
		// response class name
281
		$response = sprintf('%s\\response\\%s%sJsonResponse', 
282
			$this->modelService->getRootNamespace(),
283
			$model->getPhpName(),
284
			$fkModelName
285
		);
286
287
		$generators = [
288
			'read' => new ToManyRelationshipReadActionGenerator($this->service), 
289
			'update' => new ToManyRelationshipUpdateActionGenerator($this->service), 
290
			'add' => new ToManyRelationshipAddActionGenerator($this->service),
291
			'remove' => new ToManyRelationshipRemoveActionGenerator($this->service)
292
		];
293
		$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...
294
			'read' => 'Reads the relationship of {model} to {foreign}',
295
			'update' => 'Updates the relationship of {model} to {foreign}',
296
			'add' => 'Adds {foreign} as relationship to {model}',
297
			'remove' => 'Removes {foreign} as relationship of {model}'
298
		];
299
		
300 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...
301
			// generate fqcn
302
			$className = sprintf('%s%s%sAction', $model->getPhpName(), $fkModelName, ucfirst($type));
303
			$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...
304
			
305
			// generate action
306
			$action = new ActionSchema($actionNamePrefix . '-' . $type);
307
			$action->addAcl('admin');
308
			$action->setClass($fqcn);
309
			$action->setTitle(str_replace(
310
				['{model}', '{foreign}'],
311
				[$model->getOriginCommonName(), $foreign->getoriginCommonName()], 
312
				$titles[$type])
313
			);
314
			$action->setResponse('json', $response);
315
			$module->addAction($action);
316
			$actions[$type] = $action;
317
			
318
			// generate class
319
			$generator = $generators[$type];
320
			$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...
321
			$this->codegenService->dumpStruct($class, true);
322
		}
323
		
324
		// generate response class
325
		$generator = new ToManyRelationshipJsonResponseGenerator($this->service, $model, $foreign);
326
		$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...
327
		$this->codegenService->dumpStruct($response, true);
328
	}
329
	
330
	protected function generatePaths(Swagger $swagger) {
331
		$paths = $swagger->getPaths();
332
		
333
		foreach ($this->packageService->getModule()->getActionNames() as $name) {
334
			$this->generateOperation($paths, $name);
335
		}
336
	}
337
	
338
	protected function generateOperation(Paths $paths, $actionName) {
339
		$this->logger->notice('Generating Operation for: ' . $actionName);
340
341
		if (Text::create($actionName)->contains('relationship')) {
342
			$this->generateRelationshipOperation($paths, $actionName);
343
		} else {
344
			$this->generateCRUDOperation($paths, $actionName);
345
		}
346
	}
347
348
	protected function generateRelationshipOperation(Paths $paths, $actionName) {
349
		$this->logger->notice('Generating Relationship Operation for: ' . $actionName);
350
		$prefix = substr($actionName, 0, strrpos($actionName, 'relationship') + 12);
351
		$module = $this->packageService->getModule();
352
353
		// test for to-many relationship:
354
		$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...
355
			&& $module->hasAction($prefix . '-update')
356
			&& $module->hasAction($prefix . '-add')
357
			&& $module->hasAction($prefix . '-remove')
358
		;
359
		$single = $module->hasAction($prefix . '-read') 
360
			&& $module->hasAction($prefix . '-update')
361
			&& !$many
362
		;
363
		
364
		if (!$many && !$single) {
365
			$this->io->writeln(sprintf('<comment>Couldn\'t detect whether %s is a to-one or to-many relationship, skin generating endpoints</comment>', $actionName));
366
			return;
367
		}
368
		
369
		// find model names
370
		$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...
371
		$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...
372
		$foreignModelName = substr($actionName, $start, strpos($actionName, 'relationship') - 1 - $start);
373
374
		// 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...
375
// 		$model = $this->modelService->getModel(NameUtils::toSnakeCase($modelName));
376
// 		$foreignModel = $this->modelService->getModel(NameUtils::toSnakeCase($foreignModelName));
377
// 		$fk = null;
378
// 		foreach ($model->getForeignKeys() as $key) {
379
// 			if ($key->getForeignTable() == $foreignModel) {
380
// 				$fk = $key;
381
// 			}
382
// 		}
383
// 		$fkName = $fk->getLocalColumn()->getName();
384
		
385
		$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...
386
		$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...
387
		$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...
388
		$endpoint = '/' . NameUtils::pluralize($modelName) . '/{id}/relationship/' . ($single ?
389
			$foreignModelName : NameUtils::pluralize($foreignModelName));
390
		
391
		$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...
392
		$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...
393
		$operation = $path->getOperation($method);
394
		$operation->setDescription($action->getTitle());
395
		$operation->setOperationId($action->getName());
396
		$operation->getTags()->clear();
397
		$operation->getTags()->add(new Tag($this->package->getKeeko()->getModule()->getSlug()));
0 ignored issues
show
Documentation introduced by
$this->package->getKeeko...>getModule()->getSlug() is of type string, but the function expects a array.

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

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

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

function acceptsInteger($int) { }

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

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
398
		
399
		$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...
400
		$responses = $operation->getResponses();
401
		
402
		// general model related params
403
		// params
404
		$id = $params->getByName('id');
405
		$id->setIn('path');
406
		$id->setDescription(sprintf('The %s id', $modelName));
407
		$id->setRequired(true);
408
		$id->setType('integer');
409
		
410
		// response
411
		$invalid = $responses->get('400');
412
		$invalid->setDescription('Invalid ID supplied');
413
		
414
		$notfound = $responses->get('404');
415
		$notfound->setDescription(sprintf('No %s found', $modelName));
416
	}
417
	
418
	protected function generateCRUDOperation(Paths $paths, $actionName) {
419
		$this->logger->notice('Generating CRUD Operation for: ' . $actionName);
420
		$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...
421
		$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...
422
		$modelName = $this->modelService->getModelNameByAction($action);
0 ignored issues
show
Bug introduced by
It seems like $action defined by $this->packageService->getAction($actionName) on line 421 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...
423
		$tableName = $this->modelService->getTableName($modelName);
424
	
425
		if (!$database->hasTable($tableName)) {
426
			return $paths;
427
		}
428
	
429
		$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...
430
		$modelObjectName = $database->getTable($tableName)->getPhpName();
431
		$modelPluralName = NameUtils::pluralize($modelName);
432
	
433
		// find path branch
434
		switch ($type) {
435
			case 'list':
436
			case 'create':
437
				$endpoint = '/' . $modelPluralName;
438
				break;
439
	
440
			case 'read':
441
			case 'update':
442
			case 'delete':
443
				$endpoint = '/' . $modelPluralName . '/{id}';
444
				break;
445
	
446
			default:
447
				throw new \RuntimeException(sprintf('type (%s) not found, can\'t continue.', $type));
448
				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...
449
		}
450
451
		$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...
452
		$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...
453
		$operation = $path->getOperation($method);
454
		$operation->setDescription($action->getTitle());
455
		$operation->setOperationId($action->getName());
456
		$operation->getTags()->clear();
457
		$operation->getTags()->add(new Tag($this->package->getKeeko()->getModule()->getSlug()));
0 ignored issues
show
Documentation introduced by
$this->package->getKeeko...>getModule()->getSlug() is of type string, but the function expects a array.

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

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

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

function acceptsInteger($int) { }

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

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
458
	
459
		$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...
460
		$responses = $operation->getResponses();
461
	
462
		switch ($type) {
463
			case 'list':
464
				$ok = $responses->get('200');
465
				$ok->setDescription(sprintf('Array of %s', $modelPluralName));
466
				$ok->getSchema()->setRef('#/definitions/' . 'Paged' . NameUtils::pluralize($modelObjectName));
467
				break;
468
	
469
			case 'create':
470
				// params
471
				$body = $params->getByName('body');
472
				$body->setName('body');
473
				$body->setIn('body');
474
				$body->setDescription(sprintf('The new %s', $modelName));
475
				$body->setRequired(true);
476
				$body->getSchema()->setRef('#/definitions/Writable' . $modelObjectName);
477
	
478
				// response
479
				$ok = $responses->get('201');
480
				$ok->setDescription(sprintf('%s created', $modelName));
481
				break;
482
	
483 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...
484
				// response
485
				$ok = $responses->get('200');
486
				$ok->setDescription(sprintf('gets the %s', $modelName));
487
				$ok->getSchema()->setRef('#/definitions/' . $modelObjectName);
488
				break;
489
	
490 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...
491
				// response
492
				$ok = $responses->get('200');
493
				$ok->setDescription(sprintf('%s updated', $modelName));
494
				$ok->getSchema()->setRef('#/definitions/' . $modelObjectName);
495
				break;
496
	
497
			case 'delete':
498
				// response
499
				$ok = $responses->get('204');
500
				$ok->setDescription(sprintf('%s deleted', $modelName));
501
				break;
502
		}
503
	
504
		if ($type == 'read' || $type == 'update' || $type == 'delete') {
505
			// params
506
			$id = $params->getByName('id');
507
			$id->setIn('path');
508
			$id->setDescription(sprintf('The %s id', $modelName));
509
			$id->setRequired(true);
510
			$id->setType('integer');
511
	
512
			// response
513
			$invalid = $responses->get('400');
514
			$invalid->setDescription('Invalid ID supplied');
515
				
516
			$notfound = $responses->get('404');
517
			$notfound->setDescription(sprintf('No %s found', $modelName));
518
		}
519
	
520
		// response - @TODO Error model
521
	}
522
	
523
	private function getMethod($type) {
524
		$methods = [
525
			'list' => 'get',
526
			'create' => 'post',
527
			'read' => 'get',
528
			'update' => 'patch',
529
			'delete' => 'delete',
530
			'add' => 'post',
531
			'remove' => 'delete'
532
		];
533
	
534
		return $methods[$type];
535
	}
536
537
	protected function generateDefinitions(Swagger $swagger) {
538
		$definitions = $swagger->getDefinitions();
539
		
540
		// general definitions
541
		$this->generatePagedMeta($definitions);
542
		$this->generateResourceIdentifier($definitions); 
543
544
		// models
545
		$modelName = $this->modelService->getModelName();
546
		if ($modelName !== null) {
547
			$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...
548
		} else {
549
			foreach ($this->modelService->getModels() as $model) {
550
				$definitions = $this->generateDefinition($definitions, $model->getName());
0 ignored issues
show
Bug introduced by
It seems like $definitions defined by $this->generateDefinitio...ons, $model->getName()) on line 550 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...
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...
551
			}
552
		}
553
	}
554
	
555
	protected function generatePagedMeta(Definitions $definitions) {
556
		$props = $definitions->get('PagedMeta')->setType('object')->getProperties();
557
		$names = ['total', 'first', 'next', 'previous', 'last'];
558
		
559
		foreach ($names as $name) {
560
			$props->get($name)->setType('integer');
561
		}
562
	}
563
	
564
	protected function generateResourceIdentifier(Definitions $definitions) {
565
		$props = $definitions->get('ResourceIdentifier')->setType('object')->getProperties();
566
		$this->generateIdentifier($props);
567
	}
568
	
569
	protected function generateIdentifier(Definitions $props) {
570
		$props->get('id')->setType('string');
571
		$props->get('type')->setType('string');
572
	}
573
	
574
	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...
575
		$data = $props->get('data')->setType('object')->getProperties();
576
		$this->generateIdentifier($data);
577
		return $data;
578
	}
579
580
	protected function generateDefinition(Definitions $definitions, $modelName) {
581
		$this->logger->notice('Generating Definition for: ' . $modelName);
582
		$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...
583
		$modelObjectName = $model->getPhpName();
584
		
585
		// paged model
586
		$pagedModel = 'Paged' . NameUtils::pluralize($modelObjectName);
587
		$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...
588
		$paged->get('data')
589
			->setType('array')
590
			->getItems()->setRef('#/definitions/' . $modelObjectName);
591
		$paged->get('meta')->setRef('#/definitions/PagedMeta');
592
		
593
		// writable model
594
		$writable = $definitions->get('Writable' . $modelObjectName)->setType('object')->getProperties();
595
		$this->generateModelProperties($writable, $model, true);
1 ignored issue
show
Bug introduced by
It seems like $model defined by $this->modelService->getModel($modelName) on line 582 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...
596
597
		// readable model
598
		$readable = $definitions->get($modelObjectName)->setType('object')->getProperties();
599
		$this->generateModelProperties($readable, $model, false);
1 ignored issue
show
Bug introduced by
It seems like $model defined by $this->modelService->getModel($modelName) on line 582 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...
600
	}
601
	
602
	protected function generateModelProperties(Definitions $props, Table $model, $write = false) {
603
		// links
604 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...
605
			$links = $props->get('links')->setType('object')->getProperties();
606
			$links->get('self')->setType('string');
607
		}
608
		
609
		// data
610
		$data = $this->generateResourceData($props);
611
		
612
		// attributes
613
		$attrs = $data->get('attributes');
614
		$attrs->setType('object');
615
		$this->generateModelAttributes($attrs->getProperties(), $model, $write);
616
617
		// relationships
618
		if ($this->hasRelationships($model)) {
619
			$relationships = $data->get('relationships')->setType('object')->getProperties();
620
			$this->generateModelRelationships($relationships, $model, $write);
621
		}
622
	}
623
	
624
	protected function generateModelAttributes(Definitions $props, Table $model, $write = false) {
625
		$modelName = $model->getOriginCommonName();
626
		$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...
627
			? $this->codegenService->getCodegen()->getWriteFilter($modelName)
628
			: $this->codegenService->getCodegen()->getReadFilter($modelName);
629
630
		if ($write) {
631
			$filter = array_merge($filter, $this->codegenService->getComputedFields($model));
632
		}
633
		
634
		// no id, already in identifier
635
		$filter[] = 'id';
636
		$types = ['int' => 'integer'];
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...
637
		
638
		foreach ($model->getColumns() as $col) {
639
			$prop = $col->getName();
640
			
641
			if (!in_array($prop, $filter)) {
642
				$type = $col->getPhpType();
643
				if (isset($types[$type])) {
644
					$type = $types[$type];
645
				}
646
				$props->get($prop)->setType($type);
647
			}
648
		}
649
650
		return $props;
651
	}
652
	
653
	protected function hasRelationships(Table $model) {
654
		return (count($model->getForeignKeys()) + count($model->getCrossFks())) > 0;
655
	}
656
	
657
	protected function generateModelRelationships(Definitions $props, Table $model, $write = false) {
658
		$relationships = $this->modelService->getRelationships($model);
659
		
660
		// to-one
661
		foreach ($relationships['one'] as $one) {
662
			$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...
663
			$typeName = NameUtils::dasherize($fk->getForeignTable()->getOriginCommonName());
664
			$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...
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
			$this->generateResourceData($rel);
674
		}
675
		
676
		// to-many
677
		foreach ($relationships['many'] as $many) {
678
			$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...
679
			$foreignModel = $fk->getForeignTable();
680
			$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...
681
			$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...
682
			
683
			// links
684 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...
685
				$links = $rel->get('links')->setType('object')->getProperties();
686
				$links->get('self')->setType('string');
687
			}
688
			
689
			// data
690
			$rel->get('data')
691
				->setType('array')
692
				->getItems()->setRef('#/definitions/ResourceIdentifier');
693
		}
694
	}
695
696
}