YamlConverter   F
last analyzed

Complexity

Total Complexity 94

Size/Duplication

Total Lines 471
Duplicated Lines 12.1 %

Coupling/Cohesion

Components 1
Dependencies 18

Test Coverage

Coverage 86.13%

Importance

Changes 0
Metric Value
wmc 94
lcom 1
cbo 18
dl 57
loc 471
ccs 267
cts 310
cp 0.8613
rs 1.5789
c 0
b 0
f 0

20 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 15 1
A convert() 9 9 2
A flattAttributes() 0 12 3
A flattElements() 0 12 3
B getTypes() 0 17 5
B navigate() 20 20 6
A visitTypeBase() 0 12 4
B visitElementDef() 0 23 4
A findPHPNamespace() 3 9 2
A findPHPName() 0 13 2
D visitType() 5 41 10
A visitTypeAnonymous() 0 19 3
A visitComplexType() 0 10 3
B visitSimpleType() 0 14 5
B visitBaseComplexType() 0 18 5
B handleClassExtension() 0 42 6
B visitAttribute() 5 33 5
C typeHasValue() 0 22 8
B findPHPClass() 5 22 5
C visitElement() 10 69 12

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like YamlConverter often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use YamlConverter, and based on these observations, apply Extract Interface, too.

1
<?php
2
namespace GoetasWebservices\Xsd\XsdToPhp\Jms;
3
4
use Doctrine\Common\Inflector\Inflector;
5
use Exception;
6
use GoetasWebservices\XML\XSDReader\Schema\Attribute\AttributeContainer;
7
use GoetasWebservices\XML\XSDReader\Schema\Attribute\AttributeItem;
8
use GoetasWebservices\XML\XSDReader\Schema\Element\Element;
9
use GoetasWebservices\XML\XSDReader\Schema\Element\ElementContainer;
10
use GoetasWebservices\XML\XSDReader\Schema\Element\ElementDef;
11
use GoetasWebservices\XML\XSDReader\Schema\Element\ElementItem;
12
use GoetasWebservices\XML\XSDReader\Schema\Element\ElementRef;
13
use GoetasWebservices\XML\XSDReader\Schema\Item;
14
use GoetasWebservices\XML\XSDReader\Schema\Schema;
15
use GoetasWebservices\XML\XSDReader\Schema\SchemaItem;
16
use GoetasWebservices\XML\XSDReader\Schema\Type\BaseComplexType;
17
use GoetasWebservices\XML\XSDReader\Schema\Type\ComplexType;
18
use GoetasWebservices\XML\XSDReader\Schema\Type\SimpleType;
19
use GoetasWebservices\XML\XSDReader\Schema\Type\Type;
20
use GoetasWebservices\Xsd\XsdToPhp\AbstractConverter;
21
use GoetasWebservices\Xsd\XsdToPhp\Naming\NamingStrategy;
22
23
class YamlConverter extends AbstractConverter
24
{
25
26 22
    public function __construct(NamingStrategy $namingStrategy)
27
    {
28
29 22
        parent::__construct($namingStrategy);
30
31
        $this->addAliasMap('http://www.w3.org/2001/XMLSchema', 'dateTime', function (Type $type) {
0 ignored issues
show
Unused Code introduced by
The parameter $type is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
32 3
            return "GoetasWebservices\Xsd\XsdToPhp\XMLSchema\DateTime";
33 22
        });
34
        $this->addAliasMap('http://www.w3.org/2001/XMLSchema', 'time', function (Type $type) {
0 ignored issues
show
Unused Code introduced by
The parameter $type is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
35
            return "GoetasWebservices\Xsd\XsdToPhp\XMLSchema\Time";
36 22
        });
37
        $this->addAliasMap("http://www.w3.org/2001/XMLSchema", "date", function (Type $type) {
0 ignored issues
show
Unused Code introduced by
The parameter $type is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
38
            return "DateTime<'Y-m-d'>";
39 22
        });
40 22
    }
41
42
    private $classes = [];
43
44 22 View Code Duplication
    public function convert(array $schemas)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
45
    {
46 22
        $visited = array();
47 22
        $this->classes = array();
48 22
        foreach ($schemas as $schema) {
49 22
            $this->navigate($schema, $visited);
50 22
        }
51 22
        return $this->getTypes();
52
    }
53
54 11
    private function flattAttributes(AttributeContainer $container)
55
    {
56 11
        $items = array();
57 11
        foreach ($container->getAttributes() as $attr) {
58 5
            if ($attr instanceof AttributeContainer) {
59 1
                $items = array_merge($items, $this->flattAttributes($attr));
60 1
            } else {
61 5
                $items[] = $attr;
62
            }
63 11
        }
64 11
        return $items;
65
    }
66
67 11
    private function flattElements(ElementContainer $container)
68
    {
69 11
        $items = array();
70 11
        foreach ($container->getElements() as $attr) {
71 11
            if ($attr instanceof ElementContainer) {
72 3
                $items = array_merge($items, $this->flattElements($attr));
73 3
            } else {
74 11
                $items[] = $attr;
75
            }
76 11
        }
77 11
        return $items;
78
    }
79
80
    /**
81
     *
82
     * @return PHPClass[]
83
     */
84
    public function getTypes()
85
    {
86 22
        uasort($this->classes, function ($a, $b) {
87 7
            return strcmp(key($a), key($b));
88 22
        });
89
90 22
        $ret = array();
91
92 22
        foreach ($this->classes as $definition) {
93 21
            $classname = key($definition["class"]);
94 21
            if (strpos($classname, '\\') !== false && (!isset($definition["skip"]) || !$definition["skip"])) {
95 21
                $ret[$classname] = $definition["class"];
96 21
            }
97 22
        }
98
99 22
        return $ret;
100
    }
101
102 22 View Code Duplication
    private function navigate(Schema $schema, array &$visited)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
103
    {
104 22
        if (isset($visited[spl_object_hash($schema)])) {
105
            return;
106
        }
107 22
        $visited[spl_object_hash($schema)] = true;
108
109 22
        foreach ($schema->getTypes() as $type) {
110 9
            $this->visitType($type);
111 22
        }
112 22
        foreach ($schema->getElements() as $element) {
113 14
            $this->visitElementDef($schema, $element);
114 22
        }
115
116 22
        foreach ($schema->getSchemas() as $schildSchema) {
117 22
            if (!in_array($schildSchema->getTargetNamespace(), $this->baseSchemas, true)) {
118 1
                $this->navigate($schildSchema, $visited);
119 1
            }
120 22
        }
121 22
    }
122
123 16
    private function visitTypeBase(&$class, &$data, Type $type, $name)
124
    {
125 16
        if ($type instanceof BaseComplexType) {
126 11
            $this->visitBaseComplexType($class, $data, $type, $name);
127 11
        }
128 16
        if ($type instanceof ComplexType) {
129 11
            $this->visitComplexType($class, $data, $type);
130 11
        }
131 16
        if ($type instanceof SimpleType) {
132 7
            $this->visitSimpleType($class, $data, $type, $name);
133 7
        }
134 16
    }
135
136 14
    public function &visitElementDef(Schema $schema, ElementDef $element)
137
    {
138 14
        if (!isset($this->classes[spl_object_hash($element)])) {
139 14
            $className = $this->findPHPNamespace($element) . "\\" . $this->getNamingStrategy()->getItemName($element);
140 14
            $class = array();
141 14
            $data = array();
142 14
            $ns = $className;
143 14
            $class[$ns] = &$data;
144 14
            $data["xml_root_name"] = $element->getName();
145
146 14
            if ($schema->getTargetNamespace()) {
147 13
                $data["xml_root_namespace"] = $schema->getTargetNamespace();
148 13
            }
149 14
            $this->classes[spl_object_hash($element)]["class"] = &$class;
150
151 14
            if (!$element->getType()->getName()) {
152 7
                $this->visitTypeBase($class, $data, $element->getType(), $element->getName());
153 7
            } else {
154 7
                $this->handleClassExtension($class, $data, $element->getType(), $element->getName());
155
            }
156 14
        }
157 14
        return $this->classes[spl_object_hash($element)]["class"];
158
    }
159
160 21
    private function findPHPNamespace(SchemaItem $item)
161
    {
162 21
        $schema = $item->getSchema();
163
164 21 View Code Duplication
        if (!isset($this->namespaces[$schema->getTargetNamespace()])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
165
            throw new Exception(sprintf("Can't find a PHP namespace to '%s' namespace", $schema->getTargetNamespace()));
166
        }
167 21
        return $this->namespaces[$schema->getTargetNamespace()];
168
    }
169
170
171 9
    private function findPHPName(Type $type)
172
    {
173 9
        $schema = $type->getSchema();
174
175 9
        if ($alias = $this->getTypeAlias($type, $schema)) {
176
            return $alias;
177
        }
178
179 9
        $ns = $this->findPHPNamespace($type);
180 9
        $name = $this->getNamingStrategy()->getTypeName($type);
181
182 9
        return $ns . "\\" . $name;
183
    }
184
185
186 9
    public function &visitType(Type $type, $force = false)
187
    {
188
189 9
        if (!isset($this->classes[spl_object_hash($type)])) {
190
191 9
            if ($alias = $this->getTypeAlias($type)) {
192
                $class = array();
193
                $class[$alias] = array();
194
195
                $this->classes[spl_object_hash($type)]["class"] = &$class;
196
                $this->classes[spl_object_hash($type)]["skip"] = true;
197
                return $class;
198
            }
199
200 9
            $className = $this->findPHPName($type);
201
202 9
            $class = array();
203 9
            $data = array();
204
205 9
            $class[$className] = &$data;
206
207 9
            $this->classes[spl_object_hash($type)]["class"] = &$class;
208
209 9
            $this->visitTypeBase($class, $data, $type, $type->getName());
210
211 9
            if ($type instanceof SimpleType) {
212 1
                $this->classes[spl_object_hash($type)]["skip"] = true;
213 1
                return $class;
214
            }
215
216 9
            if (!$force && ($this->isArrayType($type) || $this->isArrayNestedElement($type))) {
217 1
                $this->classes[spl_object_hash($type)]["skip"] = true;
218 1
                return $class;
219
            }
220 9 View Code Duplication
        } elseif ($force) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
221 2
            if (!($type instanceof SimpleType) && !$this->getTypeAlias($type)) {
222 2
                $this->classes[spl_object_hash($type)]["skip"] = false;
223 2
            }
224 2
        }
225 9
        return $this->classes[spl_object_hash($type)]["class"];
226
    }
