GenerateSerializerCommand::initialize()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 6
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 4
nc 1
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\generator\serializer\ModelSerializerGenerator;
9
use keeko\tools\generator\serializer\SkeletonSerializerGenerator;
10
use keeko\tools\helpers\QuestionHelperTrait;
11
use keeko\tools\ui\SerializerUI;
12
use keeko\tools\utils\NamespaceResolver;
13
use phootwork\lang\Text;
14
use phpDocumentor\Reflection\DocBlock\Serializer;
15
use Symfony\Component\Console\Input\InputArgument;
16
use Symfony\Component\Console\Input\InputInterface;
17
use Symfony\Component\Console\Input\InputOption;
18
use Symfony\Component\Console\Output\OutputInterface;
19
use Propel\Generator\Model\Table;
20
use keeko\tools\generator\serializer\TypeInferencerGenerator;
21
22
class GenerateSerializerCommand extends AbstractKeekoCommand {
23
24
	use QuestionHelperTrait;
25
26
	private $twig;
27
28
	protected function configure() {
29
		$this
30
			->setName('generate:serializer')
31
			->setDescription('Generates a serializer')
32
			->addArgument(
33
				'name',
34
				InputArgument::OPTIONAL,
35
				'The name of the action for which the serializer should be generated.'
36
			)
37
			->addOption(
38
				'model',
39
				'm',
40
				InputOption::VALUE_OPTIONAL,
41
				'The model for which the serializer should be generated, when there is no name argument (if ommited all models will be generated)'
42
			)
43
		;
44
45
		$this->configureGenerateOptions();
46
47
		parent::configure();
48
	}
49
50
	protected function initialize(InputInterface $input, OutputInterface $output) {
51
		parent::initialize($input, $output);
52
53
		$loader = new \Twig_Loader_Filesystem($this->service->getConfig()->getTemplateRoot() . '/serializer');
54
		$this->twig = new \Twig_Environment($loader);
55
	}
56
57
	/**
58
	 * Checks whether actions can be generated at all by reading composer.json and verify
59
	 * all required information are available
60
	 */
61
	private function check() {
62
		$module = $this->packageService->getModule();
63
		if ($module === null) {
64
			throw new \DomainException('No module definition found in composer.json - please run `keeko init`.');
65
		}
66
	}
67
68
	protected function interact(InputInterface $input, OutputInterface $output) {
69
		$this->check();
70
71
		$ui = new SerializerUI($this);
72
		$ui->show();
73
	}
74
75
	protected function execute(InputInterface $input, OutputInterface $output) {
76
		$this->check();
77
78
		$name = $input->getArgument('name');
79
		$modelName = $input->getOption('model');
80
81
		// only a specific action
82
		if ($name) {
83
			$this->generateSkeleton($name);
84
		}
85
86
		// create action(s) from a model
87
		else if ($modelName) {
88
			if (!$this->modelService->hasModel($modelName)) {
89
				throw new \RuntimeException(sprintf('Model (%s) does not exist.', $modelName));
90
			}
91
			$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...
92
		}
93
94
		// anyway, generate all models
95
		else {
96
			foreach ($this->modelService->getModels() as $model) {
97
				$this->generateModel($model);
98
			}
99
		}
100
101
		// generate type inferencer
102
		$this->generateInferencer();
103
	}
104
105
	private function generateModel(Table $model) {
106
		$this->logger->info('Generate Serializer from Model: ' . $model->getOriginCommonName());
107
108
		// generate class
109
		$generator = new ModelSerializerGenerator($this->service);
110
		$serializer = $generator->generate($model);
111
		$this->codeService->dumpStruct($serializer, true);
112
113
		// generate trait
114
		$generator = new ModelSerializerTraitGenerator($this->service);
115
		$trait = $generator->generate($model);
116
		$this->codeService->dumpStruct($trait, true);
117
118
		// add serializer + ApiModelInterface on the model
119
		$class = new PhpClass(str_replace('\\\\', '\\', $model->getNamespace() . '\\' . $model->getPhpName()));
120
		$file = $this->codeService->getFile($class);
121
		if ($file->exists()) {
122
			$class = PhpClass::fromFile($this->codeService->getFilename($class));
123
			$class
124
				->addUseStatement($serializer->getQualifiedName())
125
				->addUseStatement('keeko\\framework\\model\\ApiModelInterface')
126
				->addInterface('ApiModelInterface')
127
				->setProperty(PhpProperty::create('serializer')
128
					->setStatic(true)
129
					->setVisibility('private')
130
				)
131
				->setMethod(PhpMethod::create('getSerializer')
132
					->setStatic(true)
133
					->setType($serializer->getName())
134
					->setBody($this->twig->render('get-serializer.twig', [
135
						'class' => $serializer->getName()
136
					]))
137
				)
138
			;
139
140
			$this->codeService->dumpStruct($class, true);
141
		}
142
	}
143
144
	/**
145
	 * Generates a skeleton serializer
146
	 *
147
	 * @param string $name
148
	 */
149
	private function generateSkeleton($name) {
150
		$this->logger->info('Generate Skeleton Serializer: ' . $name);
151
		$input = $this->io->getInput();
152
153
		$className = NamespaceResolver::getNamespace('src/serializer', $this->package) . '\\' . $name;
154
155
		if (!Text::create($className)->endsWith('Serializer')) {
156
			$className .= 'Serializer';
157
		}
158
159
		// generate code
160
		$generator = new SkeletonSerializerGenerator($this->service);
161
		$class = $generator->generate($className);
162
		$this->codeService->dumpStruct($class, $input->getOption('force'));
163
	}
164
165
	private function generateInferencer() {
166
		$generator = new TypeInferencerGenerator($this->service);
167
		$class = $generator->generate();
168
		$this->codeService->dumpStruct($class, true);
169
	}
170
171
}
172