MessageMapperBuilder::buildArrayData()   B
last analyzed

Complexity

Conditions 5
Paths 5

Size

Total Lines 20
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 20
rs 8.8571
c 0
b 0
f 0
cc 5
eloc 10
nc 5
nop 1
1
<?php
2
/*
3
 * This file is part of the Borobudur-Bus package.
4
 *
5
 * (c) Hexacodelabs <http://hexacodelabs.com>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
11
namespace Borobudur\Bus\Message;
12
13
use Borobudur\Bus\Exception\InvalidArgumentException;
14
use ReflectionClass;
15
use ReflectionObject;
16
use ReflectionParameter;
17
18
/**
19
 * @author      Iqbal Maulana <[email protected]>
20
 * @created     10/12/15
21
 */
22
class MessageMapperBuilder
23
{
24
    /**
25
     * Factory create object.
26
     *
27
     * @param string $class
28
     * @param mixed  $data
29
     *
30
     * @return object
31
     */
32
    public static function create($class, $data)
33
    {
34
        $reflection = new ReflectionClass($class);
35
        $parameters = $reflection->getConstructor()->getParameters();
36
37
        return $reflection->newInstanceArgs(self::normalizeParameters($parameters, $data));
38
    }
39
40
    /**
41
     * Call factory method on class.
42
     *
43
     * @param string $class
44
     * @param string $method
45
     * @param mixed  $data
46
     *
47
     * @return object
48
     */
49
    public static function call($class, $method, $data)
50
    {
51
        $reflection = new ReflectionClass($class);
52
        if (!$reflection->hasMethod($method)) {
53
            throw new InvalidArgumentException(
54
                sprintf(
55
                    'Undefined method "%s" in class "%s".',
56
                    $method,
57
                    $class
58
                )
59
            );
60
        }
61
62
        $method = $reflection->getMethod($method);
63
        $parameters = $method->getParameters();
64
65
        return $method->invokeArgs(null, self::normalizeParameters($parameters, $data));
66
    }
67
68
    /**
69
     * Normalize parameters.
70
     *
71
     * @param ReflectionParameter[] $parameters
72
     * @param mixed                 $data
73
     *
74
     * @return array
75
     */
76
    public static function normalizeParameters(array $parameters, $data)
77
    {
78
        $arguments = array();
79
        foreach ($parameters as $param) {
80
            if (!$param instanceof ReflectionParameter) {
81
                throw new InvalidArgumentException(
82
                    sprintf(
83
                        'Param "%s" not instance of ReflectionParameter',
84
                        (string) $param
85
                    )
86
                );
87
            }
88
89
            $name = $param->getName();
90
            $arguments[$name] = self::buildValue($param, $data);
91
        }
92
93
        return $arguments;
94
    }
95
96
    /**
97
     * @param ReflectionParameter $param
98
     * @param mixed               $data
99
     *
100
     * @return mixed
101
     */
102
    public static function buildValue(ReflectionParameter $param, $data)
103
    {
104
        $name = $param->getName();
105
        if (($class = $param->getClass()) && is_object($data)) {
106
            if (method_exists($data, 'toArray')) {
107
                $temp = (object) $data->toArray();
108
                if (isset($temp->{$name}) && is_object($temp->{$name}) && $class->isInstance($temp->{$name})) {
109
                    return $temp->{$name};
110
                }
111
            }
112
113
            $reflection = new ReflectionObject($data);
114
            if ($reflection->hasProperty($name)) {
115
                $prop = $reflection->getProperty($name);
116
                $prop->setAccessible(true);
117
                $value = $prop->getValue($data);
118
                if (is_object($value) && $class->isInstance($value)) {
119
                    return $value;
120
                }
121
            }
122
        }
123
124
        $data = self::buildArrayData($data);
125
        $value = isset($data[$name]) ? $data[$name] : null;
126
127
        return self::buildObjectValue($param, $value);
128
    }
129
130
    /**
131
     * Normalize data.
132
     *
133
     * @param mixed $data
134
     *
135
     * @return array
136
     */
137
    public static function buildArrayData($data)
138
    {
139
        if (is_object($data)) {
140
            if (method_exists($data, 'serialize')) {
141
                return $data->{'serialize'}();
142
            }
143
144
            if (method_exists($data, 'toArray')) {
145
                return $data->{'toArray'}();
146
            }
147
148
            if (method_exists($data, 'all')) {
149
                return $data->{'all'}();
150
            }
151
152
            return (array) get_object_vars($data);
153
        }
154
155
        return (array) $data;
156
    }
157
158
    /**
159
     * Normalize value.
160
     *
161
     * @param ReflectionParameter $param
162
     * @param mixed               $value
163
     *
164
     * @return mixed
165
     */
166
    private static function buildObjectValue(ReflectionParameter $param, $value)
167
    {
168
        if (null === $value) {
169
            return $value;
170
        }
171
        
172
        if (null !== ($class = $param->getClass()) && false === is_object($value)) {
173
            if (is_scalar($value) && $class->hasMethod('fromString')) {
174
                return $class->getMethod('fromString')->invoke(null, $value);
175
            }
176
177
            if ((is_array($value) || is_object($value)) && $class->hasMethod('deserialize')) {
178
                return $class->getMethod('deserialize')->invoke(null, $value);
179
            }
180
181
            if ($class->isInstantiable()) {
182
                return $class->newInstance($value);
183
            }
184
        }
185
186
        return $value;
187
    }
188
}
189