Completed
Push — master ( 366fbf...5f1478 )
by Rafael
02:45
created

Array2Object::parseValue()   B

Complexity

Conditions 7
Paths 5

Size

Total Lines 21
Code Lines 12

Duplication

Lines 21
Ratio 100 %

Importance

Changes 7
Bugs 0 Features 0
Metric Value
c 7
b 0
f 0
dl 21
loc 21
rs 7.551
cc 7
eloc 12
nc 5
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($this, $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 View Code Duplication
    private function parseValue($value, $types, \ReflectionProperty $property, $object)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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
                        foreach ($value as $key => &$arrayValue) {
124
                            $arrayValue = $parser->toObjectValue($arrayValue, str_replace('[]', null, $type), $property, $object);
125
                        }
126
                    } else {
127
                        $value = $parser->toObjectValue($value, $type, $property, $object);
128
                    }
129
                } else {
130
                    throw new \InvalidArgumentException(sprintf("%s is not a valid parser.", get_class($parser)));
131
                }
132
            }
133
        }
134
135
        return $value;
136
    }
137
}