BuildableTrait   A
last analyzed

Complexity

Total Complexity 38

Size/Duplication

Total Lines 176
Duplicated Lines 0 %

Test Coverage

Coverage 95.95%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 69
c 1
b 0
f 0
dl 0
loc 176
ccs 71
cts 74
cp 0.9595
rs 9.36
wmc 38

9 Methods

Rating   Name   Duplication   Size   Complexity  
A getNonNullItems() 0 15 6
A __toString() 0 7 2
B buildObjectFromArray() 0 35 9
A buildFromArray() 0 18 6
A buildArrayFromArray() 0 7 2
A arrayIsAssoc() 0 3 1
A __clone() 0 5 2
A toXmlObject() 0 18 3
B propertyToXml() 0 25 7
1
<?php
2
3
namespace garethp\ews;
4
5
use garethp\ews\API\Type;
6
use garethp\ews\API\XmlObject;
7
8
trait BuildableTrait
9
{
10
    /**
11
     * @var string
12
     */
13
    public $_ = '';
14
15
    public $_value = null;
16
17 32
    public function getNonNullItems($includeHiddenValue = false)
18
    {
19 32
        $items = get_object_vars($this);
20
21 32
        foreach ($items as $key => $item) {
22 32
            if (substr($key, 0, 1) == "_" || $item === null) {
23 32
                unset($items[$key]);
24
            }
25
        }
26
27 32
        if ($includeHiddenValue && $this->_value !== null) {
28 1
            $items['_value'] = $this->_value;
29
        }
30
31 32
        return $items;
32
    }
33
34
    /**
35
     * @param $array
36
     * @param bool $strict When set to true, we'll use reflection to build the objects
37
     *
38
     * @return static|XmlObject
39
     */
40 33
    public static function buildFromArray($array, bool $strict = false)
41
    {
42 33
        if (static::class === Type::class) {
0 ignored issues
show
introduced by
The condition static::class === garethp\ews\API\Type::class is always false.
Loading history...
43 33
            return XmlObject::buildFromArray($array, $strict);
44
        }
45
46 33
        if ($array instanceof XmlObject && $strict) {
47 2
            $array = (array)$array;
48
        }
49
50 33
        if (!is_array($array)) {
51 18
            return $array;
52
        }
53
54 33
        if (!self::arrayIsAssoc($array)) {
55 19
            return self::buildArrayFromArray($array, $strict);
0 ignored issues
show
Bug Best Practice introduced by
The expression return self::buildArrayFromArray($array, $strict) returns the type array which is incompatible with the documented return type garethp\ews\API\XmlObjec...ethp\ews\BuildableTrait.
Loading history...
Unused Code introduced by
The call to garethp\ews\BuildableTrait::buildArrayFromArray() has too many arguments starting with $strict. ( Ignorable by Annotation )

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

55
            return self::/** @scrutinizer ignore-call */ buildArrayFromArray($array, $strict);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
56
        } else {
57 33
            return self::buildObjectFromArray($array, $strict);
58
        }
59
    }
60
61 33
    protected static function buildObjectFromArray($array, bool $strict = false)
62
    {
63 33
        $object = new static();
64 33
        $reflect = new \ReflectionClass(static::class);
65
66 33
        foreach ($array as $key => $value) {
67
            // If we're in strict mode, let's take the reflection class, check for a setter and try to use that to build
68
            // the array, resulting in type-correct responses the whole way down.
69 33
            if ($strict === true && $reflect->hasMethod("set" . ucfirst($key))) {
70 2
                $parameters = $reflect->getMethod("set" . ucfirst($key))->getParameters();
71
72 2
                if (count($parameters) === 1
73 2
                    && $parameters[0]->hasType()
74 2
                    && $parameters[0]->getClass() !== null) {
75 2
                    $classToBuild = $parameters[0]->getClass()->getName();
76
77 2
                    $newValue = call_user_func("$classToBuild::buildFromArray", $value, true);
78 2
                    $object->$key = $newValue;
79 2
                    continue;
80
                }
81
            }
82
83 33
            if (is_array($value)) {
84 32
                $value = self::buildFromArray($value);
85
            }
86
87
            //I think _value is a more expressive way to set string value, but Soap needs _
88 33
            if ($key === "_value") {
89 7
                $key = "_";
90
            }
91
92 33
            $object->$key = $value;
93
        }
94
95 33
        return $object;
96
    }
97
98 19
    public static function buildArrayFromArray($array)
99
    {
100 19
        foreach ($array as $key => $value) {
101 19
            $array[$key] = self::buildFromArray($value);
102
        }
103
104 19
        return $array;
105
    }
106
107 6
    public function toXmlObject()
108
    {
109 6
        $objectToReturn = new XmlObject();
110 6
        $objectToReturn->_ = (string)$this;
111
112 6
        $properties = $this->getNonNullItems(true);
113
114 6
        foreach ($properties as $name => $property) {
115
            //I think _value is a more expressive way to set string value, but Soap needs _
116 6
            if ($name == "_value") {
117
                $name = "_";
118
            }
119
120 6
            $name = ucfirst($name);
121 6
            $objectToReturn->$name = $this->propertyToXml($name, $property);
122
        }
123
124 6
        return $objectToReturn;
125
    }
126
127
    /**
128
     * @param $name
129
     * @param $property
130
     * @return array|Type|null
131
     */
132 6
    protected function propertyToXml($name, $property)
0 ignored issues
show
Unused Code introduced by
The parameter $name is not used and could be removed. ( Ignorable by Annotation )

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

132
    protected function propertyToXml(/** @scrutinizer ignore-unused */ $name, $property)

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

Loading history...
133
    {
134 6
        if ($property instanceof \DateTime) {
135
            $property = $property->format("c");
136
        }
137
138 6
        if ($property instanceof Type) {
139 6
            return $property->toXmlObject();
0 ignored issues
show
Bug Best Practice introduced by
The expression return $property->toXmlObject() returns the type garethp\ews\API\XmlObject which is incompatible with the documented return type array|garethp\ews\API\Type|null.
Loading history...
140
        }
141
142 6
        if (is_array($property) && $this->arrayIsAssoc($property)) {
143
            return $this->buildFromArray($property);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->buildFromArray($property) returns the type garethp\ews\API\XmlObject which is incompatible with the documented return type array|garethp\ews\API\Type|null.
Loading history...
144
        }
145
146 6
        if (is_array($property)) {
147 5
            return array_map(function ($property) {
148 5
                if ($property instanceof Type) {
149 5
                    return $property->toXmlObject();
150
                }
151
152 1
                return $property;
153 5
            }, $property);
154
        }
155
156 6
        return $property;
157
    }
158
159 39
    public static function arrayIsAssoc($array)
160
    {
161 39
        return (bool)count(array_filter(array_keys($array), 'is_string'));
162
    }
163
164
    /**
165
     * Clones any object properties on a type object when it is cloned. Allows
166
     * for a deep clone required when using object to represent data types when
167
     * making a SOAP call.
168
     */
169 1
    public function __clone()
170
    {
171
        // Iterate over all properties on the current object.
172 1
        foreach (get_object_vars($this) as $property => $value) {
173 1
            $this->$property = \garethp\ews\Utilities\cloneValue($value);
174
        }
175
    }
176
177 23
    public function __toString()
178
    {
179 23
        if (!is_string($this->_)) {
0 ignored issues
show
introduced by
The condition is_string($this->_) is always true.
Loading history...
180 6
            return '';
181
        }
182
183 19
        return $this->_;
184
    }
185
}
186