227
228 3
    private function &visitTypeAnonymous(Type $type, $parentName, $parentClass)
229
    {
230 3
        $class = array();
231 3
        $data = array();
232
233 3
        $name = $this->getNamingStrategy()->getAnonymousTypeName($type, $parentName);
234
235 3
        $class[key($parentClass) . "\\" . $name] = &$data;
236
237 3
        $this->visitTypeBase($class, $data, $type, $parentName);
238 3
        if ($parentName) {
239 3
            $this->classes[spl_object_hash($type)]["class"] = &$class;
240
241 3
            if ($type instanceof SimpleType) {
242 1
                $this->classes[spl_object_hash($type)]["skip"] = true;
243 1
            }
244 3
        }
245 3
        return $class;
246
    }
247
248 11
    private function visitComplexType(&$class, &$data, ComplexType $type)
249
    {
250 11
        $schema = $type->getSchema();
251 11
        if (!isset($data["properties"])) {
252
            $data["properties"] = array();
253
        }
254 11
        foreach ($this->flattElements($type) as $element) {
255 11
            $data["properties"][$this->getNamingStrategy()->getPropertyName($element)] = $this->visitElement($class, $schema, $element);
256 11
        }
257 11
    }
258
259 7
    private function visitSimpleType(&$class, &$data, SimpleType $type, $name)
