Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
90.91% covered (success)
90.91%
30 / 33
60.00% covered (warning)
60.00%
3 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
PropertySerializer
90.91% covered (success)
90.91%
30 / 33
60.00% covered (warning)
60.00%
3 / 5
19.27
0.00% covered (danger)
0.00%
0 / 1
 toJson
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
5
 toJsonArray
83.33% covered (warning)
83.33%
10 / 12
0.00% covered (danger)
0.00%
0 / 1
4.07
 toJsonStdclass
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 iterate
83.33% covered (warning)
83.33%
5 / 6
0.00% covered (danger)
0.00%
0 / 1
5.12
 toJsonObject
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
3
1<?php
2namespace Apie\Serializer\PropertySerializer;
3
4use ReflectionClass;
5use ReflectionProperty;
6use stdClass;
7
8class PropertySerializer
9{
10    public function toJson(mixed $object): SerializedProperties
11    {
12        return match(get_debug_type($object)) {
13            'null', 'string', 'int', 'float', 'bool' => SerializedProperties::createFromPrimitive($object),
14            'array' => $this->toJsonArray($object),
15            stdClass::class => $this->toJsonStdclass($object),
16            default => $this->toJsonObject($object),
17        };
18    }
19
20    private function toJsonArray(array $object): SerializedProperties
21    {
22        $isList = true;
23        $count = 0;
24        $returnValue = [];
25        foreach (array_keys($object) as $key) {
26            if ($key === $count) {
27                $count++;
28            } else {
29                $isList = false;
30                break;
31            }
32            $returnValue[$key] = $this->toJson($object[$key])->getRoot();
33        }
34        return $isList
35            ? SerializedProperties::createFromList(new TypehintMap($returnValue))
36            : SerializedProperties::createFromMap(new TypehintMap($returnValue));
37    }
38
39    private function toJsonStdclass(stdClass $object): SerializedProperties
40    {
41        $returnValue = [];
42        // @phpstan-ignore foreach.nonIterable
43        foreach ($object as $key => $value) {
44            $returnValue[$key] = $this->toJson($value)->getRoot();
45        }
46        return SerializedProperties::createFromMap(new TypehintMap($returnValue));
47    }
48
49    /**
50     * @param ReflectionClass<object> $reflectionClass
51     * @return iterable<string, ReflectionProperty>
52     */
53    private function iterate(ReflectionClass $reflectionClass, int $filter): iterable
54    {
55        foreach ($reflectionClass->getProperties($filter) as $property) {
56            $name = $property->isPrivate() ? $property->getDeclaringClass()->getName() . '::' . $property->getName() : $property->getName();
57            yield $name => $property;
58        }
59        $parent = $reflectionClass->getParentClass();
60        if ($parent && $filter !== ReflectionProperty::IS_PRIVATE) {
61            yield from $this->iterate($parent, ReflectionProperty::IS_PRIVATE);
62        }
63    }
64
65    private function toJsonObject(object $object): SerializedProperties
66    {
67        $returnValue = [];
68        foreach ($this->iterate(new ReflectionClass($object), ReflectionProperty::IS_PUBLIC|ReflectionProperty::IS_PROTECTED) as $key => $property) {
69            if ($property->isInitialized($object)) {
70                $returnValue[$key] = $this->toJson($property->getValue($object))->getRoot();
71            }
72        }
73        return SerializedProperties::createFromMap(new TypehintMap($returnValue));
74    }
75}