Completed
Push — master ( 24f2ce...35728e )
by Gareth
04:20
created

Type::buildObjectFromArray()   A

Complexity

Conditions 4
Paths 5

Size

Total Lines 18
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 4
Metric Value
dl 0
loc 18
ccs 9
cts 9
cp 1
rs 9.2
cc 4
eloc 9
nc 5
nop 1
crap 4
1
<?php
2
/**
3
 * Contains \garethp\ews\API\Type.
4
 */
5
6
namespace garethp\ews\API;
7
8
use garethp\ews\Caster;
9
10
/**
11
 * Base class for Exchange Web Service Types.
12
 *
13
 * @package php-ews\Type
14
 */
15
class Type
16
{
17
    use MagicMethodsTrait;
18
19
    /**
20
     * @var string
21
     */
22
    public $_ = "";
23
24 25
    public function getNonNullItems($includeHiddenValue = false)
25
    {
26 25
        $items = get_object_vars($this);
27
28 25
        foreach ($items as $key => $item) {
29 25
            if (substr($key, 0, 1) == "_" || $item === null) {
30 25
                unset($items[$key]);
31
            }
32
        }
33
34 25
        if (isset($this->_value) && $this->_value !== null && $includeHiddenValue) {
0 ignored issues
show
Bug introduced by
The property _value does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
35
            $items['_value'] = $this->_value;
0 ignored issues
show
Documentation introduced by
The property _value does not exist on object<garethp\ews\API\Type>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
36
        }
37
38 25
        return $items;
39
    }
40
41
    /**
42
     * @param $array
43
     * @return static
44
     */
45 30
    public static function buildFromArray($array)
46
    {
47 30
        if (!is_array($array)) {
48 2
            return $array;
49
        }
50
51 30
        if (!self::arrayIsAssoc($array)) {
52 15
            return self::buildArrayFromArray($array);
53
        } else {
54 30
            return self::buildObjectFromArray($array);
55
        }
56
    }
57
58 30
    protected static function buildObjectFromArray($array)
59
    {
60 30
        $object = new static();
61 30
        foreach ($array as $key => $value) {
62 30
            if (is_array($value)) {
63 26
                $value = self::buildFromArray($value);
64
            }
65
66
            //I think _value is a more expressive way to set string value, but Soap needs _
67 30
            if ($key === "_value") {
68 3
                $key = "_";
69
            }
70
71 30
            $object->$key = $value;
72
        }
73
74 30
        return $object;
75
    }
76
77 15
    public static function buildArrayFromArray($array)
78
    {
79 15
        foreach ($array as $key => $value) {
80 15
            $array[$key] = self::buildFromArray($value);
81
        }
82
83 15
        return $array;
84
    }
85
86 25
    public function toXmlObject()
87
    {
88 25
        $objectToReturn = new self();
89 25
        $objectToReturn->_ = (string) $this;
90
91 25
        $properties = $this->getNonNullItems(true);
92
93 25
        foreach ($properties as $name => $property) {
94
            //I think _value is a more expressive way to set string value, but Soap needs _
95 25
            if ($name == "_value") {
96
                $name = "_";
97
            }
98
99 25
            $name = ucfirst($name);
100
101 25
            if (isset($this->_typeMap[lcfirst($name)])) {
102
                $property = $this->castToExchange($property, $this->_typeMap[lcfirst($name)]);
103
            }
104
105 25
            if ($property instanceof Type) {
106 25
                $property = $property->toXmlObject();
107
            }
108
109 25
            if (is_array($property) && $this->arrayIsAssoc($property)) {
110
                $property = $this->buildFromArray($property);
111
            }
112
113 25
            if (is_array($property)) {
114 13
                foreach ($property as $key => $value) {
115 13
                    if ($value instanceof Type) {
116 13
                        $property[$key] = $value->toXmlObject();
117
                    }
118
                }
119
            }
120
121 25
            $objectToReturn->$name = $property;
122
        }
123
124 25
        return $objectToReturn;
125
    }
126
127 35
    public static function arrayIsAssoc($array)
128
    {
129 35
        return (bool) count(array_filter(array_keys($array), 'is_string'));
130
    }
131
132
    /**
133
     * Clones any object properties on a type object when it is cloned. Allows
134
     * for a deep clone required when using object to represent data types when
135
     * making a SOAP call.
136
     */
137 1
    public function __clone()
138
    {
139
        // Iterate over all properties on the current object.
140 1
        foreach (get_object_vars($this) as $property => $value) {
141
            // If the value of the property is an object then clone it.
142 1
            if (is_object($value)) {
143 1
                $this->$property = clone $value;
144 1
            } elseif (is_array($value)) {
145
                // The value is an array that may use objects as values. Iterate
146
                // over the array and clone any values that are objects into a
147
                // new array.
148
                // For some reason, if we try to set $this->$property to an
149
                // empty array then update it as we go it ends up being empty.
150
                // If we use a new array that we then set as the value of
151
                // $this->$property all is well.
152 1
                $new_value = array();
153 1
                foreach ($value as $index => $array_value) {
154 1
                    $new_value[$index] = (is_object($array_value) ? clone $array_value : $array_value);
155
                }
156
157
                // Set the property to the new array.
158 1
                $this->$property = $new_value;
159
            }
160
        }
161
    }
162
163 30
    public function __toString()
164
    {
165 30
        if (!is_string($this->_)) {
166 4
            return '';
167
        }
168
169 26
        return $this->_;
170
    }
171
}
172