Completed
Push — master ( d6c5c0...118f52 )
by Thomas
04:57
created

GenerateActionCommand::generateAction()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 14
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 1

Importance

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