Completed
Push — master ( 0f383e...0534bb )
by Viacheslav
19:15 queued 09:17
created

TypeBuilder::processArrayType()   A

Complexity

Conditions 6
Paths 18

Size

Total Lines 24
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 6.288

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 6
eloc 18
nc 18
nop 0
dl 0
loc 24
ccs 12
cts 15
cp 0.8
crap 6.288
rs 9.0444
c 1
b 0
f 0
1
<?php
2
3
namespace Swaggest\PhpCodeBuilder\JsonSchema;
4
5
6
use Swaggest\JsonSchema\Constraint\Type;
7
use Swaggest\JsonSchema\Schema;
8
use Swaggest\PhpCodeBuilder\PhpAnyType;
9
use Swaggest\PhpCodeBuilder\PhpStdType;
10
use Swaggest\PhpCodeBuilder\Types\ArrayOf;
11
use Swaggest\PhpCodeBuilder\Types\OrType;
12
13
class TypeBuilder
14
{
15
    /** @var Schema */
16
    private $schema;
17
    /** @var string */
18
    private $path;
19
    /** @var PhpBuilder */
20
    private $phpBuilder;
21
    /** @var OrType */
22
    private $result;
23
24
    /**
25
     * TypeBuilder constructor.
26
     * @param Schema $schema
27
     * @param string $path
28
     * @param PhpBuilder $phpBuilder
29
     */
30 12
    public function __construct($schema, $path, PhpBuilder $phpBuilder)
31
    {
32 12
        $this->schema = $schema;
33 12
        $this->path = $path;
34 12
        $this->phpBuilder = $phpBuilder;
35 12
    }
36
37 12
    /**
38
     * @throws Exception
39 12
     * @throws \Swaggest\PhpCodeBuilder\Exception
40 12
     */
41 3
    private function processLogicType()
42 12
    {
43 4
        $orSchemas = null;
44 12
        if ($this->schema->allOf !== null) {
45 4
            $orSchemas = $this->schema->allOf;
46
        } elseif ($this->schema->anyOf !== null) {
47
            $orSchemas = $this->schema->anyOf;
48 12
        } elseif ($this->schema->oneOf !== null) {
49 7
            $orSchemas = $this->schema->oneOf;
50 7
        }
51
52
        if ($orSchemas !== null) {
53 12
            foreach ($orSchemas as $item) {
54
                $this->result->add($this->phpBuilder->getType($item, $this->path));
55 12
            }
56
        }
57 12
    }
58
59 12
    /**
60 12
     * @throws Exception
61 2
     * @throws \Swaggest\PhpCodeBuilder\Exception
62 2
     */
63 12
    private function processArrayType()
64 12
    {
65 12
        $schema = $this->schema;
66
67
        /** @var string $pathItems */
68
        $pathItems = Schema::names()->items;
0 ignored issues
show
Documentation Bug introduced by
It seems like Swaggest\JsonSchema\Schema::names()->items can also be of type string. However, the property $items is declared as type Swaggest\JsonSchema\Sche...a\SchemaContract[]|null. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
69
        if ($this->isSchema($schema->items)) {
70
            $items = array();
71
            $additionalItems = $schema->items;
72 12
        } elseif ($schema->items === null) { // items defaults to empty schema so everything is valid
73 12
            $items = array();
74 12
            $additionalItems = true;
75 12
        } else { // listed items
76
            $items = $schema->items;
77 12
            $additionalItems = $schema->additionalItems;
78 2
            $pathItems = Schema::names()->additionalItems;
0 ignored issues
show
Documentation Bug introduced by
It seems like Swaggest\JsonSchema\Sche...ames()->additionalItems can also be of type string. However, the property $additionalItems is declared as type Swaggest\JsonSchema\SchemaContract|boolean|null. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
79
        }
80
81
        $itemsLen = is_array($items) ? count($items) : 0;
82 12
        $index = 0;
83
        if ($index < $itemsLen) {
84 12
        } else {
85
            if ($additionalItems instanceof Schema) {
86 12
                $this->result->add(new ArrayOf($this->phpBuilder->getType($additionalItems, $this->path . '->' . $pathItems)));
87
            }
88
        }
89 12
    }
90
91 12
    private function isSchema($var)
92 4
    {
93
        return $var instanceof Schema;
94
    }
95
96
    /**
97
     * @throws Exception
98 12
     * @throws \Swaggest\PhpCodeBuilder\Exception
99 3
     */
100 3
    private function processObjectType()
101 3
    {
102
        if ($this->schema->patternProperties !== null) {
103
            foreach ($this->schema->patternProperties as $pattern => $schema) {
104
                //$this->result->add(new ArrayOf($this->phpBuilder->getType($schema, $this->path . '->' . $pattern)));
105 12
            }
106
        }
107 8
108
109 8
        if ($this->schema->additionalProperties instanceof Schema) {
110
            $this->result->add(new ArrayOf($this->phpBuilder->getType(
111 5
                $this->schema->additionalProperties,
112
                $this->path . '->' . Schema::names()->additionalProperties)
0 ignored issues
show
Bug introduced by
Are you sure Swaggest\JsonSchema\Sche...)->additionalProperties of type Swaggest\JsonSchema\SchemaContract|boolean|string can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

112
                $this->path . '->' . /** @scrutinizer ignore-type */ Schema::names()->additionalProperties)
Loading history...
113
            ));
114 6
        }