260
    {
261 7
        if ($restriction = $type->getRestriction()) {
262 7
            $parent = $restriction->getBase();
263 7
            if ($parent instanceof Type) {
264 7
                $this->handleClassExtension($class, $data, $parent, $name);
265 7
            }
266 7
        } elseif ($unions = $type->getUnions()) {
267 1
            foreach ($unions as $i => $unon) {
268 1
                $this->handleClassExtension($class, $data, $unon, $name . $i);
269 1
                break;
270 1
            }
271 1
        }
272 7
    }
273
274 11
    private function visitBaseComplexType(&$class, &$data, BaseComplexType $type, $name)
275
    {
276 11
        $parent = $type->getParent();
277 11
        if ($parent) {
278 2
            $parentType = $parent->getBase();
279 2
            if ($parentType instanceof Type) {
280 2
                $this->handleClassExtension($class, $data, $parentType, $name);
281 2
            }
282 2
        }
283
284 11
        $schema = $type->getSchema();
285 11
        if (!isset($data["properties"])) {
286 11
            $data["properties"] = array();
287 11
        }
288 11
        foreach ($this->flattAttributes($type) as $attr) {
289 5
            $data["properties"][$this->getNamingStrategy()->getPropertyName($attr)] = $this->visitAttribute($class, $schema, $attr);
290 11
        }
291 11
    }
