Completed
Push — master ( b0f07b...0ca432 )
by Randy
03:00
created

HydrateProcedure::assign()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
dl 0
loc 6
ccs 0
cts 0
cp 0
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 3
nc 2
nop 1
crap 6
1
<?php
2
3
namespace Dgame\Soap\Hydrator;
4
5
use Dgame\Soap\Attribute\Attribute;
6
use Dgame\Soap\Attribute\XmlAttribute;
7
use Dgame\Soap\Element;
8
use Dgame\Soap\Visitor\AttributeVisitorInterface;
9
use Dgame\Soap\Visitor\ElementVisitorInterface;
10
use Dgame\Soap\XmlElement;
11
use Dgame\Soap\XmlNode;
12
13
/**
14
 * Class HydrateProcedure
15
 * @package Dgame\Soap\Hydrator
16
 */
17
final class HydrateProcedure implements ElementVisitorInterface, AttributeVisitorInterface
18
{
19
    /**
20
     * @var Hydrate
21
     */
22
    private $hydrate;
23
    /**
24
     * @var ClassMapper
25
     */
26
    private $mapper;
27
    /**
28
     * @var array
29
     */
30
    private $warnings = [];
31
32
    /**
33 9
     * Hydrat constructor.
34
     *
35 9
     * @param ClassMapper $mapper
36 9
     */
37
    public function __construct(ClassMapper $mapper)
38
    {
39
        $this->mapper = $mapper;
40
    }
41 9
42
    /**
43 9
     * @return array
44
     */
45
    public function getWarnings(): array
46
    {
47
        return $this->warnings;
48
    }
49 9
50
    /**
51 9
     * @return bool
52
     */
53
    public function hasWarnings(): bool
54
    {
55
        return !empty($this->warnings);
56
    }
57
58
    /**
59
     * @return Hydrate
60
     */
61
    public function getHydrate(): Hydrate
62
    {
63
        return $this->hydrate;
64
    }
65 9
66
    /**
67 9
     * @return bool
68 9
     */
69
    public function isValid(): bool
70
    {
71
        return $this->hydrate !== null;
72
    }
73 9
74
    /**
75 9
     * @param Element $element
76 9
     */
77 9
    public function visitElement(Element $element)
78
    {
79
        $this->visit($element);
80
    }
81
82
    /**
83
     * @param XmlElement $element
84
     */
85
    public function visitXmlElement(XmlElement $element)
86
    {
87
        $this->visit($element);
88
    }
89
90 5
    /**
91
     * @param XmlNode $node
92 5
     */
93 5
    public function visitXmlNode(XmlNode $node)
94
    {
95
        $this->visit($node);
96
        $this->visitChildrenOf($node);
97
    }
98 5
99
    /**
100 5
     * @param Attribute $attribute
101 5
     */
102
    public function visitAttribute(Attribute $attribute)
103 5
    {
104
        $this->assignAttribute($attribute);
105
    }
106
107
    /**
108 9
     * @param XmlAttribute $attribute
109
     */
110 9
    public function visitXmlAttribute(XmlAttribute $attribute)
111 9
    {
112 9
        $this->assignAttribute($attribute);
113
    }
114 9
115
    /**
116
     * @param Attribute $attribute
117
     */
118
    private function assignAttribute(Attribute $attribute)
119 9
    {
120
        if ($attribute->hasValue()) {
121 9
            $this->hydrate->assign($attribute);
122 5
        }
123
    }
124
125 9
    /**
126 3
     * @param Element $element
127
     */
128 9
    private function visit(Element $element)
129
    {
130
        $this->hydrate = $this->mapper->new($element->getName());
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->mapper->new($element->getName()) can also be of type object<self>. However, the property $hydrate is declared as type object<Dgame\Soap\Hydrator\Hydrate>. 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...
131
        if ($this->isValid()) {
132
            $this->visitAttributesOf($element);
133 9
        } else {
134
            $this->warnings[] = 'Class not found: ' . $element->getName();
135 9
        }
136 9
    }
137
138 9
    /**
139
     * @param Element $element
140
     */
141
    private function visitAttributesOf(Element $element)
142
    {
143 9
        foreach ($element->getAttributes() as $attribute) {
144
            $attribute->accept($this);
145 9
        }
146 9
147
        if ($element->hasValue()) {
148 9
            $this->hydrate->setValue('value', $element->getValue());
149 7
        }
150
    }
151 6
152
    /**
153 9
     * @param XmlNode $node
154
     */
155
    private function visitChildrenOf(XmlNode $node)
156
    {
157
        foreach ($node->getElements() as $child) {
158
            $this->visitChild($child);
159 7
        }
160
    }
161 7
162 5
    /**
163
     * @param Element $element
164 6
     */
165
    private function visitChild(Element $element)
166 7
    {
167
        $procedure = new self($this->mapper);
168
        $element->accept($procedure);
169
170
        if ($this->isValid()) {
171 6
            $this->appendOrAssign($procedure, $element);
0 ignored issues
show
Documentation introduced by
$procedure is of type object<Dgame\Soap\Hydrator\HydrateProcedure>, but the function expects a object<self>.

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...
172
        } elseif (!$this->skipTo($procedure)) {
0 ignored issues
show
Documentation introduced by
$procedure is of type object<Dgame\Soap\Hydrator\HydrateProcedure>, but the function expects a object<self>.

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...
173 6
            $this->warnings[] = 'Could not hydrate: ' . $element->getName();
174 6
        }
175
    }
176 6
177
    /**
178
     * @param HydrateProcedure $procedure
0 ignored issues
show
Documentation introduced by
Should the type for parameter $procedure not be \self?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
179
     * @param Element          $element
180
     */
181
    private function appendOrAssign(self $procedure, Element $element)
182
    {
183
        if ($procedure->isValid()) {
184
            $this->append($procedure->getHydrate());
185
        } else {
186
            $this->assign($element);
187
        }
188
    }
189
190
    /**
191
     * @param HydrateProcedure $procedure
0 ignored issues
show
Documentation introduced by
Should the type for parameter $procedure not be \self?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
192
     *
193
     * @return bool
194
     */
195
    private function skipTo(self $procedure): bool
196
    {
197
        if (!$procedure->isValid()) {
198
            return false;
199
        }
200
201
        $this->hydrate = $procedure->getHydrate();
202
203
        return true;
204
    }
205
206
    /**
207
     * @param Hydrate $hydrate
208
     */
209
    private function append(Hydrate $hydrate)
210
    {
211
        if (!$this->hydrate->append($hydrate)) {
0 ignored issues
show
Documentation introduced by
$hydrate is of type object<Dgame\Soap\Hydrator\Hydrate>, but the function expects a object<self>.

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...
212
            $this->warnings[] = 'Could not append: ' . $hydrate->getName();
213
        }
214
    }
215
216
    /**
217
     * @param Element $element
218
     */
219
    private function assign(Element $element)
220
    {
221
        if (!$this->hydrate->assign($element)) {
222
            $this->warnings[] = 'Could not assign Element: ' . $element->getName();
223
        }
224
    }
225
}