PlainArrayHydrator   A
last analyzed

Complexity

Total Complexity 22

Size/Duplication

Total Lines 122
Duplicated Lines 0 %

Coupling/Cohesion

Components 0
Dependencies 1

Test Coverage

Coverage 100%

Importance

Changes 5
Bugs 4 Features 0
Metric Value
wmc 22
c 5
b 4
f 0
lcom 0
cbo 1
dl 0
loc 122
ccs 80
cts 80
cp 1
rs 10

4 Methods

Rating   Name   Duplication   Size   Complexity  
C hydrate() 0 31 7
C extract() 0 37 8
B parsePropAndClass() 0 24 3
A getHydrator() 0 18 4
1
<?php
2
/**
3
 * PlainArrayHydrator.php
4
 *
5
 * @date 25.12.2015 15:47:21
6
 */
7
8
namespace Sufir\Hydrator;
9
10
use Closure;
11
use ReflectionObject;
12
use ReflectionClass;
13
use Sufir\Hydrator\Instantiator;
14
use InvalidArgumentException;
15
16
/**
17
 * PlainArrayHydrator
18
 *
19
 * Обеспечивает наполнение и извлечение данных из объекта.
20
 *
21
 * @todo refactoring
22
 * @todo hedrate and extraction internal classes
23
 * @author Sklyarov Alexey <[email protected]>
24
 * @package Sufir\Hydrator
25
 */
26
class PlainArrayHydrator implements HydratorInterface
27
{
28
    /**
29
     * {@inhereitdoc}
30
     */
31 3
    public function hydrate(array $data, $object)
32
    {
33 3
        if (is_string($object)) {
34 3
            $object = (new Instantiator())->newInstance($object);
35 3
        }
36
37 3
        $className = get_class($object);
38 3
        $selfProperties = [];
39 3
        $subObjects = [];
40
41 3
        foreach ($data as $property => $value) {
42 3
            if (substr($property, 0, 1) !== '_') {
43 3
                $selfProperties[$property] = $value;
44 3
            } elseif (substr($property, 0, 2) === '__') {
45 3
                $sub = explode('_', trim($property, '_'));
46 3
                if (count($sub) === 2) {
47 3
                    $subObjects[$sub[0]][$sub[1]] = $value;
48 3
                }
49 3
            }
50 3
        }
51
52 3
        foreach ($subObjects as $class => $properties) {
53 3
            $class = $this->parsePropAndClass($class, $className);
54 2
            $selfProperties[$class['property']] = $this->hydrate($properties, $class['class']);
55 2
        }
56
57 2
        $hydrate = $this->getHydrator($className);
58 1
        $hydrate($object, $selfProperties);
59
60 1
        return $object;
61
    }
62
63
    /**
64
     * {@inhereitdoc}
65
     */
66 1
    public function extract($object)
67
    {
68 1
        $data = [];
69 1
        $reflection = new ReflectionObject($object);
70 1
        $class = $reflection->getName();
71 1
        $propertises = $reflection->getProperties();
72
73 1
        foreach ($propertises as $prop) {
74 1
            $prop->setAccessible(true);
75 1
            $value = $prop->getValue($object);
76 1
            $propName = $prop->getName();
77
78 1
            if (!is_object($value)) {
79 1
                $data[$propName] = $value;
80 1
            } else {
81 1
                $fullClassName = get_class($value);
82 1
                if (strpos($fullClassName, $class) === 0) {
83 1
                    $className = substr($fullClassName, strrpos($fullClassName, '\\')+1);
84 1
                } else {
85 1
                    $className = '\\' . $fullClassName;
86
                }
87
88 1
                $data['__' . lcfirst($propName) . ':' . $className] = $this->extract($value);
89
            }
90 1
        }
91
92 1
        foreach ($data as $key => $value) {
93 1
            if (substr($key, 0, 2) === '__' && is_array($value)) {
94 1
                foreach ($value as $subKey => $subVal) {
95 1
                    $data["{$key}_{$subKey}"] = $subVal;
96 1
                }
97 1
                unset($data[$key]);
98 1
            }
99 1
        }
100
101 1
        return $data;
102
    }
103
104 3
    protected function parsePropAndClass($className, $namespace = null)
105
    {
106 3
        $parts = explode(":", $className, 2);
107 3
        if (count($parts) !== 2) {
108 1
            throw new InvalidArgumentException(
109 1
                "Wrong property and type definition {$className},"
110
                . "must in format «__propertyName:SubClassName» or «__propertyName:\ClassName»"
111 1
            );
112
        }
113
114 2
        $prop = $parts[0];
115 2
        $class = $parts[1];
116
117 2
        if (strpos($class, '\\') === 0) {
118 2
            $namespace = '';
119 2
        } else {
120 1
            $namespace = trim($namespace, " \t\n\r\0\x0B\\\/") . '\\';
121
        }
122
123
        return [
124 2
            'property' => $prop,
125 2
            'class' => $namespace . $class,
126 2
        ];
127
    }
128
129 2
    protected function getHydrator($className)
130
    {
131 2
        $reflection = new ReflectionClass($className);
132
133 2
        if (!$reflection->isUserDefined()) {
134 1
            throw new InvalidArgumentException(
135 1
                "Cannot hydrate internal class «{$className}»"
136 1
            );
137
        }
138
139 1
        return Closure::bind(function ($object, $data) {
140 1
            foreach ($data as $property => $value) {
141 1
                if (property_exists($object, $property)) {
142 1
                    $object->{$property} = $value;
143 1
                }
144 1
            }
145 1
        }, null, $className);
146
    }
147
}
148