292
293 14
    private function handleClassExtension(&$class, &$data, Type $type, $parentName)
294
    {
295 14
        if ($alias = $this->getTypeAlias($type)) {
296
297
298 13
            $property = array();
299 13
            $property["expose"] = true;
300 13
            $property["xml_value"] = true;
301 13
            $property["access_type"] = "public_method";
302 13
            $property["accessor"]["getter"] = "value";
303 13
            $property["accessor"]["setter"] = "value";
304 13
            $property["type"] = $alias;
305
306 13
            $data["properties"]["__value"] = $property;
307
308
309 13
        } else {
310 2
            $extension = $this->visitType($type, true);
311
312 2
            if (isset($extension['properties']['__value']) && count($extension['properties']) === 1) {
313
                $data["properties"]["__value"] = $extension['properties']['__value'];
314
            } else {
315 2
                if ($type instanceof SimpleType) { // @todo ?? basta come controllo?
316 1
                    $property = array();
317 1
                    $property["expose"] = true;
318 1
                    $property["xml_value"] = true;
319 1
                    $property["access_type"] = "public_method";
320 1
                    $property["accessor"]["getter"] = "value";
321 1
                    $property["accessor"]["setter"] = "value";
322
323 1
                    if ($valueProp = $this->typeHasValue($type, $class, $parentName)) {
324 1
                        $property["type"] = $valueProp;
325 1
                    } else {
326 1
                        $property["type"] = key($extension);
327
                    }
328
329 1
                    $data["properties"]["__value"] = $property;
330
331 1
                }
332
            }
333
        }
334 14
    }
335
336 5
    private function visitAttribute(&$class, Schema $schema, AttributeItem $attribute)
