Completed
Push — master ( ef9d83...bc740a )
by Rafael
03:05
created

Array2Object   A

Complexity

Total Complexity 24

Size/Duplication

Total Lines 132
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 6

Importance

Changes 14
Bugs 2 Features 0
Metric Value
wmc 24
c 14
b 2
f 0
lcom 1
cbo 6
dl 0
loc 132
rs 10

6 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A getContext() 0 4 1
A setContext() 0 6 1
A createObject() 0 12 3
C populate() 0 23 7
C parseValue() 0 33 11
1
<?php
2
3
/**
4
 * LICENSE: This file is subject to the terms and conditions defined in
5
 * file 'LICENSE', which is part of this source code package.
6
 *
7
 * @copyright 2016 Copyright(c) - All rights reserved.
8
 */
9
10
namespace Rafrsr\LibArray2Object;
11
12
use Rafrsr\LibArray2Object\Parser\ValueParserInterface;
13
14
/**
15
 * Using the property names and the common property annotations
16
 * populate a object instance with the values of the array recursively
17
 */
18
class Array2Object
19
{
20
    /**
21
     * @var Array2ObjectContext
22
     */
23
    private $context;
24
25
    /**
26
     * @param Array2ObjectContext $context
27
     */
28
    public function __construct(Array2ObjectContext $context)
29
    {
30
        $this->context = $context;
31
    }
32
33
    /**
34
     * @return Array2ObjectContext
35
     */
36
    public function getContext()
37
    {
38
        return $this->context;
39
    }
40
41
    /**
42
     * @param Array2ObjectContext $context
43
     *
44
     * @return $this
45
     */
46
    public function setContext(Array2ObjectContext $context)
47
    {
48
        $this->context = $context;
49
50
        return $this;
51
    }
52
53
    /**
54
     * createObject
55
     *
56
     * @param string $class class to create object or instance
57
     * @param array  $data  array of data
58
     *
59
     * @return mixed
60
     *
61
     * @throws \InvalidArgumentException
62
     */
63
    public function createObject($class, array $data)
64
    {
65
        if (is_string($class) && class_exists($class)) {
66
            $object = new $class;
67
        } else {
68
            throw new \InvalidArgumentException('The first argument should be a valid class, can use ::populate with objects');
69
        }
70
71
        $this->populate($object, $data);
72
73
        return $object;
74
    }
75
76
    /**
77
     * @param object $object object instance to populate
78
     * @param array  $data   array of data to apply
79
     *
80
     * @throws \InvalidArgumentException
81
     */
82
    public function populate($object, array $data)
83
    {
84
        if (!is_object($object)) {
85
            throw new \InvalidArgumentException('The first param should be a object.');
86
        }
87
88
        if ($object instanceof Array2ObjectInterface) {
89
            $object->__populate($data);
90
        } else {
91
            $reflClass = new \ReflectionClass($object);
92
            foreach (Utils::getClassProperties($reflClass) as $property) {
93
                foreach ($data as $key => $value) {
94
                    if ($this->context->getMatcher()->match($property, $key)
95
                        && $this->context->getWriter()->isWritable($object, $property->getName())
96
                    ) {
97
                        $types = Utils::getPropertyTypes($property);
98
                        $value = $this->parseValue($value, $types, $property, $object);
0 ignored issues
show
Bug introduced by
It seems like $object can also be of type array; however, Rafrsr\LibArray2Object\Array2Object::parseValue() does only seem to accept object, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
99
                        $this->context->getWriter()->setValue($object, $property->getName(), $value);
100
                    }
101
                }
102
            }
103
        }
104
    }
105
106
    /**
107
     * Parse a value using given types
108
     *
109
     * @param mixed               $value
110
     * @param array               $types
111
     * @param \ReflectionProperty $property
112
     * @param object              $object
113
     *
114
     * @return array|bool|float|int|string
115
     */
116
    private function parseValue($value, $types, \ReflectionProperty $property, $object)
117
    {
118
        foreach ($types as $type) {
119
120
            foreach ($this->context->getParsers() as $parser) {
121
                if ($parser instanceof ValueParserInterface) {
122
                    if (is_array($value) && preg_match('/[\w\d_]+\[\]/', $type)) {
123
124
                        //support for nesting children
125
                        //https://github.com/rafrsr/lib-array2object/issues/1
126
                        if (count($value) === 1 && is_array(current($value))) {
127
                            if (array_key_exists(0, current($value))) {
128
                                $value = current($value);
129
                            } elseif (in_array('[]', $types, true)) {
130
                                //https://github.com/rafrsr/lib-array2object/issues/1#issuecomment-228155603
131
                                $value = [current($value)];
132
                            }
133
                        }
134
135
                        foreach ($value as $key => &$arrayValue) {
136
                            $arrayValue = $parser->toObjectValue($arrayValue, str_replace('[]', null, $type), $property, $object);
137
                        }
138
                    } else {
139
                        $value = $parser->toObjectValue($value, str_replace('[]', null, $type), $property, $object);
140
                    }
141
                } else {
142
                    throw new \InvalidArgumentException(sprintf("%s is not a valid parser.", get_class($parser)));
143
                }
144
            }
145
        }
146
147
        return $value;
148
    }
149
}