Passed
Branch 001-basic (dcea18)
by Mr.
02:13
created

Serializer::hydrate()   B

Complexity

Conditions 8
Paths 27

Size

Total Lines 31
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 17
CRAP Score 8

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 8
eloc 20
c 1
b 0
f 0
nc 27
nop 2
dl 0
loc 31
ccs 17
cts 17
cp 1
crap 8
rs 8.4444
1
<?php
2
3
declare(strict_types=1);
4
5
namespace LibraryCatalog\Transformer;
6
7
use LibraryCatalog\Transformer\Encoder\EncoderInterface;
8
use LibraryCatalog\Transformer\Serializer\Exception;
9
use LibraryCatalog\Transformer\Serializer\HydrateException;
10
11
class Serializer
12
{
13
    /** @var EncoderInterface */
14
    protected $encoder;
15
16
    /**
17
     * Serializer constructor.
18
     * @param EncoderInterface $encoder
19
     */
20 6
    public function __construct(EncoderInterface $encoder)
21
    {
22 6
        $this->encoder = $encoder;
23 6
    }
24
25
    /**
26
     * @param $data
27
     * @return string
28
     * @throws Encoder\Exception
29
     * @throws HydrateException
30
     */
31 11
    public function serialize($data): string
32
    {
33 11
        if (!is_object($data)) {
34
            throw new HydrateException();
35
        }
36
37 11
        return $this->encoder->encode($this->normalizeObject($data));
38
    }
39
40
    /**
41
     * @param string $value
42
     * @param string $classname
43
     * @return object
44
     * @throws Encoder\Exception
45
     * @throws Exception
46
     * @throws HydrateException
47
     */
48 9
    public function deserialize(string $value, string $classname = ''): object
49
    {
50 9
        $data = $this->encoder->decode($value);
51
52 8
        if (!is_array($data)) {
53
            throw new Exception("Not valid input data");
54
        }
55
56 8
        return $this->hydrate($data, $classname);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->hydrate($data, $classname) could return the type array which is incompatible with the type-hinted return object. Consider adding an additional type-check to rule them out.
Loading history...
57
    }
58
59
    /**
60
     * Extract all public fields (but not arrays and objects).
61
     *
62
     * @param object $object
63
     * @return array
64
     */
65 5
    public function extractFields(object $object): array
66
    {
67 5
        $res = get_object_vars($object);
68 5
        foreach ($res as $key => $value) {
69 5
            if (is_array($value) || is_object($value)) {
70 1
                unset($res[$key]);
71
            }
72
        }
73 5
        return $res;
74
    }
75
76
    /**
77
     * @param array $data
78
     * @param string $classname
79
     * @return mixed
80
     * @throws HydrateException
81
     */
82 9
    public function hydrate(array $data, string $classname = '')
83
    {
84
        try {
85 9
            if ($classname != '') {
86 3
                $object = new $classname();
87 8
            } elseif (isset($data['__cn'])) {
88 8
                $object = new $data['__cn']();
89
            } else {
90 8
                $object = [];
91
            }
92 1
        } catch (\Error $e) {
93 1
            throw new HydrateException($e->getMessage());
94
        }
95
96 8
        if (isset($data['__cn'])) {
97 7
            unset($data['__cn']);
98
        }
99
100 8
        foreach ($data as $key => $value) {
101 8
            if (is_array($value)) {
102 1
                if (is_array($object)) {
103 1
                    $object[$key] = $this->hydrate($value, '');
104
                } else {
105 1
                    $object->{$key} = $this->hydrate($value, '');
106
                }
107
            } else {
108 8
                $object->{$key} = $value;
109
            }
110
        }
111
112 8
        return $object;
113
    }
114
115
    /**
116
     * @param $data
117
     * @return mixed
118
     */
119 11
    protected function normalizeObject($data)
120
    {
121 11
        if (is_object($data)) {
122 11
            $data->__cn = get_class($data);
123
124 11
            foreach ($data as $key => $value) {
125 11
                if (is_object($value)) {
126 3
                    $data->{$key} = $this->normalizeObject($value);
127 11
                } elseif (is_array($value)) {
128 4
                    $data->{$key} = [];
129
130 4
                    foreach ($value as $keyIn => $valueIn) {
131 3
                        $data->{$key}[$keyIn] = $this->normalizeObject($valueIn);
132
                    }
133
                }
134
            }
135
        }
136
137 11
        return $data;
138
    }
139
}
140