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

DoclerLabs / api-client-generator / 7259428899

19 Dec 2023 08:47AM UTC coverage: 89.733% (-0.3%) from 90.043%
7259428899

push

github

web-flow
Merge pull request #102 from DoclerLabs/generator-php-8

generator php 8

355 of 381 new or added lines in 40 files covered. (93.18%)

6 existing lines in 4 files now uncovered.

2657 of 2961 relevant lines covered (89.73%)

3.35 hits per line

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

71.13
/src/Input/Factory/FieldFactory.php
1
<?php
2

3
declare(strict_types=1);
4

5
namespace DoclerLabs\ApiClientGenerator\Input\Factory;
6

7
use cebe\openapi\spec\Parameter;
8
use cebe\openapi\spec\Reference;
9
use cebe\openapi\SpecObjectInterface;
10
use DoclerLabs\ApiClientGenerator\Ast\PhpVersion;
11
use DoclerLabs\ApiClientGenerator\Entity\Constraint\ConstraintCollection;
12
use DoclerLabs\ApiClientGenerator\Entity\Constraint\MaximumConstraint;
13
use DoclerLabs\ApiClientGenerator\Entity\Constraint\MaxItemsConstraint;
14
use DoclerLabs\ApiClientGenerator\Entity\Constraint\MaxLengthConstraint;
15
use DoclerLabs\ApiClientGenerator\Entity\Constraint\MinimumConstraint;
16
use DoclerLabs\ApiClientGenerator\Entity\Constraint\MinItemsConstraint;
17
use DoclerLabs\ApiClientGenerator\Entity\Constraint\MinLengthConstraint;
18
use DoclerLabs\ApiClientGenerator\Entity\Constraint\PatternConstraint;
19
use DoclerLabs\ApiClientGenerator\Entity\Field;
20
use DoclerLabs\ApiClientGenerator\Entity\FieldType;
21
use DoclerLabs\ApiClientGenerator\Input\InvalidSpecificationException;
22
use DoclerLabs\ApiClientGenerator\Input\PhpNameValidator;
23
use DoclerLabs\ApiClientGenerator\Naming\CaseCaster;
24
use DoclerLabs\ApiClientGenerator\Naming\SchemaNaming;
25
use Throwable;
26
use UnexpectedValueException;
27

