Issues (57)

src/Profile.php (1 issue)

1
<?php
2
3
declare(strict_types=1);
4
5
namespace Koriym\AppStateDiagram;
6
7
use Koriym\AppStateDiagram\Exception\DescriptorIsNotArrayException;
8
use Koriym\AppStateDiagram\Exception\DescriptorNotFoundException;
9
use Koriym\AppStateDiagram\Exception\InvalidDescriptorException;
10
use Seld\JsonLint\ParsingException;
11
use stdClass;
12
13
use function assert;
14
use function is_array;
15
use function is_string;
16
use function json_encode;
17
use function ksort;
18
use function property_exists;
19
use function substr;
20
21
final class Profile extends AbstractProfile
22
{
23
    /** @var string */
24
    public $schema;
25
26
    /** @var string */
27
    public $title;
28
29
    /** @var string */
30
    public $doc;
31
32
    /** @var string  */
33
    public $alpsFile;
34
35
    /**
36
     * Descriptor instances (not reference)
37
     *
38
     * @var array<string, stdClass>
39
     */
40
    private $instances = [];
41
42
    /** @var array<string, list<string>> */
0 ignored issues
show
Documentation Bug introduced by
The doc comment array<string, list<string>> at position 4 could not be parsed: Expected '>' at position 4, but found 'list'.
Loading history...
43
    public $tags = [];
44
45
    /** @var LinkRelations */
46
    public $linkRelations;
47
48
    /** @var LabelNameInterface */
49
    private $labelName;
50
51
    /**
52
     * @throws ParsingException
53
     *
54
     * @SuppressWarnings(PHPMD.BooleanArgumentFlag)
55
     */
56
    public function __construct(string $alpsFile, LabelNameInterface $labelName, bool $doFinalize = true)
57
    {
58
        $hyperReference = new HyperReference($labelName);
59
        $this->alpsFile = $alpsFile;
60
        [$profile, $descriptors] = (new SplitProfile())($alpsFile);
61
        /** @psalm-suppress all */
62
        [$this->schema, $this->title, $this->doc] = [$profile->{'$schema'} ?? '', $profile->alps->title ?? '', $profile->alps->doc->value ??  ''];
63
        /** @psalm-suppress all */
64
        $this->linkRelations = new LinkRelations($profile->alps->link ?? null);
65
        $instances = new Instances();
66
        $this->storeDescriptors($descriptors, $instances, $hyperReference);
67
        $this->instances = $instances->get();
68
        $this->labelName = $labelName;
69
        if ($doFinalize) {
70
            $this->finalize($hyperReference);
71
        }
72
    }
73
74
    /**
75
     * Return instances of raw descriptor
76
     *
77
     * @return array{0: array<string, stdClass>, 1: HyperReference}
78
     */
79
    public function export(string $id, string $alpsFile): array
80
    {
81
        if (! isset($this->instances[$id])) {
82
            throw new DescriptorNotFoundException($id);
83
        }
84
85
        $instance = $this->instances[$id];
86
        $instances = new Instances();
87
        $hyperReference = new HyperReference($this->labelName);
88
        assert(is_string($instance->id));
89
        if (property_exists($instance, 'rt')) {
90
            assert(is_string($instance->rt));
91
            $this->rt($instance->rt, $alpsFile, $hyperReference);
92
        }
93
94
        if (! property_exists($instance, 'descriptor')) {
95
            return [[$instance->id => $instance], $hyperReference];
96
        }
97
98
        /** @var list<stdClass> $stdClasses */
99
        $stdClasses = $instance->descriptor;
100
        $this->storeDescriptors($stdClasses, $instances, $hyperReference);
101
        /** @var array<string, stdClass> $crawledInstances */
102
        $crawledInstances = [$instance->id => $instance];
103
104
        return [$instances->get() + $crawledInstances, $hyperReference];
105
    }
106
107
    private function rt(string $rt, string $alpsFile, HyperReference $hyperReference): void
108
    {
109
        $rtKey = substr($rt, 1);
110
        if (isset($this->instances[$rtKey])) {
111
            $hyperReference->add($alpsFile, $rt);
112
        }
113
    }
114
115
    private function finalize(HyperReference $hyperReference): void
116
    {
117
        $instances = $hyperReference->getInstances($this->instances);
118
        ksort($instances);
119
        $this->descriptors = (new CreateDescriptor())($instances);
120
        $this->links = (new CreateLinks($this->labelName))($this->descriptors, $instances);
121
        $this->scanTags();
122
    }
123
124
    /**
125
     * Set the raw descriptor on selection (instance or reference)
126
     *
127
     * @param list<stdClass> $rawDescriptors
128
     */
129
    private function storeDescriptors(array $rawDescriptors, Instances $instances, HyperReference $hyperReference): void
130
    {
131
        foreach ($rawDescriptors as $rawDescriptor) {
132
            if (property_exists($rawDescriptor, 'rt') && is_string($rawDescriptor->rt)) {
133
                $hyperReference->add($this->alpsFile, $rawDescriptor->rt);
134
            }
135
136
            if (property_exists($rawDescriptor, 'id')) {
137
                $this->storeRawDescriptor($rawDescriptor, $instances, $hyperReference);
138
                continue;
139
            }
140
141
            if (property_exists($rawDescriptor, 'href') && is_string($rawDescriptor->href)) {
142
                $hyperReference->add($this->alpsFile, $rawDescriptor->href);
143
                continue;
144
            }
145
146
            throw new InvalidDescriptorException((string) json_encode($rawDescriptor));
147
        }
148
    }
149
150
    private function storeRawDescriptor(stdClass $rawDescriptor, Instances $instances, HyperReference $hyperReference): void
151
    {
152
        assert(is_string($rawDescriptor->id));
153
        $instances->add($rawDescriptor);
154
        if (property_exists($rawDescriptor, 'descriptor')) {
155
            /** @psalm-suppress MixedAssignment */
156
            $descriptors = $rawDescriptor->descriptor;
157
            if (! is_array($descriptors)) {
158
                throw new DescriptorIsNotArrayException($rawDescriptor->id);
159
            }
160
161
            /** @var list<stdClass> $descriptors */
162
163
            $this->storeDescriptors($descriptors, $instances, $hyperReference);
164
        }
165
    }
166
167
    private function scanTags(): void
168
    {
169
        foreach ($this->descriptors as $descriptor) {
170
            foreach ($descriptor->tags as $tag) {
171
                $this->tags[$tag][] = $descriptor->id;
172
            }
173
        }
174
175
        ksort($this->tags);
176
    }
177
}
178