337
    {
338 5
        $property = array();
339 5
        $property["expose"] = true;
340 5
        $property["access_type"] = "public_method";
341 5
        $property["serialized_name"] = $attribute->getName();
342
343 5
        $property["accessor"]["getter"] = "get" . Inflector::classify($attribute->getName());
344 5
        $property["accessor"]["setter"] = "set" . Inflector::classify($attribute->getName());
345
346 5
        $property["xml_attribute"] = true;
347
348 5
        if ($alias = $this->getTypeAlias($attribute)) {
349
            $property["type"] = $alias;
350
351 5
        } elseif ($itemOfArray = $this->isArrayType($attribute->getType())) {
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface GoetasWebservices\XML\XS...Attribute\AttributeItem as the method getType() does only exist in the following implementations of said interface: GoetasWebservices\XML\XS...ema\Attribute\Attribute, GoetasWebservices\XML\XS...\Attribute\AttributeDef, GoetasWebservices\XML\XS...\Attribute\AttributeRef.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
352
353 View Code Duplication
            if ($valueProp = $this->typeHasValue($itemOfArray, $class, 'xx')) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
354
                $property["type"] = "GoetasWebservices\Xsd\XsdToPhp\Jms\SimpleListOf<" . $valueProp . ">";
355
            } else {
356
                $property["type"] = "GoetasWebservices\Xsd\XsdToPhp\Jms\SimpleListOf<" . $this->findPHPName($itemOfArray) . ">";
357
            }
358
359
            $property["xml_list"]["inline"] = false;
360
            $property["xml_list"]["entry_name"] = $itemOfArray->getName();
361
            if ($schema->getTargetNamespace()) {
362
                $property["xml_list"]["entry_namespace"] = $schema->getTargetNamespace();
363
            }
364
        } else {
365 5
            $property["type"] = $this->findPHPClass($class, $attribute);
0 ignored issues
show
Documentation introduced by
$attribute is of type object<GoetasWebservices...ttribute\AttributeItem>, but the function expects a object<GoetasWebservices...\XSDReader\Schema\Item>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
366
        }
367 5
        return $property;
368
    }
369
370 3
    private function typeHasValue(Type $type, $parentClass, $name)
371
    {
372 3
        $collected = array();
0 ignored issues
show
Unused Code introduced by
$collected is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
373
        do {
374 3
            if ($alias = $this->getTypeAlias($type)) {
375
                return $alias;
376
            } else {
377
378 3
                if ($type->getName()) {
379 1
                    $parentClass = $this->visitType($type);
380 1
                } else {
381 3
                    $parentClass = $this->visitTypeAnonymous($type, $name, $parentClass);
382
                }
383 3
                $props = reset($parentClass);
384 3
                if (isset($props['properties']['__value']) && count($props['properties']) === 1) {
385 2
                    return $props['properties']['__value']['type'];
386
                }
387
            }
388 3
        } while (method_exists($type, 'getRestriction') && $type->getRestriction() && $type = $type->getRestriction()->getBase());
389
390 3
        return false;
391
    }
392
393
    /**
394
     *
395
     * @param PHPClass $class
396
     * @param Schema $schema
397
     * @param Element $element
398
     * @param boolean $arrayize
399
     * @return \GoetasWebservices\Xsd\XsdToPhp\Structure\PHPProperty
400
     */
401 11
    private function visitElement(&$class, Schema $schema, ElementItem $element, $arrayize = true)
