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\services; |
||
3 | |||
4 | use keeko\framework\schema\GeneratorDefinitionSchema; |
||
5 | use keeko\tools\command\GenerateActionCommand; |
||
6 | use keeko\tools\command\GenerateApiCommand; |
||
7 | use keeko\tools\command\GenerateDomainCommand; |
||
8 | use keeko\tools\command\GenerateEmberModelsCommand; |
||
9 | use keeko\tools\command\GenerateSerializerCommand; |
||
10 | use keeko\tools\model\ManyToManyRelationship; |
||
11 | use keeko\tools\model\OneToManyRelationship; |
||
12 | use keeko\tools\model\OneToOneRelationship; |
||
13 | use keeko\tools\model\Project; |
||
14 | use keeko\tools\model\Relationship; |
||
15 | use keeko\tools\model\Relationships; |
||
16 | use keeko\tools\model\ReverseOneToOneRelationship; |
||
17 | use phootwork\collection\ArrayList; |
||
18 | use phootwork\collection\Map; |
||
19 | use phootwork\collection\Set; |
||
20 | use phootwork\lang\Text; |
||
21 | use Propel\Generator\Builder\Util\SchemaReader; |
||
22 | use Propel\Generator\Config\GeneratorConfig; |
||
23 | use Propel\Generator\Model\Database; |
||
24 | use Propel\Generator\Model\Table; |
||
25 | |||
26 | class ModelReader { |
||
27 | |||
28 | /** @var Project */ |
||
29 | private $project; |
||
30 | |||
31 | /** @var Database */ |
||
32 | private $database; |
||
33 | |||
34 | /** @var GeneratorDefinitionSchema */ |
||
35 | private $generatorDefinition; |
||
36 | |||
37 | /** @var Map */ |
||
38 | private $relationships; |
||
39 | |||
40 | /** @var Set */ |
||
41 | private $relationshipsLoaded; |
||
42 | |||
43 | /** @var Map */ |
||
44 | private $models; |
||
45 | |||
46 | /** @var Set */ |
||
47 | private $excluded; |
||
48 | |||
49 | /** @var CommandService */ |
||
50 | private $service; |
||
51 | |||
52 | public function __construct(Project $project, CommandService $service) { |
||
53 | $this->project = $project; |
||
54 | $this->service = $service; |
||
55 | $this->relationships = new Map(); |
||
56 | $this->relationshipsLoaded = new Set(); |
||
57 | $this->generatorDefinition = $project->getGeneratorDefinition(); |
||
58 | $this->excluded = $this->loadExcludedModels(); |
||
59 | |||
60 | $this->load(); |
||
61 | } |
||
62 | |||
63 | private function loadExcludedModels() { |
||
64 | $list = new ArrayList(); |
||
65 | $command = $this->service->getCommand(); |
||
66 | if ($command instanceof GenerateActionCommand) { |
||
67 | $list = $this->generatorDefinition->getExcludedAction(); |
||
68 | } else if ($command instanceof GenerateApiCommand) { |
||
69 | $list = $this->generatorDefinition->getExcludedApi(); |
||
70 | } else if ($command instanceof GenerateDomainCommand) { |
||
71 | $list = $this->generatorDefinition->getExcludedDomain(); |
||
72 | } else if ($command instanceof GenerateEmberModelsCommand) { |
||
73 | $list = $this->generatorDefinition->getExcludedEmber(); |
||
74 | } else if ($command instanceof GenerateSerializerCommand) { |
||
75 | $list = $this->generatorDefinition->getExcludedSerializer(); |
||
76 | } |
||
77 | |||
78 | return new Set($list); |
||
79 | } |
||
80 | |||
81 | public function getExcluded() { |
||
82 | return $this->excluded; |
||
83 | } |
||
84 | |||
85 | public function getProject() { |
||
86 | return $this->project; |
||
87 | } |
||
88 | |||
89 | private function load() { |
||
90 | if ($this->project->hasSchemaFile()) { |
||
91 | $this->loadDatabase(); |
||
92 | $this->loadRelationships(); |
||
93 | } |
||
94 | } |
||
95 | |||
96 | private function loadDatabase() { |
||
0 ignored issues
–
show
|
|||
97 | if ($this->database === null) { |
||
98 | $dom = new \DOMDocument('1.0', 'UTF-8'); |
||
99 | $dom->load($this->project->getSchemaFileName()); |
||
100 | $this->includeExternalSchemas($dom); |
||
101 | |||
102 | $config = new GeneratorConfig($this->project->getRootPath()); |
||
103 | $reader = new SchemaReader($config->getConfiguredPlatform()); |
||
104 | $reader->setGeneratorConfig($config); |
||
105 | $schema = $reader->parseString($dom->saveXML(), $this->project->getSchemaFileName()); |
||
106 | $this->database = $schema->getDatabase(); |
||
107 | |||
108 | // extend excluded list with parents when using a certain behavior |
||
109 | foreach ($this->database->getTables() as $table) { |
||
110 | foreach ($table->getBehaviors() as $behavior) { |
||
111 | |||
112 | switch ($behavior->getName()) { |
||
113 | case 'concrete_inheritance': |
||
114 | $parent = $behavior->getParameter('extends'); |
||
115 | $this->excluded->add($parent); |
||
116 | $this->renameForeignKeys($table, $parent); |
||
117 | break; |
||
118 | |||
119 | case 'versionable': |
||
120 | $versionTableName = $behavior->getParameter('version_table') |
||
121 | ? $behavior->getParameter('version_table') |
||
122 | : ($table->getOriginCommonName() . '_version'); |
||
123 | |||
124 | $this->excluded->add($versionTableName); |
||
125 | break; |
||
126 | } |
||
127 | } |
||
128 | } |
||
129 | } |
||
130 | |||
131 | return $this->database; |
||
132 | } |
||
133 | |||
134 | private function renameForeignKeys(Table $table, $parent) { |
||
135 | $parent = $this->getModel($parent); |
||
136 | |||
137 | foreach ($table->getForeignKeys() as $fk) { |
||
138 | // find fk in parent |
||
139 | foreach ($parent->getForeignKeys() as $pfk) { |
||
140 | if ($pfk->getForeignTableCommonName() == $fk->getForeignTableCommonName() |
||
141 | && $pfk->getLocalColumnName() == $fk->getLocalColumnName() |
||
142 | && $pfk->getForeignColumnName() == $fk->getForeignColumnName()) { |
||
143 | |||
144 | // replace |
||
145 | $name = new Text($pfk->getName()); |
||
146 | if ($name->contains($parent->getOriginCommonName())) { |
||
147 | $name = $name->replace($parent->getOriginCommonName(), $table->getOriginCommonName()); |
||
148 | $fk->setName($name->toString()); |
||
149 | } |
||
150 | break; |
||
151 | } |
||
152 | } |
||
153 | } |
||
154 | } |
||
155 | |||
156 | private function includeExternalSchemas(\DOMDocument $dom) { |
||
157 | $databaseNode = $dom->getElementsByTagName('database')->item(0); |
||
158 | $externalSchemaNodes = $dom->getElementsByTagName('external-schema'); |
||
159 | |||
160 | while ($externalSchema = $externalSchemaNodes->item(0)) { |
||
161 | $include = $externalSchema->getAttribute('filename'); |
||
162 | $externalSchema->parentNode->removeChild($externalSchema); |
||
163 | |||
164 | if (!is_readable($include)) { |
||
165 | throw new \RuntimeException("External schema '$include' does not exist"); |
||
0 ignored issues
–
show
As per coding-style, please use concatenation or
sprintf for the variable $include instead of interpolation.
It is generally a best practice as it is often more readable to use concatenation instead of interpolation for variables inside strings. // Instead of
$x = "foo $bar $baz";
// Better use either
$x = "foo " . $bar . " " . $baz;
$x = sprintf("foo %s %s", $bar, $baz);
![]() |
|||
166 | } |
||
167 | |||
168 | $externalSchemaDom = new \DOMDocument('1.0', 'UTF-8'); |
||
169 | $externalSchemaDom->load(realpath($include)); |
||
170 | |||
171 | // The external schema may have external schemas of its own ; recurs |
||
172 | $this->includeExternalSchemas($externalSchemaDom); |
||
173 | foreach ($externalSchemaDom->getElementsByTagName('table') as $tableNode) { |
||
174 | $databaseNode->appendChild($dom->importNode($tableNode, true)); |
||
175 | } |
||
176 | } |
||
177 | } |
||
178 | |||
179 | public function getDatabase() { |
||
180 | return $this->database; |
||
181 | } |
||
182 | |||
183 | private function loadRelationships() { |
||
184 | foreach ($this->getModels() as $table) { |
||
185 | $this->loadRelationshipsForModel($table); |
||
186 | } |
||
187 | } |
||
188 | |||
189 | /** |
||
190 | * Returns all model relationships. |
||
191 | * |
||
192 | * @param Table $model |
||
193 | */ |
||
194 | private function loadRelationshipsForModel(Table $model) { |
||
195 | if ($this->relationshipsLoaded->contains($model->getName())) { |
||
196 | return; |
||
197 | } |
||
198 | |||
199 | if ($this->excluded->contains($model->getOriginCommonName())) { |
||
200 | return; |
||
201 | } |
||
202 | |||
203 | $relationships = $this->getRelationships($model); |
||
204 | $definition = $this->generatorDefinition->getRelationships($model->getOriginCommonName()); |
||
205 | |||
206 | // one-to-* relationships |
||
207 | foreach ($model->getForeignKeys() as $fk) { |
||
208 | // skip, if fk is excluded |
||
209 | if ($this->excluded->contains($fk->getForeignTable()->getOriginCommonName())) { |
||
210 | continue; |
||
211 | } |
||
212 | |||
213 | $type = Relationship::ONE_TO_MANY; |
||
214 | if ($definition->has($fk->getName())) { |
||
215 | $type = $definition->get($fk->getName()); |
||
216 | } |
||
217 | |||
218 | $foreign = $fk->getForeignTable(); |
||
219 | |||
220 | switch ($type) { |
||
221 | case Relationship::ONE_TO_ONE: |
||
222 | $relationship = new OneToOneRelationship($model, $foreign, $fk); |
||
0 ignored issues
–
show
It seems like
$foreign defined by $fk->getForeignTable() on line 218 can be null ; however, keeko\tools\model\OneToO...tionship::__construct() 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);
}
}
![]() |
|||
223 | $relationships->add($relationship); |
||
224 | |||
225 | $reverse = new ReverseOneToOneRelationship($foreign, $model, $fk); |
||
0 ignored issues
–
show
It seems like
$foreign defined by $fk->getForeignTable() on line 218 can be null ; however, keeko\tools\model\OneToO...tionship::__construct() 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);
}
}
![]() |
|||
226 | $relationship->setReverseRelationship($reverse); |
||
227 | $this->getRelationships($foreign)->add($reverse); |
||
0 ignored issues
–
show
It seems like
$foreign defined by $fk->getForeignTable() on line 218 can be null ; however, keeko\tools\services\Mod...der::getRelationships() 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);
}
}
![]() |
|||
228 | break; |
||
229 | |||
230 | case Relationship::ONE_TO_MANY: |
||
231 | $relationship = new OneToManyRelationship($foreign, $model, $fk); |
||
0 ignored issues
–
show
It seems like
$foreign defined by $fk->getForeignTable() on line 218 can be null ; however, keeko\tools\model\OneToO...tionship::__construct() 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);
}
}
![]() |
|||
232 | $this->getRelationships($foreign)->add($relationship); |
||
0 ignored issues
–
show
It seems like
$foreign defined by $fk->getForeignTable() on line 218 can be null ; however, keeko\tools\services\Mod...der::getRelationships() 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);
}
}
![]() |
|||
233 | |||
234 | $reverse = new OneToOneRelationship($model, $foreign, $fk); |
||
0 ignored issues
–
show
It seems like
$foreign defined by $fk->getForeignTable() on line 218 can be null ; however, keeko\tools\model\OneToO...tionship::__construct() 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 | $relationship->setReverseRelationship($reverse); |
||
236 | $relationships->add($reverse); |
||
237 | break; |
||
238 | } |
||
239 | } |
||
240 | |||
241 | // many-to-many relationships |
||
242 | foreach ($model->getCrossFks() as $cfk) { |
||
243 | $relationship = new ManyToManyRelationship($model, $cfk); |
||
244 | |||
245 | // skip, if fk is excluded |
||
246 | if ($this->excluded->contains($relationship->getForeign()->getOriginCommonName())) { |
||
247 | continue; |
||
248 | } |
||
249 | |||
250 | $relationships->add($relationship); |
||
251 | } |
||
252 | |||
253 | $this->relationships->set($model->getName(), $relationships); |
||
254 | $this->relationshipsLoaded->add($model->getName()); |
||
255 | |||
256 | return $relationships; |
||
257 | } |
||
258 | |||
259 | /** |
||
260 | * |
||
261 | * @param Table $model |
||
262 | * @return Relationships |
||
263 | */ |
||
264 | public function getRelationships(Table $model) { |
||
265 | if (!$this->relationships->has($model->getName())) { |
||
266 | $this->relationships->set($model->getName(), new Relationships($model)); |
||
267 | } |
||
268 | return $this->relationships->get($model->getName()); |
||
269 | } |
||
270 | |||
271 | /** |
||
272 | * Checks whether the given model exists |
||
273 | * |
||
274 | * @param String $name tableName or modelName |
||
275 | * @return boolean |
||
276 | */ |
||
277 | public function hasModel($name) { |
||
278 | return $this->getDatabase()->hasTable($this->getTableName($name), true); |
||
279 | } |
||
280 | |||
281 | /** |
||
282 | * Returns the model for the given name |
||
283 | * |
||
284 | * @param String $name modelName or tableName |
||
285 | * @return Table |
||
286 | */ |
||
287 | public function getModel($name) { |
||
288 | $tableName = $this->getTableName($name); |
||
289 | $db = $this->getDatabase(); |
||
290 | $table = $db->getTable($tableName); |
||
291 | |||
292 | return $table; |
||
293 | } |
||
294 | |||
295 | /** |
||
296 | * Returns the tableName for a given name |
||
297 | * |
||
298 | * @param String $name tableName or modelName |
||
299 | * @return String tableName |
||
300 | */ |
||
301 | public function getTableName($name) { |
||
302 | $db = $this->getDatabase(); |
||
303 | if (!Text::create($name)->startsWith($db->getTablePrefix())) { |
||
304 | $name = $db->getTablePrefix() . $name; |
||
305 | } |
||
306 | |||
307 | return $name; |
||
308 | } |
||
309 | |||
310 | /** |
||
311 | * Returns the models from the database, where table namespace matches package namespace |
||
312 | * |
||
313 | * @return Map |
||
314 | */ |
||
315 | public function getModels() { |
||
316 | if ($this->models === null) { |
||
317 | $database = $this->getDatabase(); |
||
318 | $namespace = $database->getNamespace(); |
||
319 | |||
320 | $this->models = new Map(); |
||
321 | |||
322 | foreach ($database->getTables() as $table) { |
||
323 | if (!$table->isCrossRef() |
||
324 | && $table->getNamespace() == $namespace |
||
325 | && !$this->excluded->contains($table->getOriginCommonName())) { |
||
326 | $this->models->set($table->getOriginCommonName(), $table); |
||
327 | } |
||
328 | } |
||
329 | } |
||
330 | |||
331 | return $this->models; |
||
332 | } |
||
333 | |||
334 | /** |
||
335 | * Returns all model names |
||
336 | * |
||
337 | * @return Set |
||
338 | */ |
||
339 | public function getModelNames() { |
||
340 | return $this->getModels()->keys(); |
||
341 | } |
||
342 | } |
Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a
@return
annotation as described here.