Completed
Push — master ( 3ea98f...31081b )
by Iqbal
02:31
created

MessageMapperBuilder::create()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 7
rs 9.4285
cc 1
eloc 4
nc 1
nop 2
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 ReflectionParameter;
16
17
/**
18
 * @author      Iqbal Maulana <[email protected]>
19
 * @created     10/12/15
20
 */
21
class MessageMapperBuilder
22
{
23
    /**
24
     * Factory create object.
25
     *
26
     * @param string $class
27
     * @param mixed  $data
28
     *
29
     * @return object
30
     */
31
    public static function create($class, $data)
32
    {
33
        $reflection = new ReflectionClass($class);
34
        $parameters = $reflection->getConstructor()->getParameters();
35
36
        return $reflection->newInstanceArgs(self::normalizeParameters($parameters, $data));
37
    }
38
39
    /**
40
     * Call factory method on class.
41
     *
42
     * @param string $class
43
     * @param string $method
44
     * @param mixed  $data
45
     *
46
     * @return object
47
     */
48
    public static function call($class, $method, $data)
49
    {
50
        $reflection = new ReflectionClass($class);
51
        if (!$reflection->hasMethod($method)) {
52
            throw new InvalidArgumentException(
53
                sprintf(
54
                    'Undefined method "%s" in class "%s".',
55
                    $method,
56
                    $class
57
                )
58
            );
59
        }
60
61
        $method = $reflection->getMethod($method);
62
        $parameters = $method->getParameters();
63
64
        return $method->invokeArgs(null, self::normalizeParameters($parameters, $data));
65
    }
66
67
    /**
68
     * Normalize parameters.
69
     *
70
     * @param ReflectionParameter[] $parameters
71
     * @param mixed                 $data
72
     *
73
     * @return array
74
     */
75
    public static function normalizeParameters(array $parameters, $data)
76
    {
77
        $arguments = array();
78
        foreach ($parameters as $param) {
79
            if (!$param instanceof ReflectionParameter) {
80
                throw new InvalidArgumentException(
81
                    sprintf(
82
                        'Param "%s" not instance of ReflectionParameter',
83
                        (string) $param
84
                    )
85
                );
86
            }
87
88
            $name = $param->getName();
89
            $arguments[$name] = self::buildValue($param, $data);
90
        }
91
92
        return $arguments;
93
    }
94
95
    /**
96
     * @param ReflectionParameter $param
97
     * @param mixed               $data
98
     *
99
     * @return mixed
100
     */
101
    public static function buildValue(ReflectionParameter $param, $data)
102
    {
103
        $name = $param->getName();
104
        if (($class = $param->getClass()) && is_object($data) && property_exists($data, $name)) {
105
            if ($class->isInstance($data->{$name})) {
106
                return $data->{$name};
107
            }
108
        }
109
110
        $data = self::buildArrayData($data);
111
        $value = isset($data[$name]) ? $data[$name] : null;
112
113
        return self::buildObjectValue($param, $value);
114
    }
115
116
    /**
117
     * Normalize data.
118
     *
119
     * @param mixed $data
120
     *
121
     * @return array
122
     */
123
    public static function buildArrayData($data)
124
    {
125
        if (is_object($data)) {
126
            if (method_exists($data, 'serialize')) {
127
                return $data->{'serialize'}();
128
            }
129
130
            if (method_exists($data, 'toArray')) {
131
                return $data->{'toArray'}();
132
            }
133
134
            if (method_exists($data, 'all')) {
135
                return $data->{'all'}();
136
            }
137
138
            return (array) get_object_vars($data);
139
        }
140
141
        return (array) $data;
142
    }
143
144
    /**
145
     * Normalize value.
146
     *
147
     * @param ReflectionParameter $param
148
     * @param mixed               $value
149
     *
150
     * @return mixed
151
     */
152
    private static function buildObjectValue(ReflectionParameter $param, $value)
153
    {
154
        if (null === $value) {
155
            return $value;
156
        }
157
        
158
        if (null !== ($class = $param->getClass()) && false === is_object($value)) {
159
            if (is_scalar($value) && $class->hasMethod('fromString')) {
160
                return $class->getMethod('fromString')->invoke(null, $value);
161
            }
162
163
            if ((is_array($value) || is_object($value)) && $class->hasMethod('deserialize')) {
164
                return $class->getMethod('deserialize')->invoke(null, $value);
165
            }
166
167
            if ($class->isInstantiable()) {
168
                return $class->newInstance($value);
169
            }
170
        }
171
172
        return $value;
173
    }
174
}
175