This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | namespace keeko\tools\command; |
||
3 | |||
4 | use gossi\codegen\model\PhpClass; |
||
5 | use keeko\framework\schema\ActionSchema; |
||
6 | use keeko\framework\utils\NameUtils; |
||
7 | use keeko\tools\generator\responder\ApiJsonResponderGenerator; |
||
8 | use keeko\tools\generator\responder\SkeletonHtmlResponderGenerator; |
||
9 | use keeko\tools\generator\responder\SkeletonJsonResponderGenerator; |
||
10 | use keeko\tools\generator\responder\TwigHtmlResponderGenerator; |
||
11 | use keeko\tools\generator\Types; |
||
12 | use keeko\tools\helpers\QuestionHelperTrait; |
||
13 | use keeko\tools\model\Relationship; |
||
14 | use keeko\tools\ui\ResponseUI; |
||
15 | use keeko\tools\utils\NamespaceResolver; |
||
16 | use phootwork\collection\Set; |
||
17 | use phootwork\file\File; |
||
18 | use phootwork\lang\Text; |
||
19 | use Symfony\Component\Console\Input\InputArgument; |
||
20 | use Symfony\Component\Console\Input\InputInterface; |
||
21 | use Symfony\Component\Console\Input\InputOption; |
||
22 | use Symfony\Component\Console\Output\OutputInterface; |
||
23 | use Propel\Generator\Model\Table; |
||
24 | |||
25 | class GenerateResponderCommand extends AbstractKeekoCommand { |
||
26 | |||
27 | use QuestionHelperTrait; |
||
28 | |||
29 | protected $generated; |
||
30 | |||
31 | protected function configure() { |
||
32 | $this->generated = new Set(); |
||
33 | |||
34 | $this |
||
35 | ->setName('generate:responder') |
||
36 | ->setDescription('Generates code for a responder') |
||
37 | ->addArgument( |
||
38 | 'name', |
||
39 | InputArgument::OPTIONAL, |
||
40 | 'The name of the action, which should be generated. Typically in the form %nomen%-%verb% (e.g. user-create)' |
||
41 | ) |
||
42 | ->addOption( |
||
43 | 'model', |
||
44 | 'm', |
||
45 | InputOption::VALUE_OPTIONAL, |
||
46 | 'The model for which the response should be generated, when there is no name argument (if ommited all models will be generated)' |
||
47 | ) |
||
48 | ->addOption( |
||
49 | 'format', |
||
50 | '', |
||
51 | InputOption::VALUE_OPTIONAL, |
||
52 | 'The response format to create', |
||
53 | 'json' |
||
54 | ) |
||
55 | ->addOption( |
||
56 | 'template', |
||
57 | '', |
||
58 | InputOption::VALUE_OPTIONAL, |
||
59 | 'The template for the body method (blank or twig)', |
||
60 | 'blank' |
||
61 | ) |
||
62 | ->addOption( |
||
63 | 'serializer', |
||
64 | '', |
||
65 | InputOption::VALUE_OPTIONAL, |
||
66 | 'The serializer to be used for the json api template' |
||
67 | ) |
||
68 | ; |
||
69 | |||
70 | $this->configureGenerateOptions(); |
||
71 | |||
72 | parent::configure(); |
||
73 | } |
||
74 | |||
75 | /** |
||
76 | * Checks whether actions can be generated at all by reading composer.json and verify |
||
77 | * all required information are available |
||
78 | */ |
||
79 | private function check() { |
||
80 | $module = $this->packageService->getModule(); |
||
81 | if ($module === null || count($module->getActionNames()) == 0) { |
||
82 | throw new \DomainException('No action definition found in composer.json - please run `keeko generate:action`.'); |
||
83 | } |
||
84 | } |
||
85 | |||
86 | protected function interact(InputInterface $input, OutputInterface $output) { |
||
87 | $this->check(); |
||
88 | |||
89 | $ui = new ResponseUI($this); |
||
90 | $ui->show(); |
||
91 | } |
||
92 | |||
93 | protected function execute(InputInterface $input, OutputInterface $output) { |
||
94 | $this->check(); |
||
95 | |||
96 | $name = $input->getArgument('name'); |
||
97 | $modelName = $input->getOption('model'); |
||
98 | |||
99 | // generate responser for a specific action |
||
100 | if ($name) { |
||
101 | $this->generateResponder($name); |
||
102 | } |
||
103 | |||
104 | // generate a responder for a specific model |
||
105 | else if ($modelName) { |
||
106 | if (!$this->modelService->hasModel($modelName)) { |
||
107 | throw new \RuntimeException(sprintf('Model (%s) does not exist.', $modelName)); |
||
108 | } |
||
109 | $this->generateModel($this->modelService->getModel($modelName)); |
||
0 ignored issues
–
show
|
|||
110 | } |
||
111 | |||
112 | // generate responders for all models |
||
113 | else { |
||
114 | foreach ($this->modelService->getModels() as $model) { |
||
115 | $this->generateModel($model); |
||
116 | } |
||
117 | } |
||
118 | |||
119 | $this->packageService->savePackage(); |
||
120 | } |
||
121 | |||
122 | private function generateModel(Table $model) { |
||
123 | // generate responders for crud actions |
||
124 | foreach (Types::getModelTypes($model) as $type) { |
||
125 | $actionName = $this->factory->getActionNameGenerator()->generate($type, $model); |
||
126 | $this->generateResponder($actionName); |
||
127 | } |
||
128 | |||
129 | // generate responders for relationships |
||
130 | if (!$model->isReadOnly()) { |
||
131 | $relationships = $this->modelService->getRelationships($model); |
||
132 | foreach ($relationships->getAll() as $relationship) { |
||
133 | foreach (Types::getRelationshipTypes($relationship) as $type) { |
||
134 | $actionName = $this->factory->getActionNameGenerator()->generate($type, $relationship); |
||
135 | $this->generateResponder($actionName); |
||
136 | } |
||
137 | } |
||
138 | } |
||
139 | } |
||
140 | |||
141 | private function generateResponder($actionName) { |
||
142 | $this->logger->info('Generate Responder for: ' . $actionName); |
||
143 | $module = $this->packageService->getModule(); |
||
144 | |||
145 | if (!$module->hasAction($actionName)) { |
||
146 | throw new \RuntimeException(sprintf('action (%s) not found', $actionName)); |
||
147 | } |
||
148 | |||
149 | $input = $this->io->getInput(); |
||
150 | $force = $input->getOption('force'); |
||
151 | $format = $input->getOption('format'); |
||
152 | $template = $input->getOption('template'); |
||
153 | $action = $module->getAction($actionName); |
||
154 | |||
155 | // check if relationship response |
||
156 | if (Text::create($actionName)->contains('relationship') && $format == 'json') { |
||
157 | return $this->generateRelationshipResponder($action); |
||
158 | } |
||
159 | |||
160 | // responder class name |
||
161 | if (!$action->hasResponder($format)) { |
||
162 | $namespaceGenerator = $this->factory->getNamespaceGenerator(); |
||
163 | $actionNamespace = $namespaceGenerator->getActionNamespace(); |
||
164 | $className = Text::create($action->getClass()) |
||
165 | ->replace($actionNamespace, '') |
||
166 | ->prepend($namespaceGenerator->getResponderNamespaceByFormat($format)) |
||
167 | ->toString(); |
||
168 | $className = preg_replace('/Action$/', ucwords($format) . 'Responder', $className); |
||
169 | $action->setResponder($format, $className); |
||
170 | } |
||
171 | |||
172 | // action information |
||
173 | $parsed = $this->factory->getActionNameGenerator()->parseName($actionName); |
||
174 | $type = $parsed['type']; |
||
175 | $isModel = $type && $this->modelService->hasModel($parsed['modelName']); |
||
176 | |||
177 | // find generator |
||
178 | $generator = null; |
||
179 | |||
180 | // model given and format is json |
||
181 | if ($isModel && $format == 'json') { |
||
182 | $force = true; |
||
183 | $generator = $this->factory->createModelJsonResponderGenerator($type); |
||
184 | } |
||
185 | |||
186 | // payload |
||
187 | else if ($template == 'payload') { |
||
188 | $generator = $this->factory->createPayloadResponderGenerator($format); |
||
189 | } |
||
190 | |||
191 | // json + dump |
||
192 | else if ($format == 'json' && $template == 'api') { |
||
193 | $generator = new ApiJsonResponderGenerator($this->service); |
||
194 | $generator->setSerializer($this->getSerializer()); |
||
195 | } |
||
196 | |||
197 | // blank json |
||
198 | else if ($format == 'json') { |
||
199 | $generator = new SkeletonJsonResponderGenerator($this->service); |
||
200 | } |
||
201 | |||
202 | // html + twig |
||
203 | else if ($format == 'html' && $template == 'twig') { |
||
204 | $generator = new TwigHtmlResponderGenerator($this->service); |
||
205 | |||
206 | // create twig template |
||
207 | $path = $this->project->getRootPath() . '/res/templates/' . $actionName . '.twig'; |
||
208 | $file = new File($path); |
||
209 | $file->touch(); |
||
210 | } |
||
211 | |||
212 | // blank html as default |
||
213 | else if ($format == 'html') { |
||
214 | $generator = new SkeletonHtmlResponderGenerator($this->service); |
||
215 | } |
||
216 | |||
217 | // run generation, if generator was chosen |
||
218 | if ($generator !== null) { |
||
219 | /* @var $class PhpClass */ |
||
220 | $class = $generator->generate($action); |
||
221 | |||
222 | // write to file |
||
223 | $file = $this->codeService->getFile($class); |
||
224 | $overwrite = !$file->exists() || $force; |
||
225 | $this->codeService->dumpStruct($class, $overwrite); |
||
226 | } |
||
227 | } |
||
228 | |||
229 | private function generateRelationshipResponder(ActionSchema $action) { |
||
230 | // find relationship |
||
231 | $parsed = $this->factory->getActionNameGenerator()->parseRelationship($action->getName()); |
||
232 | $model = $this->modelService->getModel($parsed['modelName']); |
||
233 | $relatedName = NameUtils::dasherize($parsed['relatedName']); |
||
234 | $relationship = $this->modelService->getRelationship($model, $relatedName); |
||
0 ignored issues
–
show
It seems like
$model defined by $this->modelService->get...l($parsed['modelName']) on line 232 can be null ; however, keeko\tools\services\Mod...vice::getRelationship() 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);
}
}
![]() |
|||
235 | |||
236 | if ($relationship === null) { |
||
237 | return; |
||
238 | } |
||
239 | |||
240 | // class name |
||
241 | $className = $this->factory->getResponderClassNameGenerator()->generateJsonRelationshipResponder($relationship); |
||
242 | $action->setResponder('json', $className); |
||
243 | |||
244 | // return if already generated |
||
245 | if ($this->generated->contains($className)) { |
||
246 | return; |
||
247 | } |
||
248 | |||
249 | // generate code |
||
250 | $generator = $this->factory->createRelationshipJsonResponderGenerator($relationship); |
||
251 | $responder = $generator->generate($action); |
||
252 | $this->codeService->dumpStruct($responder, true); |
||
253 | $this->generated->add($className); |
||
254 | } |
||
255 | |||
256 | private function getSerializer() { |
||
257 | $input = $this->io->getInput(); |
||
258 | $serializer = $input->getOption('serializer'); |
||
259 | |||
260 | if (empty($serializer)) { |
||
261 | throw new \RuntimeException('No serializer given, please pass --serializer for template'); |
||
262 | } |
||
263 | |||
264 | // check fqcn |
||
265 | $class = PhpClass::create($serializer); |
||
266 | if ($class->getQualifiedName() == $serializer) { |
||
267 | $class->setQualifiedName(NamespaceResolver::getNamespace('src/serializer', $this->package) . |
||
268 | '\\' . $serializer); |
||
269 | } |
||
270 | |||
271 | // check serializer exists |
||
272 | $file = $this->codeService->getFile($class); |
||
273 | if (!$file->exists()) { |
||
274 | $this->io->writeln(sprintf('<error>Warning:</error> Serializer <info>%s</info> does not exists, please run `keeko generate:serializer %s`', $serializer, $class->getName())); |
||
275 | } |
||
276 | |||
277 | return $class->getQualifiedName(); |
||
278 | } |
||
279 | } |
||
280 |
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: