generateRelationshipAction()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 9
rs 9.6666
c 0
b 0
f 0
ccs 6
cts 6
cp 1
cc 1
eloc 5
nc 1
nop 2
crap 1
1
<?php
2
namespace keeko\tools\command;
3
4
use keeko\framework\schema\ActionSchema;
5
use keeko\tools\generator\action\SkeletonActionGenerator;
6
use keeko\tools\generator\Types;
7
use keeko\tools\helpers\ActionCommandHelperTrait;
8
use keeko\tools\model\Relationship;
9
use keeko\tools\ui\ActionUI;
10
use phootwork\lang\Text;
11
use Propel\Generator\Model\Table;
12
use Symfony\Component\Console\Input\InputArgument;
13
use Symfony\Component\Console\Input\InputInterface;
14
use Symfony\Component\Console\Input\InputOption;
15
use Symfony\Component\Console\Output\OutputInterface;
16
17
class GenerateActionCommand extends AbstractKeekoCommand {
18
19
	use ActionCommandHelperTrait;
20
21
	protected function configure() {
22
		$this
23
			->setName('generate:action')
24
			->setDescription('Generates an action')
25 20
			->addArgument(
26 20
				'name',
27 20
				InputArgument::OPTIONAL,
28 20
				'The name of the action, which should be generated. Typically in the form %nomen%-%verb% (e.g. user-create)'
29 20
			)
30 20
			->addOption(
31 20
				'classname',
32
				'c',
33 20
				InputOption::VALUE_OPTIONAL,
34 20
				'The class name (If ommited, class name will be guessed from action name)',
35 20
				null
36 20
			)
37 20
			->addOption(
38 20
				'model',
39
				'm',
40 20
				InputOption::VALUE_OPTIONAL,
41 20
				'The model for which the actions should be generated (if ommited all models will be generated)'
42 20
			)
43 20
			->addOption(
44 20
				'title',
45
				'',
46 20
				InputOption::VALUE_OPTIONAL,
47 20
				'The title for the generated option'
48 20
			)
49 20
			->addOption(
50 20
				'acl',
51
				'',
52 20
				InputOption::VALUE_IS_ARRAY | InputOption::VALUE_OPTIONAL,
53 20
				'The acl\'s for this action (Options are: guest, user, admin)'
54 20
			)
55 20
		;
56 20
57
		$this->configureGenerateOptions();
58 20
59 20
		parent::configure();
60 20
	}
61 20
62
	protected function initialize(InputInterface $input, OutputInterface $output) {
63 20
		parent::initialize($input, $output);
64
	}
65
66
	/**
67
	 * Checks whether actions can be generated at all by reading composer.json and verify
68
	 * all required information are available
69
	 */
70
	private function check() {
71 1
		$module = $this->packageService->getModule();
72
		if ($module === null) {
73 20
			throw new \DomainException('No module definition found in composer.json - please run `keeko init`.');
74
		}
75 20
	}
76 20
77
	protected function interact(InputInterface $input, OutputInterface $output) {
78
		$this->check();
79
80
		$ui = new ActionUI($this);
81
		$ui->show();
82 10
	}
83 10
84 10
	protected function execute(InputInterface $input, OutputInterface $output) {
85 1
		$this->check();
86 4
87 9
		$name = $input->getArgument('name');
88
		$modelName = $input->getOption('model');
89
90
		// generate a skeleton action (or model, if action name belongs to a model)
91
		if ($name) {
92
			// stop if action belongs to a model ...
93
			$action = $this->getAction($name);
94
			if ($this->modelService->isModelAction($action)) {
95
				throw new \RuntimeException(sprintf('The action (%s) belongs to a model', $name));
96
			}
97
98
			// ... anyway generate a skeleton action
99
			$this->generateSkeleton($name);
100
		}
101
102
		// generate an action for a specific model
103
		else if ($modelName) {
104
			if (!$this->modelService->hasModel($modelName)) {
105
				throw new \RuntimeException(sprintf('Model (%s) does not exist.', $modelName));
106
			}
107
			$this->generateModel($this->modelService->getModel($modelName));
0 ignored issues
show
Bug introduced by
It seems like $this->modelService->getModel($modelName) can be null; however, generateModel() 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...
108
		}
109
110
		// generate actions for all models
111
		else {
112
			foreach ($this->modelService->getModels() as $model) {
113
				$this->generateModel($model);
114
			}
115
		}
116
117
		$this->packageService->savePackage();
118
	}
119
120
	/**
121
	 * Generates a skeleton action
122
	 *
123
	 * @param string $actionName
124
	 */
125
	private function generateSkeleton($actionName) {
126
		$this->logger->info('Generate Skeleton Action: ' . $actionName);
127
		$input = $this->io->getInput();
128
129
		// generate action
130
		$action = $this->getAction($actionName);
131
132
		// title
133
		if (($title = $input->getOption('title')) !== null) {
134
			$action->setTitle($title);
135
		}
136
137
		if (Text::create($action->getTitle())->isEmpty()) {
138
			throw new \RuntimeException(sprintf('Cannot create action %s, because I am missing a title for it', $actionName));
139
		}
140
141
		// classname
142
		if (($classname = $input->getOption('classname')) !== null) {
143
			$action->setClass($classname);
144
		}
145
146
		if (Text::create($action->getClass())->isEmpty()) {
147
			$action->setClass($this->guessClassname($actionName));
148
		}
149
150
// 		// guess title if there is none set yet
0 ignored issues
show
Unused Code Comprehensibility introduced by
59% 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...
151
// 		if (Text::create($action->getTitle())->isEmpty()
152 10
// 				&& $this->modelService->isModelAction($action)
153 10
// 				&& $this->modelService->isCrudAction($action)) {
154
// 			$modelName = $this->modelService->getModelNameByAction($action);
155
// 			$type = $this->modelService->getOperationByAction($action);
156
// 			$action->setTitle($this->getActionTitle($modelName, $type));
157
// 		}
158
159 9
		// acl
160 9
		$action->setAcl($this->getAcl($action));
161
162
		// generate code
163 9
		$generator = new SkeletonActionGenerator($this->service);
164 3
		$class = $generator->generate($action);
165 2
		$this->codeService->dumpStruct($class, $input->getOption('force'));
166
	}
167
168 6
	/**
169 2
	 * Generates actions for a model
170 2
	 *
171
	 * @param Table $model
172
	 */
173 4
	private function generateModel(Table $model) {
174 3
		$this->logger->info('Generate Actions from Model: ' . $model->getOriginCommonName());
175 3
176 2
		// generate action type(s)
177 2
		foreach (Types::getModelTypes($model) as $type) {
178 2
			$this->generateModelAction($model, $type);
179 1
		}
180
181 3
		// generate relationship actions
182
		if (!$model->isReadOnly()) {
183
			$relationships = $this->modelService->getRelationships($model);
184
			foreach ($relationships->getAll() as $relationship) {
185 1
				foreach (Types::getRelationshipTypes($relationship) as $type) {
186 1
					$this->generateRelationshipAction($relationship, $type);
187 1
				}
188
			}
189
		}
190 8
	}
191 8
192
	/**
193 5
	 * Generates a model action
194 5
	 *
195 5
	 * @param Table $model
196 5
	 * @param string $type
197 5
	 */
198 1
	private function generateModelAction(Table $model, $type) {
199 1
		// generate action
200 4
		$action = $this->generateAction($model, $type);
201
202
		// generate class
203 5
		$generator = $this->factory->createModelActionGenerator($type);
204 5
		$class = $generator->generate($action);
205 5
		$this->codeService->dumpStruct($class, true);
206 5
	}
207 5
208 5
	/**
209 4
	 * Generates a relationship action
210 5
	 *
211 5
	 * @param Relationship $relationship
212 5
	 * @param string $type
213
	 */
214 5
	private function generateRelationshipAction(Relationship $relationship, $type) {
215 5
		// generate action
216
		$action = $this->generateAction($relationship, $type);
217 4
218
		// generate class
219 4
		$generator = $this->factory->createRelationshipActionGenerator($type, $relationship);
220 3
		$class = $generator->generate($action, $relationship);
221
		$this->codeService->dumpStruct($class, true);
222 4
	}
223 4
224 4
	/**
225 4
	 * Generates an action
226 4
	 *
227
	 * @param Table|Relationship $object
228
	 * @param string $type
229
	 * @return ActionSchema
230
	 */
231
	private function generateAction($object, $type) {
232
		// generators
233
		$nameGenerator = $this->factory->getActionNameGenerator();
234
		$classNameGenerator = $this->factory->getActionClassNameGenerator();
235
		$titleGenerator = $this->factory->getActionTitleGenerator();
236
237 8
		// generate action
238 8
		$action = $this->getAction($nameGenerator->generate($type, $object));
239 8
		$action->setClass($classNameGenerator->generate($type, $object));
240
		$action->setTitle($titleGenerator->generate($type, $object));
241
		$action->addAcl('admin');
242 8
243
		return $action;
244 8
	}
245
}
246