Passed
Push — master ( 010c64...640715 )
by Jesse
05:03
created

ObjectExtractor::withAlternative()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php declare(strict_types=1);
2
3
namespace Stratadox\EntityState\Internal;
4
5
use function array_merge as these;
6
use function assert;
7
use function is_object;
8
use Stratadox\EntityState\PropertyState;
9
use Stratadox\IdentityMap\MapsObjectsByIdentity as Map;
10
use Stratadox\IdentityMap\NoSuchObject;
11
use Stratadox\Specification\Contract\Satisfiable;
12
13
final class ObjectExtractor implements Extractor
14
{
15
    private $next;
16
    private $stringifier;
17
18
    private function __construct(Extractor $next, Satisfiable $constraint)
19
    {
20
        $this->next = $next;
21
        $this->stringifier = $constraint;
22
    }
23
24
    public static function withAlternative(Extractor $next): Extractor
25
    {
26
        return new self($next, Unsatisfiable::constraint());
27
    }
28
29
    public static function stringifyingWithAlternative(
30
        Satisfiable $constraint,
31
        Extractor $next
32
    ): Extractor {
33
        return new self($next, $constraint);
34
    }
35
36
    public function extract(
37
        Name $name,
38
        $object,
39
        Map $map,
40
        Visited $visited,
41
        Extractor $base = null
42
    ): array {
43
        if (!is_object($object)) {
44
            return $this->next->extract($name, $object, $map, $visited, $base);
45
        }
46
        assert($base !== null);
47
        return $this->objectState($name->for($object), $object, $map, $visited, $base);
48
    }
49
50
    /** @throws NoSuchObject */
51
    private function objectState(
52
        Name $name,
53
        $object,
54
        Map $map,
55
        Visited $visited,
56
        Extractor $base
57
    ): array {
58
        if ($this->stringifier->isSatisfiedBy($object)) {
59
            return [PropertyState::with((string) $name, (string) $object)];
60
        }
61
        if ($map->hasThe($object)) {
62
            return [PropertyState::with((string) $name, $map->idOf($object))];
63
        }
64
        $properties = [];
65
        foreach (ReflectionProperties::ofThe($object) as $property) {
66
            $properties[] = $base->extract(
67
                $name->forNested($property),
68
                $property->getValue($object),
69
                $map,
70
                $visited
71
            );
72
        }
73
        if (empty($properties)) {
74
            return [PropertyState::with((string) $name, null)];
75
        }
76
        return these(...$properties);
77
    }
78
}
79