Extract::stringifying()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 10
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 8
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 10
rs 10
1
<?php
2
declare(strict_types=1);
3
4
namespace Stratadox\EntityState;
5
6
use function array_shift;
7
use function count;
8
use function get_class as classOfThe;
9
use function in_array;
10
use Stratadox\EntityState\Internal\AcceptsNewEntities;
11
use Stratadox\EntityState\Internal\CollectionExtractor;
12
use Stratadox\EntityState\Internal\EntityReferenceExtractor;
13
use Stratadox\EntityState\Internal\ExtractionRequest;
14
use Stratadox\EntityState\Internal\Extractor;
15
use Stratadox\EntityState\Internal\NewEntityDetector;
16
use Stratadox\EntityState\Internal\ObjectExtractor;
17
use Stratadox\EntityState\Internal\PropertyExtractor;
18
use Stratadox\EntityState\Internal\ScalarExtractor;
19
use Stratadox\EntityState\Internal\ShouldStringify;
20
use Stratadox\EntityState\Internal\Stringifier;
21
use Stratadox\IdentityMap\MapsObjectsByIdentity as Map;
22
use Stratadox\IdentityMap\NoSuchObject;
23
24
/**
25
 * Extract the state of the entities.
26
 *
27
 * @author Stratadox
28
 */
29
final class Extract implements ExtractsEntityState, AcceptsNewEntities
30
{
31
    private $extractor;
32
    private $newEntityQueue = [];
33
    private $newEntities = [];
34
35
    private function __construct(Extractor $extractor)
36
    {
37
        $this->extractor = $extractor;
38
    }
39
40
    /**
41
     * Produces a state extractor.
42
     *
43
     * @return ExtractsEntityState
44
     */
45
    public static function state(): ExtractsEntityState
46
    {
47
        return new Extract(
48
            PropertyExtractor::using(
49
                CollectionExtractor::withAlternative(
50
                    EntityReferenceExtractor::withAlternative(
51
                        ObjectExtractor::withAlternative(
52
                            ScalarExtractor::asLastResort()
53
                        )
54
                    )
55
                )
56
            )
57
        );
58
    }
59
60
    /**
61
     * Produces a state extractor that converts certain types to string.
62
     *
63
     * @param mixed ...$classes
64
     * @return ExtractsEntityState
65
     */
66
    public static function stringifying(...$classes): ExtractsEntityState
67
    {
68
        return new Extract(
69
            PropertyExtractor::using(
70
                CollectionExtractor::withAlternative(
71
                    Stringifier::withCondition(
72
                        ShouldStringify::these(...$classes),
73
                        EntityReferenceExtractor::withAlternative(
74
                            ObjectExtractor::withAlternative(
75
                                ScalarExtractor::asLastResort()
76
                            )
77
                        )
78
                    )
79
                )
80
            )
81
        );
82
    }
83
84
    /** @inheritdoc */
85
    public function consideringIt(
86
        DefinesEntityType ...$asEntities
87
    ): ExtractsEntityState {
88
        $new = clone $this;
89
        $new->extractor = NewEntityDetector::with($new, $this->extractor, ...$asEntities);
90
        return $new;
91
    }
92
93
    /** @inheritdoc */
94
    public function from(Map $map): State
95
    {
96
        return $this->fromOnly($map, ...$map->objects());
97
    }
98
99
    /** @inheritdoc */
100
    public function fromOnly(Map $map, object ...$objects): State
101
    {
102
        $states = [];
103
        foreach ($objects as $object) {
104
            $states[] = $this->stateOfThe($object, $map, $map->idOf($object));
105
        }
106
        while (count($this->newEntityQueue)) {
107
            $newEntity = array_shift($this->newEntityQueue);
108
            [$object, $id] = $newEntity;
109
            $states[] = $this->stateOfThe($object, $map, $id, $this->newEntities);
110
        }
111
        return StateRepresentation::with(EntityStates::list(...$states), $map);
112
    }
113
114
    /**
115
     * @inheritdoc
116
     * @internal
117
     */
118
    public function addAsNewEntity(object $newEntity, ?string $id): void
119
    {
120
        if (!in_array($newEntity, $this->newEntities, true)) {
121
            $this->newEntityQueue[] = [$newEntity, $id];
122
            $this->newEntities[] = $newEntity;
123
        }
124
    }
125
126
    /** @throws NoSuchObject */
127
    private function stateOfThe(
128
        object $entity,
129
        Map $map,
130
        ?string $id,
131
        array $newEntities = []
132
    ): RepresentsEntity {
133
        return EntityState::ofThe(classOfThe($entity), $id, PropertyStates::list(
134
            ...$this->extractor->extract(
135
                ExtractionRequest::for($entity, $map, ...$newEntities)
136
            )
137
        ));
138
    }
139
}
140