402
    {
403 11
        $property = array();
404 11
        $property["expose"] = true;
405 11
        $property["access_type"] = "public_method";
406 11
        $property["serialized_name"] = $element->getName();
407
408 11
        if ($element->getSchema()->getTargetNamespace()) {
409 2
            $property["xml_element"]["namespace"] = $element->getSchema()->getTargetNamespace();
410 2
        }
411
412 11
        $property["accessor"]["getter"] = "get" . Inflector::classify($element->getName());
413 11
        $property["accessor"]["setter"] = "set" . Inflector::classify($element->getName());
414 11
        $t = $element->getType();
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface GoetasWebservices\XML\XS...ema\Element\ElementItem as the method getType() does only exist in the following implementations of said interface: GoetasWebservices\XML\XS...\Schema\Element\Element, GoetasWebservices\XML\XS...hema\Element\ElementDef, GoetasWebservices\XML\XS...hema\Element\ElementRef.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
415
416 11
        if ($arrayize) {
417
418 11
            if ($itemOfArray = $this->isArrayNestedElement($t)) {
419 1 View Code Duplication
                if (!$t->getName()) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
420
                    $classType = $this->visitTypeAnonymous($t, $element->getName(), $class);
421
                } else {
422 1
                    $classType = $this->visitType($t);
423
                }
424
425 1
                $visited = $this->visitElement($classType, $schema, $itemOfArray, false);
426
427 1
                $property["type"] = "array<" . $visited["type"] . ">";
428 1
                $property["xml_list"]["inline"] = false;
429 1
                $property["xml_list"]["entry_name"] = $itemOfArray->getName();
430 1
                if ($schema->getTargetNamespace()) {
431 1
                    $property["xml_list"]["namespace"] = $schema->getTargetNamespace();
432 1
                }
433 1
                return $property;
434 11
            } elseif ($itemOfArray = $this->isArrayType($t)) {
435
436
                if (!$t->getName()) {
437
                    $visitedType = $this->visitTypeAnonymous($itemOfArray, $element->getName(), $class);
438
439 View Code Duplication
                    if ($prop = $this->typeHasValue($itemOfArray, $class, 'xx')) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
440
                        $property["type"] = "array<" . $prop . ">";
441
                    } else {
442
                        $property["type"] = "array<" . key($visitedType) . ">";
443
                    }
444
                } else {
445
                    $this->visitType($itemOfArray);
446
                    $property["type"] = "array<" . $this->findPHPName($itemOfArray) . ">";
447
                }
448
449
                $property["xml_list"]["inline"] = false;
450
                $property["xml_list"]["entry_name"] = $itemOfArray->getName();
451
                if ($schema->getTargetNamespace()) {
452
                    $property["xml_list"]["namespace"] = $schema->getTargetNamespace();
453
                }
454
                return $property;
455 11
            } elseif ($this->isArrayElement($element)) {
456 4
                $property["xml_list"]["inline"] = true;
457 4
                $property["xml_list"]["entry_name"] = $element->getName();
458 4
                if ($schema->getTargetNamespace()) {
459 3
                    $property["xml_list"]["namespace"] = $schema->getTargetNamespace();
460 3
                }
461
462 4
                $property["type"] = "array<" . $this->findPHPClass($class, $element) . ">";
0 ignored issues
show
Documentation introduced by
$element is of type object<GoetasWebservices...ma\Element\ElementItem>, but the function expects a object<GoetasWebservices...\XSDReader\Schema\Item>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
463 4
                return $property;
464
            }
465 10
        }
466
467 11
        $property["type"] = $this->findPHPClass($class, $element);
0 ignored issues
show
Documentation introduced by
$element is of type object<GoetasWebservices...ma\Element\ElementItem>, but the function expects a object<GoetasWebservices...\XSDReader\Schema\Item>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
468 11
        return $property;
469
    }
470
471 11
    private function findPHPClass(&$class, Item $node)
472
    {
473 11
        $type = $node->getType();
474
475 11
        if ($alias = $this->getTypeAlias($node->getType())) {
476 11
            return $alias;
477
        }
478 4
        if ($node instanceof ElementRef) {
479 3
            $elementRef = $this->visitElementDef($node->getSchema(), $node->getReferencedElement());
480 3
            return key($elementRef);
481
        }
482 3
        if ($valueProp = $this->typeHasValue($type, $class, '')) {
483 2
            return $valueProp;
484
        }
485 3 View Code Duplication
        if (!$node->getType()->getName()) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
486 2
            $visited = $this->visitTypeAnonymous($node->getType(), $node->getName(), $class);
487 2
        } else {
488 1
            $visited = $this->visitType($node->getType());
489
        }
490
491 3
        return key($visited);
492
    }
493
}
494