115
116
    }
117 6
118
    private function typeSwitch($type)
119
    {
120 7
        switch ($type) {
121
            case Type::INTEGER:
122
                return PhpStdType::int();
123
124
            case Type::NUMBER:
125
                return PhpStdType::float();
126
127
            case TYPE::BOOLEAN:
128 4
                return PhpStdType::bool();
129
130
            case Type::STRING:
131 2
                return PhpStdType::string();
132
133
            /*
134 7
            case Type::OBJECT:
135
                return PhpStdType::object();
136
            */
137
138
            case Type::ARR:
139
                return PhpStdType::arr();
140
141
            case Type::NULL:
142
                return PhpStdType::null();
143
144 12
            default:
145
                return null;
146 12
        }
147 10
    }
148 10
149
    /**
150 12
     * @param Schema $schema
151
     * @param string $path
152
     * @throws Exception
153
     * @throws \Swaggest\PhpCodeBuilder\Exception
154
     */
155
    private function processNamedClass($schema, $path)
156
    {
157 12
        if ($schema->properties !== null) {
158
            $class = $this->phpBuilder->getClass($schema, $path);
159 12
            $this->result->add($class);
160 12
        }
161
    }
162
163
    /**
164 12
     * @return PhpAnyType
165 4
     * @throws Exception
166
     * @throws \Swaggest\PhpCodeBuilder\Exception
167
     */
168
    public function build()
169
    {
170 12
        $this->result = new OrType();
171 12
        if ($this->schema === null) {
172 12
            throw new Exception('Null schema');
173 12
        }
174
175 12
        if ($fromRefs = $this->schema->getFromRefs()) {
176
            $this->path = $fromRefs[count($fromRefs) - 1];
177
            //$this->result->add($this->phpBuilder->getType($this->schema->ref->getData(), $this->schema->ref->ref));
178
        }
179 12
180 8
181
        $this->processNamedClass($this->schema, $this->path);
182
        $this->processLogicType();
183 12
        $this->processArrayType();
184
        $this->processObjectType();
185
186
        if (is_array($this->schema->type)) {
187
            foreach ($this->schema->type as $type) {
188
                $this->result->add($this->typeSwitch($type));
189
            }
190
        } elseif ($this->schema->type) {
191
            $this->result->add($this->typeSwitch($this->schema->type));
192
        }
193
194
        return $this->result->simplify();
195
196
    }
197
}