• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

onmoon / openapi-server-bundle / 15887241442

25 Jun 2025 09:09PM UTC coverage: 81.18% (+0.09%) from 81.095%
15887241442

push

github

web-flow
Fix minimum versions install (#196) (#197)

* Fix minimum versions install (#196)

* Update dependencies (#195)

* update dependencies

* update sspat/reserved-words in order to use last thecodingmachine/safe

* update cebe/php-openapi

* remove usage of Safe/sprintf, Safe/substr

* fixing phpstan errors

* fixing phpstan errors

* fixing psalm errors

* tests

* tests

* tests

* downgrade cebe/php-openapi

* Revert "downgrade cebe/php-openapi"

This reverts commit ca5992ad0.

* Add PHP 8.3 and 8.4 support and update dependencies

* add security scheme

* Revert "add security scheme"

This reverts commit a1772c9c5.

* update devizzent/cebe-php-openapi

* csfix

---------

Co-authored-by: innerfly <you@example.com>

* fix

* fix errors

* fix cs

* fix package min version

* fix min package version

* fix min ver

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* remove override attr

* fix

---------

Co-authored-by: Vladimir <v.sukhoff@gmail.com>
Co-authored-by: innerfly <you@example.com>
Co-authored-by: Patrik Foldes <pf@csgo.com>

* fix code coverage regression

* update readme

---------

Co-authored-by: Vladimir <v.sukhoff@gmail.com>
Co-authored-by: innerfly <you@example.com>
Co-authored-by: Patrik Foldes <pf@csgo.com>

18 of 22 new or added lines in 5 files covered. (81.82%)

1 existing line in 1 file now uncovered.

1376 of 1695 relevant lines covered (81.18%)

3.83 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/CodeGenerator/PhpParserGenerators/DtoCodeGenerator.php
1
<?php
2

3
declare(strict_types=1);
4

5
namespace OnMoon\OpenApiServerBundle\CodeGenerator\PhpParserGenerators;
6

7
use Exception;
8
use OnMoon\OpenApiServerBundle\CodeGenerator\Definitions\DtoDefinition;
9
use OnMoon\OpenApiServerBundle\CodeGenerator\Definitions\GeneratedFileDefinition;
10
use OnMoon\OpenApiServerBundle\CodeGenerator\Definitions\PropertyDefinition;
11
use PhpParser\Builder;
12
use PhpParser\Builder\Method;
13
use PhpParser\Builder\Param;
14
use PhpParser\Builder\Property;
15
use PhpParser\Node\Arg;
16
use PhpParser\Node\Expr;
17
use PhpParser\Node\Expr\Array_;
18
use PhpParser\Node\Expr\ArrayDimFetch;
19
use PhpParser\Node\Expr\ArrayItem;
20
use PhpParser\Node\Expr\ArrowFunction;
21
use PhpParser\Node\Expr\Assign;
22
use PhpParser\Node\Expr\BinaryOp\Identical;
23
use PhpParser\Node\Expr\MethodCall;
24
use PhpParser\Node\Expr\New_;
25
use PhpParser\Node\Expr\PropertyFetch;
26
use PhpParser\Node\Expr\StaticCall;
27
use PhpParser\Node\Expr\Ternary;
28
use PhpParser\Node\Expr\Variable;
29
use PhpParser\Node\Name;
30
use PhpParser\Node\Param as Param_;
31
use PhpParser\Node\Scalar\String_;
32
use PhpParser\Node\Stmt\Expression;
33
use PhpParser\Node\Stmt\Return_;
34

35
use function array_map;
36
use function count;
37
use function sprintf;
38

39
final class DtoCodeGenerator extends CodeGenerator
40
{
41
    public function generate(DtoDefinition $definition): GeneratedFileDefinition
42
    {
43
        $fileBuilder = new FileBuilder($definition);
×
44

45
        $classBuilder = $this
×
46
            ->factory
×
47
            ->class($fileBuilder->getReference($definition))
×
48
            ->makeFinal()
×
49
            ->setDocComment(sprintf(self::AUTOGENERATED_WARNING, 'class'));
×
50

51
        $implements = $definition->getImplements();
×
52
        if ($implements !== null) {
×
53
            $classBuilder->implement($fileBuilder->getReference($implements));
×
54
        }
55

56
        $classBuilder->addStmts($this->generateProperties($fileBuilder, $definition));
×
57
        $classBuilder->addStmts($this->generateConstructor($fileBuilder, $definition));
×
58
        $classBuilder->addStmts($this->generateGetters($fileBuilder, $definition));
×
59
        $classBuilder->addStmts($this->generateSetters($fileBuilder, $definition));
×
60
        $classBuilder->addStmt($this->generateToArray($fileBuilder, $definition));
×
61
        $classBuilder->addStmt($this->generateFromArray($fileBuilder, $definition));
×
62

63
        $fileBuilder = $fileBuilder->addStmt($classBuilder);
×
64

65
        return new GeneratedFileDefinition(
×
66
            $definition,
×
67
            $this->printFile($fileBuilder)
×
68
        );
×
69
    }
70

71
    /** @return Builder[] */
72
    private function generateProperties(FileBuilder $builder, DtoDefinition $definition): array
73
    {
74
        $properties = [];
×
75
        foreach ($definition->getProperties() as $property) {
×
76
            $properties[] = $this->generateClassProperty($builder, $property);
×
77
        }
78

79
        return $properties;
×
80
    }
81

82
    /** @return Builder[] */
83
    private function generateGetters(FileBuilder $builder, DtoDefinition $definition): array
84
    {
85
        $properties = [];
×
86
        foreach ($definition->getProperties() as $property) {
×
87
            if (! $property->hasGetter()) {
×
88
                continue;
×
89
            }
90

91
            $properties[] = $this->generateGetter($builder, $property);
×
92
        }
93

94
        return $properties;
×
95
    }
96

97
    /** @return Builder[] */
98
    private function generateSetters(FileBuilder $builder, DtoDefinition $definition): array
99
    {
100
        $properties = [];
×
101
        foreach ($definition->getProperties() as $property) {
×
102
            if (! $property->hasSetter()) {
×
103
                continue;
×
104
            }
105

106
            $properties[] = $this->generateSetter($builder, $property);
×
107
        }
108

109
        return $properties;
×
110
    }
111

112
    /** @return Builder[] */
113
    private function generateConstructor(FileBuilder $builder, DtoDefinition $definition): array
114
    {
115
        $constructorBuilder = $this->factory->method('__construct')->makePublic();
×
116
        $constructorDocs    = [];
×
117
        $constructorEmpty   = true;
×
118

119
        foreach ($definition->getProperties() as $property) {
×
120
            if (! $property->isInConstructor()) {
×
121
                continue;
×
122
            }
123

124
            $constructorEmpty = false;
×
125
            $constructorBuilder
×
126
                ->addParam($this->generateMethodParameter($builder, $property))
×
127
                ->addStmt($this->getAssignmentDefinition($property->getClassPropertyName()));
×
128
            if (! $this->fullDocs && ! $property->isArray()) {
×
129
                continue;
×
130
            }
131

132
            $constructorDocs[] = sprintf(
×
133
                '@param %s $%s',
×
134
                $this->getTypeDocBlock($builder, $property),
×
135
                $property->getClassPropertyName()
×
136
            );
×
137
        }
138

139
        if ($constructorEmpty) {
×
140
            return [];
×
141
        }
142

143
        if (count($constructorDocs) > 0) {
×
144
            $constructorBuilder->setDocComment($this->getDocComment($constructorDocs));
×
145
        }
146

147
        return [$constructorBuilder];
×
148
    }
149

150
    private function generateClassProperty(FileBuilder $builder, PropertyDefinition $definition): Property
151
    {
152
        $property = $this->factory
×
153
            ->property($definition->getClassPropertyName())
×
154
            ->makePrivate();
×
155

156
        if ($definition->isNullable()) {
×
157
            $property->setDefault(null);
×
158
        }
159

160
        $property->setType($this->getTypePhp($builder, $definition));
×
161

162
        $docCommentLines = [];
×
NEW
163
        $description     = $definition->getDescription();
×
164

NEW
165
        if ($description !== null) {
×
NEW
166
            $docCommentLines[] = sprintf('%s', $description);
×
UNCOV
167
            $docCommentLines[] = '';
×
168
        }
169

170
        if ($this->fullDocs || $definition->isArray()) {
×
171
            $docCommentLines[] = sprintf(
×
172
                '@var %s $%s ',
×
173
                $this->getTypeDocBlock($builder, $definition),
×
174
                $definition->getClassPropertyName()
×
175
            );
×
176
        }
177

178
        if (count($docCommentLines) > 0) {
×
179
            $property->setDocComment($this->getDocComment($docCommentLines));
×
180
        }
181

182
        return $property;
×
183
    }
184

185
    private function generateMethodParameter(FileBuilder $builder, PropertyDefinition $definition): Param
186
    {
187
        return $this
×
188
            ->factory
×
189
            ->param($definition->getClassPropertyName())
×
190
            ->setType($this->getTypePhp($builder, $definition));
×
191
    }
192

193
    private function getAssignmentDefinition(string $name): Assign
194
    {
195
        return new Assign(
×
196
            new Variable('this->' . $name),
×
197
            new Variable($name)
×
198
        );
×
199
    }
200

201
    private function generateGetter(FileBuilder $builder, PropertyDefinition $definition): Method
202
    {
203
        $getterName = $definition->getGetterName();
×
204
        if ($getterName === null) {
×
205
            throw new Exception('Getter name should be set it hasGetter is true');
×
206
        }
207

208
        $method = $this->factory
×
209
            ->method($getterName)
×
210
            ->makePublic()
×
211
            ->setReturnType($this->getTypePhp($builder, $definition))
×
212
            ->addStmt(new Return_(new Variable('this->' . $definition->getClassPropertyName())));
×
213

214
        if ($this->fullDocs || $definition->isArray()) {
×
215
            $method->setDocComment(
×
216
                $this->getDocComment(['@return ' . $this->getTypeDocBlock($builder, $definition)])
×
217
            );
×
218
        }
219

220
        return $method;
×
221
    }
222

223
    private function generateSetter(FileBuilder $builder, PropertyDefinition $definition): Method
224
    {
225
        $setterName = $definition->getSetterName();
×
226
        if ($setterName === null) {
×
227
            throw new Exception('Setter name should be set it hasSetter is true');
×
228
        }
229

230
        $method = $this->factory
×
231
            ->method($setterName)
×
232
            ->makePublic()
×
233
            ->setReturnType('self')
×
234
            ->addParam($this->generateMethodParameter($builder, $definition))
×
235
            ->addStmt($this->getAssignmentDefinition($definition->getClassPropertyName()))
×
236
            ->addStmt(new Return_(new Variable('this')));
×
237

238
        if ($this->fullDocs || $definition->isArray()) {
×
239
            $blocks = [
×
240
                sprintf(
×
241
                    '@param %s $%s',
×
242
                    $this->getTypeDocBlock($builder, $definition),
×
243
                    $definition->getClassPropertyName()
×
244
                ),
×
245
            ];
×
246
            if ($this->fullDocs) {
×
247
                $blocks[] = '@return self';
×
248
            }
249

250
            $method->setDocComment($this->getDocComment($blocks));
×
251
        }
252

253
        return $method;
×
254
    }
255

256
    private function generateToArray(FileBuilder $builder, DtoDefinition $definition): Method
257
    {
258
        return $this
×
259
            ->factory
×
260
            ->method('toArray')
×
261
            ->makePublic()
×
262
            ->setReturnType('array')
×
263
            ->setDocComment($this->getDocComment(['@inheritDoc']))
×
264
            ->addStmt(
×
265
                new Return_(
×
266
                    new Array_(
×
267
                        array_map(
×
268
                            fn (PropertyDefinition $p) => $this->generateToArrayItem($builder, $p),
×
269
                            $definition->getProperties()
×
270
                        )
×
271
                    )
×
272
                )
×
273
            );
×
274
    }
275

276
    private function generateToArrayItem(FileBuilder $builder, PropertyDefinition $property): ArrayItem
277
    {
278
        $source = new Variable('this->' . $property->getClassPropertyName());
×
279
        $value  = $this->getConverter($builder, $property, false, $source);
×
280

281
        return new ArrayItem($value, new String_($property->getSpecPropertyName()));
×
282
    }
283

284
    private function generateFromArray(FileBuilder $builder, DtoDefinition $definition): Method
285
    {
286
        $source = new Variable('data');
×
287
        $dto    = new Variable('dto');
×
288

289
        $args    = [];
×
290
        $setters = [];
×
291

292
        foreach ($definition->getProperties() as $property) {
×
293
            $fetch = $this->generateFromArrayPropFetch($builder, $property, $source);
×
294

295
            if ($property->isInConstructor()) {
×
296
                $args[] = new Arg($fetch);
×
297
            } else {
298
                $setters[] = new Expression(new Assign(new PropertyFetch($dto, $property->getClassPropertyName()), $fetch));
×
299
            }
300
        }
301

302
        $new = new New_(new Name($builder->getReference($definition)), $args);
×
303

304
        $statements = [];
×
305
        if (count($setters) > 0) {
×
306
            $statements[] = new Expression(new Assign($dto, $new));
×
307
            foreach ($setters as $setter) {
×
308
                $statements[] = $setter;
×
309
            }
310

311
            $statements[] = new Return_($dto);
×
312
        } else {
313
            $statements[] = new Return_($new);
×
314
        }
315

316
        return $this
×
317
            ->factory
×
318
            ->method('fromArray')
×
319
            ->makePublic()
×
320
            ->makeStatic()
×
321
            ->setReturnType(new Name('self'))
×
322
            ->addParam(new Param_($source, null, new Name('array')))
×
323
            ->setDocComment($this->getDocComment(['@inheritDoc']))
×
324
            ->addStmts($statements);
×
325
    }
326

327
    private function generateFromArrayPropFetch(FileBuilder $builder, PropertyDefinition $property, Variable $sourceVar): Expr
328
    {
329
        $source = $this->generateFromArrayGetValue($property, $sourceVar);
×
330

331
        return $this->getConverter($builder, $property, true, $source);
×
332
    }
333

334
    private function generateFromArrayGetValue(PropertyDefinition $property, Variable $sourceVar): Expr
335
    {
336
        return new ArrayDimFetch($sourceVar, new String_($property->getSpecPropertyName()));
×
337
    }
338

339
    private function getConverter(FileBuilder $builder, PropertyDefinition $property, bool $deserialize, Expr $source): Expr
340
    {
341
        $converter  = null;
×
342
        $objectType = $property->getObjectTypeDefinition();
×
343
        if ($objectType !== null) {
×
344
            if ($deserialize) {
×
345
                $converter = static fn (Expr $v): Expr => new StaticCall(new Name($builder->getReference($objectType)), 'fromArray', [new Arg($v)]);
×
346
            } else {
347
                $converter = static fn (Expr $v): Expr => new MethodCall($v, 'toArray');
×
348
            }
349
        }
350

351
        if ($property->isArray() && $converter !== null) {
×
352
            $converter = fn (Expr $v): Expr => $this->factory->funcCall('array_map', [
×
353
                new ArrowFunction(
×
354
                    [
×
355
                        'static' => true,
×
356
                        'params' => [$this->factory->param('v')->getNode()],
×
357
                        'expr' => $converter(new Variable('v')),
×
358
                    ]
×
359
                ),
×
360
                $v,
×
361
            ]);
×
362
        }
363

364
        if ($property->isNullable() && $converter !== null) {
×
365
            $converter = fn (Expr $v): Expr => new Ternary(
×
366
                new Identical($this->factory->val(null), $v),
×
367
                $this->factory->val(null),
×
368
                $converter($v)
×
369
            );
×
370
        }
371

372
        if ($converter === null) {
×
373
            return $source;
×
374
        }
375

376
        return $converter($source);
×
377
    }
378
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc