Completed
Push — master ( 4ef5f0...ef9d83 )
by Rafael
04:26
created

Array2Object::parseValue()   D

Complexity

Conditions 9
Paths 6

Size

Total Lines 28
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 8
Bugs 0 Features 0
Metric Value
c 8
b 0
f 0
dl 0
loc 28
rs 4.909
cc 9
eloc 14
nc 6
nop 4
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) && strpos($type, '[]') !== false) {
123
124
                        //support for nesting children
125
                        //https://github.com/rafrsr/lib-array2object/issues/1
126
                        if (count($value) === 1 && array_key_exists(0, current($value))) {
127
                            $value = current($value);
128
                        }
129
130
                        foreach ($value as $key => &$arrayValue) {
131
                            $arrayValue = $parser->toObjectValue($arrayValue, str_replace('[]', null, $type), $property, $object);
132
                        }
133
                    } else {
134
                        $value = $parser->toObjectValue($value, $type, $property, $object);
135
                    }
136
                } else {
137
                    throw new \InvalidArgumentException(sprintf("%s is not a valid parser.", get_class($parser)));
138
                }
139
            }
140
        }
141
142
        return $value;
143
    }
144
}