28
class FieldFactory
29
{
30
    public function __construct(private PhpNameValidator $nameValidator, private PhpVersion $phpVersion)
31
    {
32
    }
2✔
33

34
    public function create(
35
        string $operationName,
36
        string $fieldName,
37
        SpecObjectInterface $schemaOrReference,
38
        bool $required,
39
        string $referenceName = '',
40
        string $parentReferenceName = ''
41
    ): Field {
42
        try {
43
            $arrayItem            = null;
2✔
44
            $objectProperties     = [];
2✔
45
            $additionalProperties = true;
2✔
46
            $schemaReference      = $schemaOrReference;
2✔
47
            $schema               = $this->resolveReference($schemaOrReference);
2✔
48

49
            if ($referenceName !== '' && !$this->nameValidator->isValidClassName($referenceName)) {
2✔
50
                throw new InvalidSpecificationException('Invalid field reference name: ' . $referenceName);
×
51
            }
52

53
            if ($fieldName !== '' && !$this->nameValidator->isValidVariableName(CaseCaster::toCamel($fieldName))) {
2✔
54
                throw new InvalidSpecificationException('Invalid field name: ' . $fieldName);
×
55
            }
56

57
            $type = $schema->type;
2✔
58
            if (isset($schema->oneOf)) {
2✔
59
                throw new InvalidSpecificationException('oneOf keyword is not currently supported.');
×
60
            } elseif (isset($schema->allOf)) {
2✔
61
                $type = FieldType::SPEC_TYPE_OBJECT;
×
62
                if ($referenceName === '') {
×
63
                    $referenceName = SchemaNaming::getClassName($schemaReference, $fieldName);
×
64
                }
65

66
                $objectProperties = $this->mergeAllOfProperties($operationName, $schema);
×
NEW
67
                $schema           = $this->mergeAllOfAttributes($schema);
×
68
            } elseif (FieldType::isSpecificationTypeArray($type)) {
2✔
69
                $itemReferenceName = '';
2✔
70
                if ($schema->items === null) {
2✔
71
                    throw new InvalidSpecificationException('Array field does not have items specified.');
×
72
                }
73
                $sibling        = $this->resolveReference($schema->items);
2✔
74
                $itemsReference = $schema->items;
2✔
75
                if (isset($sibling->allOf) || FieldType::isSpecificationTypeObject($sibling->type)) {
2✔
76
                    $itemReferenceName = SchemaNaming::getClassName(
2✔
77
                        $itemsReference,
78
                        $operationName . ucfirst($fieldName) . 'Item'
2✔
79
                    );
80
                }
81
                $arrayItem = $this->create(
2✔
82
                    $operationName,
83
                    lcfirst($itemReferenceName),
2✔
84
                    $sibling,
85
                    true,
2✔
86
                    $itemReferenceName
87
                );
88
            } elseif (FieldType::isSpecificationTypeObject($type)) {
2✔
89
                if ($referenceName === '') {
2✔
90
                    $referenceName = SchemaNaming::getClassName(
2✔
91
                        $schemaReference,
92
                        sprintf('%s%s', ucfirst($parentReferenceName), ucfirst($fieldName))
2✔
93
                    );
94
                }
95

96
                $objectProperties = $this->mapProperties($operationName, $schema, $referenceName);
2✔
97
            }
98
            if (isset($schema->additionalProperties)) {
2✔
99
                if (is_bool($schema->additionalProperties)) {
2✔
100
                    $additionalProperties = $schema->additionalProperties;
2✔
101
                } elseif (is_object($schema->additionalProperties)) {
1✔
102
                    $warningMessage = sprintf(
1✔
103
                        'Additional properties object is not supported: %s.',
1✔
104
                        $referenceName
105
                    );
106
                    trigger_error($warningMessage, E_USER_WARNING);
1✔
107
                }
108
            }
109

110
            $fieldType = new FieldType($type, $this->phpVersion);
2✔
111
            $field     = new Field(
2✔
112
                $fieldName,
113
                $fieldType,
114
                new ConstraintCollection(
2✔
115
                    new MinimumConstraint($schema->minimum, $schema->exclusiveMinimum, $fieldType),
2✔
116
                    new MaximumConstraint($schema->maximum, $schema->exclusiveMaximum, $fieldType),
2✔
117
                    new MinLengthConstraint($schema->minLength),
2✔
118
                    new MaxLengthConstraint($schema->maxLength),
2✔
119
                    new PatternConstraint($schema->pattern),
2✔
120
                    new MinItemsConstraint($schema->minItems),
2✔
121
                    new MaxItemsConstraint($schema->maxItems)
2✔
122
                ),
123
                $referenceName,
124
                $required,
125
                (bool)$schema->nullable,
2✔
126
                $additionalProperties
127
            );
128

129
            if ($arrayItem !== null) {
2✔
130
                $field->setArrayItem($arrayItem);
2✔
131
            } elseif (!empty($objectProperties)) {
2✔
132
                $field->setObjectProperties($objectProperties);
2✔
133
            } elseif (isset($schema->enum)) {
2✔
134
                $field->setEnumValues($schema->enum);
1✔
135
            }
136

137
            if (isset($schema->format)) {
2✔
138
                $field->setFormat($schema->format);
2✔
139
            }
140

141
            if (isset($schema->default)) {
2✔
142
                $field->setDefault($schema->default);
1✔
143
            }
144

145
            return $field;
2✔
146
        } catch (Throwable $exception) {
×
147
            throw new InvalidSpecificationException(
×
148
                sprintf(
×
149
                    'Error on mapping `%s`: %s',
×
150
                    $fieldName,
151
                    $exception->getMessage()
×
152
                )
153
            );
154
        }
155
    }
156

157
    protected function mapProperties(
158
        string $operationName,
159
        SpecObjectInterface $schema,
160
        string $schemaReferenceName
161
    ): array {
162
        $fields = [];
2✔
163
        foreach ($schema->properties as $childName => $child) {
2✔
164
            $required = false;
2✔
165
            if (isset($schema->required) && is_array($schema->required)) {
2✔
166
                $required = in_array($childName, $schema->required, true);
2✔
167
            }
168
            $fields[] = $this->create($operationName, $childName, $child, $required, '', $schemaReferenceName);
2✔
169
        }
170

171
        return $fields;
2✔
172
    }
173

174
    private function resolveReference(SpecObjectInterface $schema): SpecObjectInterface
175
    {
176
        $resolved = $schema;
2✔
177
        if ($schema instanceof Reference) {
2✔
178
            $resolved = $schema->resolve();
2✔
179
        }
180

181
        if (is_array($resolved) || $resolved === null) {
2✔
182
            throw new UnexpectedValueException('Unexpected value after the reference resolution');
×
183
        }
184

185
        if ($resolved instanceof Parameter) {
2✔
186
            throw new InvalidSpecificationException('Usage of parameter inside of the schema is unexpected.');
×
187
        }
188

189
        return $resolved;
2✔
190
    }
191

192
    private function mergeAllOfProperties(string $operationName, SpecObjectInterface $schema): array
193
    {
194
        $allOfProperties = [];
×
195
        foreach ($schema->allOf as $allOfSchema) {
×
196
            if ($allOfSchema instanceof Reference) {
×
197
                $allOfSchema = $allOfSchema->resolve();
×
198
            }
199
            $allOfProperties[] = $this->mapProperties($operationName, $allOfSchema, '');
×
200
        }
201

202
        return array_merge([], ...$allOfProperties);
×
203
    }
204

205
    private function mergeAllOfAttributes(SpecObjectInterface $schema): SpecObjectInterface
206
    {
207
        foreach ($schema->allOf as $allOfSchema) {
×
208
            if ($allOfSchema instanceof Reference) {
×
209
                $allOfSchema = $allOfSchema->resolve();
×
210
            }
211

212
            if (isset($allOfSchema->nullable)) {
×
213
                $schema->nullable = $allOfSchema->nullable;
×
214
            }
215

216
            // @TODO add more attributes here later if needed
217
        }
218

219
        return $schema;
×
220
    }
221
}
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

© 2025 Coveralls, Inc