Completed
Push — master ( 98cd2e...56265b )
by Thomas
09:01
created

GenerateSerializerCommand::execute()   B

Complexity

Conditions 4
Paths 4

Size

Total Lines 25
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 25
rs 8.5806
cc 4
eloc 13
nc 4
nop 2
1
<?php
2
namespace keeko\tools\command;
3
4
use gossi\codegen\model\PhpClass;
5
use gossi\codegen\model\PhpMethod;
6
use gossi\codegen\model\PhpProperty;
7
use keeko\tools\generator\serializer\base\ModelSerializerTraitGenerator;
8
use keeko\tools\helpers\QuestionHelperTrait;
9
use phootwork\file\File;
10
use Symfony\Component\Console\Input\InputArgument;
11
use Symfony\Component\Console\Input\InputInterface;
12
use Symfony\Component\Console\Input\InputOption;
13
use Symfony\Component\Console\Output\OutputInterface;
14
use Symfony\Component\Console\Question\ConfirmationQuestion;
15
use Symfony\Component\Console\Question\Question;
16
17
class GenerateSerializerCommand extends AbstractGenerateCommand {
18
19
	use QuestionHelperTrait;
20
	
21
	private $twig;
22
23
	protected function configure() {
24
		$this
25
			->setName('generate:serializer')
26
			->setDescription('Generates a serializer')
27
			->addArgument(
28
				'name',
29
				InputArgument::OPTIONAL,
30
				'The name of the action for which the serializer should be generated.'
31
			)
32
			->addOption(
33
				'model',
34
				'm',
35
				InputOption::VALUE_OPTIONAL,
36
				'The model for which the serializer should be generated, when there is no name argument (if ommited all models will be generated)'
37
			)
38
		;
39
		
40
		$this->configureGenerateOptions();
41
		
42
		parent::configure();
43
	}
44
45
	protected function initialize(InputInterface $input, OutputInterface $output) {
46
		parent::initialize($input, $output);
47
48
		$loader = new \Twig_Loader_Filesystem($this->service->getConfig()->getTemplateRoot() . '/serializer');
49
		$this->twig = new \Twig_Environment($loader);
50
	}
51
52
	/**
53
	 * Checks whether actions can be generated at all by reading composer.json and verify
54
	 * all required information are available
55
	 */
56
	private function preCheck() {
57
		$module = $this->packageService->getModule();
58
		if ($module === null) {
59
			throw new \DomainException('No module definition found in composer.json - please run `keeko init`.');
60
		}
61
	}
62
	
63
	protected function interact(InputInterface $input, OutputInterface $output) {
64
		$this->preCheck();
65
		
66
		// check if the dialog can be skipped
67
		$name = $input->getArgument('name');
68
		$model = $input->getOption('model');
69
		
70
		if ($model !== null) {
71
			return;
72
		} else if ($name !== null) {
73
			$generateModel = false;
74
		} else {
75
			$modelQuestion = new ConfirmationQuestion('Do you want to generate a serializer based off a model?');
76
			$generateModel = $this->askConfirmation($modelQuestion);
77
		}
78
		
79
		// ask questions for a model
80
		if ($generateModel) {
81
			$schema = str_replace(getcwd(), '', $this->modelService->getSchema());
82
			$allQuestion = new ConfirmationQuestion(sprintf('For all models in the schema (%s)?', $schema));
83
			$allModels = $this->askConfirmation($allQuestion);
84
85
			if (!$allModels) {
86
				$modelQuestion = new Question('Which model');
87
				$modelQuestion->setAutocompleterValues($this->modelService->getModelNames());
88
				$model = $this->askQuestion($modelQuestion);
89
				$input->setOption('model', $model);
90
			}
91
		} 
92
		
93
		// ask for which action
94
		else {
95
			$names = [];
96
			$module = $this->packageService->getModule();
97
			foreach ($module->getActionNames() as $name) {
98
				$names[] = $name;
99
			}
100
			
101
			$actionQuestion = new Question('Which action');
102
			$actionQuestion->setAutocompleterValues($names);
103
			$name = $this->askQuestion($actionQuestion);
104
			$input->setArgument('name', $name);
105
		}
106
	}
107
108
	protected function execute(InputInterface $input, OutputInterface $output) {
109
		$this->preCheck();
110
		
111
		$name = $input->getArgument('name');
112
		$model = $input->getOption('model');
113
114
		// only a specific action
115
		if ($name) {
116
			$this->generateAction($name);
117
		}
118
119
		// create action(s) from a model
120
		else if ($model) {
121
			$this->generateModel($model);
122
		}
123
124
		// anyway, generate all models
125
		else {
126
			foreach ($this->modelService->getModels() as $model) {
127
				$modelName = $model->getOriginCommonName();
128
				$input->setOption('model', $modelName);
129
				$this->generateModel($modelName);
130
			}
131
		}
132
	}
133
134
	private function generateModel($modelName) {
135
		$this->logger->info('Generate Serializer from Model: ' . $modelName);
136
		$model = $this->modelService->getModel($modelName);
137
138
		// trait
139
		$generator = new ModelSerializerTraitGenerator($this->service);
140
		$trait = $generator->generate($model);
1 ignored issue
show
Bug introduced by
It seems like $model defined by $this->modelService->getModel($modelName) on line 136 can be null; however, keeko\tools\generator\se...itGenerator::generate() 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...
141
		$this->codegenService->dumpStruct($trait, true);
142
		
143
		// class
144
		$serializer = new PhpClass(sprintf('%s\\serializer\\%sSerializer', $this->packageService->getNamespace(), $model->getPhpName()));
145
		$file = new File($this->codegenService->getFilename($serializer));
146
147
		// load from file if already exists
148
		if ($file->exists()) {
149
			$serializer = PhpClass::fromFile($file->getPathname());
150
		}
151
		
152
		// generate stub if not
153
		else {
154
			$serializer->setParentClassName('AbstractSerializer');
155
			$serializer->addUseStatement('keeko\\framework\\model\\AbstractSerializer');
156
		}
157
		
158
		// add serializer trait and write
159
		$serializer->addTrait($trait);
160
		$this->codegenService->dumpStruct($serializer, true);
161
		
162
		// add serializer + APIModelInterface on the model
163
		$class = new PhpClass(str_replace('\\\\', '\\', $model->getNamespace() . '\\' . $model->getPhpName()));
164
		$file = new File($this->codegenService->getFilename($class));
165
		if ($file->exists()) {
166
			$class = PhpClass::fromFile($this->codegenService->getFilename($class));
167
			$class
168
				->addUseStatement($serializer->getQualifiedName())
169
				->addUseStatement('keeko\\framework\\model\\ApiModelInterface')
170
				->addInterface('ApiModelInterface')
171
				->setProperty(PhpProperty::create('serializer')
172
					->setStatic(true)
173
					->setVisibility('private')
174
				)
175
				->setMethod(PhpMethod::create('getSerializer')
176
					->setStatic(true)
177
					->setBody($this->twig->render('get-serializer.twig', [
178
						'class' => $serializer->getName()
179
					]))
180
				)
181
			;
182
		
183
			$this->codegenService->dumpStruct($class, true);
184
		}	
185
	}
186
	
187
	/**
188
	 * Generates an action.
189
	 *  
190
	 * @param string $actionName
191
	 */
192
	private function generateAction($actionName) {
193
		$this->logger->info('Generate Serializer for action: ' . $actionName);
194
		
195
		
196
	}
197
	
198
	
199
200
}
201