Completed
Push — master ( 2fb143...d99a08 )
by Thomas
09:36
created

GenerateActionCommand::generateModel()   C

Complexity

Conditions 9
Paths 16

Size

Total Lines 59
Code Lines 35

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 37
CRAP Score 9.0014

Importance

Changes 10
Bugs 0 Features 2
Metric Value
c 10
b 0
f 2
dl 0
loc 59
ccs 37
cts 38
cp 0.9737
rs 6.9133
cc 9
eloc 35
nc 16
nop 1
crap 9.0014

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\PhpTrait;
6
use keeko\framework\schema\ActionSchema;
7
use keeko\framework\utils\NameUtils;
8
use keeko\tools\generator\action\BlankActionGenerator;
9
use keeko\tools\generator\action\NoopActionGenerator;
10
use keeko\tools\generator\action\ToManyRelationshipAddActionGenerator;
11
use keeko\tools\generator\action\ToManyRelationshipReadActionGenerator;
12
use keeko\tools\generator\action\ToManyRelationshipRemoveActionGenerator;
13
use keeko\tools\generator\action\ToManyRelationshipUpdateActionGenerator;
14
use keeko\tools\generator\action\ToOneRelationshipReadActionGenerator;
15
use keeko\tools\generator\action\ToOneRelationshipUpdateActionGenerator;
16
use keeko\tools\generator\GeneratorFactory;
17
use keeko\tools\helpers\QuestionHelperTrait;
18
use keeko\tools\utils\NamespaceResolver;
19
use phootwork\file\File;
20
use phootwork\lang\Text;
21
use Propel\Generator\Model\ForeignKey;
22
use Propel\Generator\Model\Table;
23
use Symfony\Component\Console\Input\InputArgument;
24
use Symfony\Component\Console\Input\InputInterface;
25 20
use Symfony\Component\Console\Input\InputOption;
26 20
use Symfony\Component\Console\Output\OutputInterface;
27 20
use Symfony\Component\Console\Question\ConfirmationQuestion;
28 20
use Symfony\Component\Console\Question\Question;
29 20
30 20
class GenerateActionCommand extends AbstractGenerateCommand {
31 20
32
	use QuestionHelperTrait;
33 20
34 20
	protected function configure() {
35 20
		$this
36 20
			->setName('generate:action')
37 20
			->setDescription('Generates an action')
38 20
			->addArgument(
39
				'name',
40 20
				InputArgument::OPTIONAL,
41 20
				'The name of the action, which should be generated. Typically in the form %nomen%-%verb% (e.g. user-create)'
42 20
			)
43 20
			->addOption(
44 20
				'classname',
45
				'c',
46 20
				InputOption::VALUE_OPTIONAL,
47 20
				'The main class name (If ommited, class name will be guessed from action name)',
48 20
				null
49 20
			)
50 20
			->addOption(
51
				'model',
52 20
				'm',
53 20
				InputOption::VALUE_OPTIONAL,
54 20
				'The model for which the actions should be generated, when there is no name argument (if ommited all models will be generated)'
55 20
			)
56 20
			->addOption(
57
				'title',
58 20
				'',
59 20
				InputOption::VALUE_OPTIONAL,
60 20
				'The title for the generated option'
61 20
			)
62
			->addOption(
63 20
				'type',
64
				'',
65
				InputOption::VALUE_OPTIONAL,
66
				'The type of this action (list|create|read|update|delete) (if ommited template is guessed from action name)'
67
			)->addOption(
68
				'acl',
69
				'',
70
				InputOption::VALUE_IS_ARRAY | InputOption::VALUE_OPTIONAL,
71 1
				'The acl\s for this action (guest, user and/or admin)'
72
			)
73 20
		;
74
		
75 20
		$this->configureGenerateOptions();
76 20
		
77
		parent::configure();
78
	}
79
80
	protected function initialize(InputInterface $input, OutputInterface $output) {
81
		parent::initialize($input, $output);
82 10
	}
83 10
84 10
	/**
85 1
	 * Checks whether actions can be generated at all by reading composer.json and verify
86 4
	 * all required information are available
87 9
	 */
88
	private function preCheck() {
89
		$module = $this->packageService->getModule();
90
		if ($module === null) {
91
			throw new \DomainException('No module definition found in composer.json - please run `keeko init`.');
92
		}
93
	}
94
	
95
	protected function interact(InputInterface $input, OutputInterface $output) {
96
		$this->preCheck();
97
		
98
		// check if the dialog can be skipped
99
		$name = $input->getArgument('name');
100
		$model = $input->getOption('model');
101
		
102
		if ($model !== null) {
103
			return;
104
		} else if ($name !== null) {
105
			$generateModel = false;
106
		} else {
107
			$modelQuestion = new ConfirmationQuestion('Do you want to generate an action based off a model?');
108
			$generateModel = $this->askConfirmation($modelQuestion);
109
		}
110
		
111
		// ask questions for a model
112
		if ($generateModel) {
113
			$schema = str_replace(getcwd(), '', $this->modelService->getSchema());
114
			$allQuestion = new ConfirmationQuestion(sprintf('For all models in the schema (%s)?', $schema));
115
			$allModels = $this->askConfirmation($allQuestion);
116
117
			if (!$allModels) {
118
				$modelQuestion = new Question('Which model');
119
				$modelQuestion->setAutocompleterValues($this->modelService->getModelNames());
120
				$model = $this->askQuestion($modelQuestion);
121
				$input->setOption('model', $model);
122
			}
123
		} else if (!$generateModel) {
124
			$action = $this->getAction($name);
125
			
126
			// ask for title
127
			$pkgTitle = $action->getTitle();
128
			$title = $input->getOption('title');
129
			if ($title === null && !empty($pkgTitle)) {
130
				$title = $pkgTitle;
131
			}
132
			$titleQuestion = new Question('What\'s the title for your action?', $title);
133
			$title = $this->askQuestion($titleQuestion);
134
			$input->setOption('title', $title);
135
			
136
			// ask for classname
137
			$pkgClass = $action->getClass();
138
			$classname = $input->getOption('classname');
139
			if ($classname === null) {
140
				if (!empty($pkgClass)) {
141
					$classname = $pkgClass;
142
				} else {
143
					$classname = $this->guessClassname($name);
144
				}
145
			}
146
			$classname = $this->askQuestion(new Question('Classname', $classname));
147
			$input->setOption('classname', $classname);
148
			
149
			// ask for acl
150
			$acls = $this->getAcl($action);
151
			$aclQuestion = new Question('ACL (comma separated list, with these options: guest, user, admin)', implode(', ', $acls));
152 10
			$acls = $this->askQuestion($aclQuestion);
153 10
			$input->setOption('acl', $acls);
154
		}
155
	}
156
157
	protected function execute(InputInterface $input, OutputInterface $output) {
158
		$this->preCheck();
159 9
160 9
		$name = $input->getArgument('name');
161
		$model = $input->getOption('model');
162
163 9
		// only a specific action
164 3
		if ($name) {
165 2
			$this->generateNamed($name);
166
		}
167
168 6
		// create action(s) from a model
169 2
		else if ($model) {
170 2
			$this->generateModel($model);
171
		}
172
173 4
		// anyway, generate all models
174 3
		else {
175 3
			foreach ($this->modelService->getModels() as $model) {
176 2
				$modelName = $model->getOriginCommonName();
177 2
				$input->setOption('model', $modelName);
178 2
				$this->generateModel($modelName);
179 1
			}
180
		}
181 3
		
182
		$this->packageService->savePackage();
183
	}
184
185 1
	private function generateModel($modelName) {
186 1
		$this->logger->info('Generate Action from Model: ' . $modelName);
187 1
		$input = $this->io->getInput();
188
		$model = $this->modelService->getModel($modelName);
189
		
190 8
		// generate domain + serializer
191 8
		$this->generateDomain($model);
1 ignored issue
show
Bug introduced by
It seems like $model defined by $this->modelService->getModel($modelName) on line 188 can be null; however, keeko\tools\command\Gene...mmand::generateDomain() 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...
192
		$this->generateSerializer($model);
1 ignored issue
show
Bug introduced by
It seems like $model defined by $this->modelService->getModel($modelName) on line 188 can be null; however, keeko\tools\command\Gene...d::generateSerializer() 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...
193 5
194 5
		// generate action type(s)
195 5
		$typeDump = $input->getOption('type');
196 5
		if ($typeDump !== null) {
197 5
			$types = [$typeDump];
198 1
		} else {
199 1
			$types = ['create', 'read', 'list', 'update', 'delete'];
200 4
		}
201
		
202
		foreach ($types as $type) {
203 5
			$input->setOption('acl', ['admin']);
1 ignored issue
show
Documentation introduced by
array('admin') is of type array<integer,string,{"0":"string"}>, but the function expects a string|boolean.

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...
204 5
			$input->setOption('type', $type);
205 5
			$actionName = $modelName . '-' . $type;
206 5
			
207 5
			if ($model->isReadOnly() && in_array($type, ['create', 'update', 'delete'])) {
208 5
				$this->logger->info(sprintf('Skip generate Action (%s), because Model (%s) is read-only', $actionName, $modelName));
209 4
				continue;
210 5
			}
211 5
			
212 5
			$action = $this->getAction($actionName);
213
			if (Text::create($action->getTitle())->isEmpty()) {
214 5
				$action->setTitle($this->getActionTitle($modelName, $type));
215 5
			}
216
			$action = $this->generateAction($actionName);
0 ignored issues
show
Documentation introduced by
$actionName is of type string, but the function expects a object<keeko\tools\command\unknown>.

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...
217 4
			
218
			// generate code
219 4
			$generator = GeneratorFactory::createModelActionGenerator($type, $this->service);
220 3
			$class = $generator->generate($action);
221
			$this->codegenService->dumpStruct($class, true);
222 4
		}
223 4
		
224 4
		// generate relationship actions
225 4
		if (!$model->isReadOnly()) {
226 4
			$relationships = $this->modelService->getRelationships($model);
1 ignored issue
show
Bug introduced by
It seems like $model defined by $this->modelService->getModel($modelName) on line 188 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...
227
				
228
			// to-one relationships
229
			foreach ($relationships['one'] as $one) {
230
				$fk = $one['fk'];
231
				$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 188 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...
232
			}
233
			
234
			// to-many relationships
235
			foreach ($relationships['many'] as $many) {
236
				$fk = $many['fk'];
237 8
				$cfk = $many['cfk'];
238 8
				$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 188 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...
239 8
			}
240
		}
241
		
242 8
		$input->setOption('type', $typeDump);
243
	}
244 8
245 2
	private function getActionTitle($modelName, $type) {
246 2
		$name = NameUtils::dasherize($modelName);
1 ignored issue
show
Bug introduced by
The method dasherize() cannot be called from this context as it is declared private in class keeko\framework\utils\NameUtils.

This check looks for access to methods that are not accessible from the current context.

If you need to make a method accessible to another context you can raise its visibility level in the defining class.

Loading history...
247
		switch ($type) {
248 8
			case 'list':
249 1
				return 'List all ' . NameUtils::pluralize($name);
250
251
			case 'create':
252 7
			case 'read':
253 2
			case 'update':
254 2
			case 'delete':
255
				return ucfirst($type) . 's ' . (in_array($name[0], ['a', 'e', 'i', 'o', 'u']) ? 'an' : 'a') . ' ' . $name;
256
		}
257 7
	}
258 4
259 4
	/**
260
	 * Generates a domain with trait for the given model
261
	 * 
262 7
	 * @param Table $model
263 7
	 */
264 7
	private function generateDomain(Table $model) {
265
		$this->runCommand('generate:domain', [
266
			'--model' => $model->getOriginCommonName()
267
		]);
268
	}
269
	
270
	/**
271 7
	 * Generates a serializer for the given model
272
	 *
273
	 * @param Table $model
274 7
	 */
275 7
	private function generateSerializer(Table $model) {
276
		$this->runCommand('generate:serializer', [
277 4
			'--model' => $model->getOriginCommonName()
278 4
		]);
279 4
	}
280
	
281
	/**
282
	 * Generates an action.
283
	 *  
284
	 * @param string $actionName
285
	 * @param ActionSchema $action the action node from composer.json
0 ignored issues
show
Documentation introduced by
There is no parameter named $action. Did you maybe mean $actionName?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.

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

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

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

Loading history...
286
	 */
287 8
	private function generateNamed($actionName) {
288 8
		$this->logger->info('Generate Action: ' . $actionName);
289 8
		$action = $this->generateAction($actionName);
0 ignored issues
show
Documentation introduced by
$actionName is of type string, but the function expects a object<keeko\tools\command\unknown>.

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...
290 7
		
291 7
		// generate code
292 7
		$this->generateCode($action);
293 7
	}
294 8
	
295
	/**
296
	 * Generates the action for the package
297 7
	 * 
298 7
	 * @param unknown $actionName
299 7
	 * @throws \RuntimeException
300 7
	 * @return ActionSchema
301 7
	 */
302 2
	private function generateAction($actionName) {
303 2
		$input = $this->io->getInput();
304 7
		
305 7
		// get action and create it if it doesn't exist
306 1
		$action = $this->getAction($actionName);
307 1
		
308 1
		if (($title = $input->getOption('title')) !== null) {
309 1
			$action->setTitle($title);
310 1
		}
311 6
		
312
		if (Text::create($action->getTitle())->isEmpty()) {
313 7
			throw new \RuntimeException(sprintf('Cannot create action %s, because I am missing a title for it', $actionName));
314
		}
315 7
		
316
		if (($classname = $input->getOption('classname')) !== null) {
317
			$action->setClass($classname);
318
		}
319
		
320
		// guess classname if there is none set yet
321
		if (Text::create($action->getClass())->isEmpty()) {
322
			$action->setClass($this->guessClassname($actionName));
323
		}
324
		
325
		// guess title if there is none set yet
326
		if (Text::create($action->getTitle())->isEmpty()
327
				&& $this->modelService->isModelAction($action)
328
				&& $this->modelService->isCrudAction($action)) {
329
			$modelName = $this->modelService->getModelNameByAction($action);
330
			$type = $this->modelService->getOperationByAction($action);
331 7
			$action->setTitle($this->getActionTitle($modelName, $type));
332 7
		}
333 7
	
334
		// set acl
335
		$action->setAcl($this->getAcl($action));
336 7
		
337 7
		return $action;
338 7
	}
339 7
	
340 7
	private function guessClassname($name) {
341
		$namespace = NamespaceResolver::getNamespace('src/action', $this->package);
342
		return $namespace . '\\' . NameUtils::toStudlyCase($name) . 'Action';
343 7
	}
344
	
345 1
	/**
346 1
	 * 
347
	 * @param string $actionName
348 1
	 * @return ActionSchema
349 1
	 */
350 1
	private function getAction($actionName) {
351
		$action = $this->packageService->getAction($actionName);
352
		if ($action == null) {
353 1
			$action = new ActionSchema($actionName);
354 1
			$module = $this->packageService->getModule();
355 1
			$module->addAction($action);
356
		}
357
		return $action;
358
	}
359 6
	
360 6
	private function getAcl(ActionSchema $action) {
361 6
		$acls = [];
362 6
		$acl = $this->io->getInput()->getOption('acl');
363 6
		if ($acl !== null && count($acl) > 0) {
364
			if (!is_array($acl)) {
365
				$acl = [$acl];
366
			}
367 7
			foreach ($acl as $group) {
368 5
				if (strpos($group, ',') !== false) {
369 1
					$groups = explode(',', $group);
370 1
					foreach ($groups as $g) {
371 1
						$acls[] = trim($g);
372 5
					}
373 5
				} else {
374
					$acls[] = $group;
375 5
				}
376 5
			}
377
			
378 5
			return $acls;
379 4
		}
380 4
		
381 4
		// read default from package
382 5
		if (!$action->getAcl()->isEmpty()) {
383
			return $action->getAcl()->toArray();
384 2
		}
385 2
386 2
		return $acls;
387 2
	}
388 2
	
389
	/**
390
	 * Generates code for an action
391 7
	 * 
392 7
	 * @param ActionSchema $action
393
	 */
394
	private function generateCode(ActionSchema $action) {
395
		$input = $this->io->getInput();
396
		$trait = null;
0 ignored issues
show
Unused Code introduced by
$trait 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...
397
398
		// class
399
		$class = new PhpClass($action->getClass());
400
		$filename = $this->codegenService->getFilename($class);
401
		$traitNs = $class->getNamespace() . '\\base';
402
		$traitName = $class->getName() . 'Trait';
403
		$overwrite = false;
404
		
405
		// load from file, when class exists
406
		if (file_exists($filename)) {
407
			// load trait
408
			$trait = new PhpTrait($traitNs . '\\' . $traitName);
409
			$traitFile = new File($this->codegenService->getFilename($trait));
410
411
			if ($traitFile->exists()) {
412
				$trait = PhpTrait::fromFile($traitFile->getPathname());
0 ignored issues
show
Unused Code introduced by
$trait 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...
413
			}
414
		
415
			// load class
416
			$class = PhpClass::fromFile($filename);
417
		}
418
		
419
		// anyway seed class information
420
		else {
421
			$overwrite = true;
422
			$class->setParentClassName('AbstractAction');
423
			$class->setDescription($action->getTitle());
424
			$class->setLongDescription($action->getDescription());
425
			$this->codegenService->addAuthors($class, $this->package);
426
		}
427
		
428
		// create base trait
429
		$modelName = $input->getOption('model');
430
		if ($modelName !== null) {
431
			$type = $this->packageService->getActionType($action->getName(), $modelName);
432
			$generator = GeneratorFactory::createActionTraitGenerator($type, $this->service);
0 ignored issues
show
Bug introduced by
The method createActionTraitGenerator() does not seem to exist on object<keeko\tools\generator\GeneratorFactory>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
433
			$trait = $generator->generate($traitNs . '\\' . $traitName, $action);
434
435
			$this->codegenService->addAuthors($trait, $this->package);
436
			$this->codegenService->dumpStruct($trait, true);
437
			
438
			if (!$class->hasTrait($trait)) {
439
				$class->addTrait($trait);
440
				$overwrite = true;
441
			}
442
		}
443
		
444
		// create class generator
445
		if ($modelName === null && !$class->hasMethod('run')) {
446
			$overwrite = true;
447
			$generator = new BlankActionGenerator($this->service);
448
		} else {
449
			$generator = new NoopActionGenerator($this->service);
450
		}
451
452
		$class = $generator->generate($class);
453
		$overwrite = $overwrite || $input->getOption('force');
454
455
		$this->codegenService->dumpStruct($class, $overwrite);
456
	}
457
	
458
	private function generateToOneRelationshipAction(Table $model, Table $foreign, ForeignKey $fk) {
459
		$module = $this->package->getKeeko()->getModule();
460
		$fkModelName = $foreign->getPhpName();
461
		$actionNamePrefix = sprintf('%s-to-%s-relationship', $model->getOriginCommonName(), $foreign->getOriginCommonName());
462
	
463
		$generators = [
464
			'read' => new ToOneRelationshipReadActionGenerator($this->service),
465
			'update' => new ToOneRelationshipUpdateActionGenerator($this->service)
466
		];
467
		$titles = [
468
			'read' => 'Reads the relationship of {model} to {foreign}',
469
			'update' => 'Updates the relationship of {model} to {foreign}'
470
		];
471
	
472
		foreach (array_keys($generators) as $type) {
473
			// generate fqcn
474
			$className = sprintf('%s%s%sAction', $model->getPhpName(), $fkModelName, ucfirst($type));
475
			$fqcn = $this->packageService->getNamespace() . '\\action\\' . $className;
476
	
477
			// generate action
478
			$action = new ActionSchema($actionNamePrefix . '-' . $type);
479
			$action->addAcl('admin');
480
			$action->setClass($fqcn);
481
			$action->setTitle(str_replace(
482
				['{model}', '{foreign}'],
483
				[$model->getOriginCommonName(), $foreign->getoriginCommonName()],
484
				$titles[$type])
485
			);
486
			$module->addAction($action);
487
	
488
			// generate class
489
			$generator = $generators[$type];
490
			$class = $generator->generate(new PhpClass($fqcn), $model, $foreign, $fk);
491
			$this->codegenService->dumpStruct($class, true);
492
		}
493
	}
494
	
495
	private function generateToManyRelationshipAction(Table $model, Table $foreign, Table $middle) {
496
		$module = $this->package->getKeeko()->getModule();
497
		$fkModelName = $foreign->getPhpName();
498
		$actionNamePrefix = sprintf('%s-to-%s-relationship', $model->getOriginCommonName(), $foreign->getOriginCommonName());
499
		
500
		$generators = [
501
			'read' => new ToManyRelationshipReadActionGenerator($this->service),
502
			'update' => new ToManyRelationshipUpdateActionGenerator($this->service),
503
			'add' => new ToManyRelationshipAddActionGenerator($this->service),
504
			'remove' => new ToManyRelationshipRemoveActionGenerator($this->service)
505
		];
506
		$titles = [
507
			'read' => 'Reads the relationship of {model} to {foreign}',
508
			'update' => 'Updates the relationship of {model} to {foreign}',
509
			'add' => 'Adds {foreign} as relationship to {model}',
510
			'remove' => 'Removes {foreign} as relationship of {model}'
511
		];
512
	
513
		foreach (array_keys($generators) as $type) {
514
			// generate fqcn
515
			$className = sprintf('%s%s%sAction', $model->getPhpName(), $fkModelName, ucfirst($type));
516
			$fqcn = $this->packageService->getNamespace() . '\\action\\' . $className;
517
	
518
			// generate action
519
			$action = new ActionSchema($actionNamePrefix . '-' . $type);
520
			$action->addAcl('admin');
521
			$action->setClass($fqcn);
522
			$action->setTitle(str_replace(
523
				['{model}', '{foreign}'],
524
				[$model->getOriginCommonName(), $foreign->getoriginCommonName()],
525
				$titles[$type])
526
			);
527
			$module->addAction($action);
528
	
529
			// generate class
530
			$generator = $generators[$type];
531
			$class = $generator->generate(new PhpClass($fqcn), $model, $foreign, $middle);
532
			$this->codegenService->dumpStruct($class, true);
533
		}
534
	}
535
536
}
537