1<?php
2namespace IXR\DataType;
3
4
5class Value
6{
7    private $data;
8    private $type;
9
10    public function __construct($data, $type = null)
11    {
12        $this->data = $data;
13        if (!$type) {
14            $type = $this->calculateType();
15        }
16        $this->type = $type;
17        if ($type === 'struct') {
18            // Turn all the values in the array in to new IXR_Value objects
19            foreach ($this->data as $key => $value) {
20                $this->data[$key] = new Value($value);
21            }
22        }
23        if ($type === 'array') {
24            for ($i = 0, $j = count($this->data); $i < $j; $i++) {
25                $this->data[$i] = new Value($this->data[$i]);
26            }
27        }
28    }
29
30    public function calculateType()
31    {
32        if ($this->data === true || $this->data === false) {
33            return 'boolean';
34        }
35        if (is_integer($this->data)) {
36            return 'int';
37        }
38        if (is_double($this->data)) {
39            return 'double';
40        }
41
42        // Deal with IXR object types base64 and date
43        if (is_object($this->data) && $this->data instanceof Date) {
44            return 'date';
45        }
46        if (is_object($this->data) && $this->data instanceof Base64) {
47            return 'base64';
48        }
49
50        // If it is a normal PHP object convert it in to a struct
51        if (is_object($this->data)) {
52            $this->data = get_object_vars($this->data);
53            return 'struct';
54        }
55        if (!is_array($this->data)) {
56            return 'string';
57        }
58
59        // We have an array - is it an array or a struct?
60        if ($this->isStruct($this->data)) {
61            return 'struct';
62        } else {
63            return 'array';
64        }
65    }
66
67    public function getXml()
68    {
69        // Return XML for this value
70        switch ($this->type) {
71            case 'boolean':
72                return '<boolean>' . (((bool)$this->data) ? '1' : '0') . '</boolean>';
73            case 'int':
74                return '<int>' . $this->data . '</int>';
75            case 'double':
76                return '<double>' . $this->data . '</double>';
77            case 'string':
78                return '<string>' . htmlspecialchars($this->data) . '</string>';
79            case 'array':
80                $return = '<array><data>' . "\n";
81                foreach ($this->data as $item) {
82                    $return .= '  <value>' . $item->getXml() . "</value>\n";
83                }
84                $return .= '</data></array>';
85                return $return;
86                break;
87            case 'struct':
88                $return = '<struct>' . "\n";
89                foreach ($this->data as $name => $value) {
90                    $name = htmlspecialchars($name);
91                    $return .= "  <member><name>$name</name><value>";
92                    $return .= $value->getXml() . "</value></member>\n";
93                }
94                $return .= '</struct>';
95                return $return;
96            case 'date':
97            case 'base64':
98                return $this->data->getXml();
99            default:
100                return false;
101        }
102    }
103
104    /**
105     * Checks whether or not the supplied array is a struct or not
106     *
107     * @param array $array
108     * @return boolean
109     */
110    public function isStruct($array)
111    {
112        $expected = 0;
113        foreach ($array as $key => $value) {
114            if ((string)$key != (string)$expected) {
115                return true;
116            }
117            $expected++;
118        }
119        return false;
120    }
121}
122