Completed
Push — master ( 20fdec...d8ea99 )
by ignace nyamagana
10:33
created

Dataset::fromIterable()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 2

Importance

Changes 0
Metric Value
eloc 4
c 0
b 0
f 0
dl 0
loc 8
ccs 2
cts 2
cp 1
rs 10
cc 2
nc 2
nop 1
crap 2
1
<?php
2
3
/**
4
 * League.Period (https://period.thephpleague.com)
5
 *
6
 * (c) Ignace Nyamagana Butera <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
declare(strict_types=1);
13
14
namespace League\Period\Chart;
15
16
use League\Period\Period;
17
use League\Period\Sequence;
18
use function array_column;
19
use function count;
20
use function gettype;
21
use function is_scalar;
22
use function method_exists;
23
use function strlen;
24
25
final class Dataset implements Data
26
{
27
    /**
28
     * @var array<int, array{0:string, 1:Sequence}>.
29
     */
30
    private $pairs = [];
31
32
    /**
33
     * @var int
34
     */
35
    private $labelMaxLength = 0;
36
37
    /**
38
     * @var Period|null
39
     */
40
    private $boundaries;
41
42
    /**
43
     * constructor.
44
     */
45
    public function __construct(iterable $pairs = [])
46 39
    {
47
        $this->appendAll($pairs);
48 39
    }
49 33
50
    /**
51
     * Creates a new collection from a countable iterable structure.
52
     *
53
     * @param array|(\Countable&iterable) $items
54
     * @param ?LabelGenerator             $labelGenerator
55
     */
56
    public static function fromItems($items, ?LabelGenerator $labelGenerator = null): self
57 9
    {
58
        $nbItems = count($items);
59 9
        $items = (function () use ($items): \Iterator {
60 9
            foreach ($items as $key => $value) {
61
                yield $key => $value;
62 6
            }
63 6
        })();
64
65 6
        $labelGenerator = $labelGenerator ?? new LatinLetter();
66 3
67
        $pairs = new \MultipleIterator(\MultipleIterator::MIT_NEED_ALL|\MultipleIterator::MIT_KEYS_ASSOC);
68 3
        $pairs->attachIterator($labelGenerator->generate($nbItems), '0');
69
        $pairs->attachIterator($items, '1');
70
71 9
        return new self($pairs);
72
    }
73 9
74 9
    /**
75 9
     * Creates a new collection from a generic iterable structure.
76
     */
77 9
    public static function fromIterable(iterable $iterable): self
78
    {
79
        $dataset = new self();
80
        foreach ($iterable as $label => $item) {
81
            $dataset->append($label, $item);
82
        }
83 15
84
        return $dataset;
85 15
    }
86 15
87 12
    /**
88
     * {@inheritDoc}
89
     */
90 15
    public function appendAll(iterable $pairs): void
91
    {
92
        foreach ($pairs as [$label, $item]) {
93
            $this->append($label, $item);
94
        }
95
    }
96 39
97
    /**
98 39
     * {@inheritDoc}
99 21
     */
100
    public function append($label, $item): void
101 33
    {
102
        if (!is_scalar($label) && !method_exists($label, '__toString')) {
103
            throw new \TypeError('The label passed to '.__METHOD__.' must be a scalar or an stringable object, '.gettype($label).' given.');
104
        }
105
106 33
        if ($item instanceof Period) {
107
            $item = new Sequence($item);
108 33
        }
109 3
110
        if (!$item instanceof Sequence) {
111
            throw new \TypeError('The item passed to '.__METHOD__.' must be a '.Period::class.' or a '.Sequence::class.' instance, '.gettype($item).' given.');
112 30
        }
113 15
114
        $label = (string) $label;
115
        $this->setLabelMaxLength($label);
116 30
        $this->setBoundaries($item);
117 3
118
        $this->pairs[] = [$label, $item];
119
    }
120 27
121 27
    /**
122 27
     * Computes the label maximum length for the dataset.
123
     */
124 27
    private function setLabelMaxLength(string $label): void
125 27
    {
126
        $labelLength = strlen($label);
127
        if ($this->labelMaxLength < $labelLength) {
128
            $this->labelMaxLength = $labelLength;
129
        }
130 27
    }
131
132 27
    /**
133 27
     * Computes the Period boundary for the dataset.
134 27
     */
135
    private function setBoundaries(Sequence $sequence): void
136 27
    {
137
        if (null === $this->boundaries) {
138
            $this->boundaries = $sequence->boundaries();
139
140
            return;
141 27
        }
142
143 27
        $this->boundaries = $this->boundaries->merge(...$sequence);
144 27
    }
145
146 27
    /**
147
     * {@inheritDoc}
148
     */
149 18
    public function count(): int
150 18
    {
151
        return count($this->pairs);
152
    }
153
154
    /**
155 21
     * {@inheritDoc}
156
     */
157 21
    public function getIterator(): \Iterator
158
    {
159
        foreach ($this->pairs as $pair) {
160
            yield $pair;
161
        }
162
    }
163 3
164
    /**
165 3
     * {@inheritDoc}
166 3
     */
167
    public function jsonSerialize(): array
168 3
    {
169
        $mapper = static function (array $pair): array {
170
            return ['label' => $pair[0], 'item' => $pair[1]];
171
        };
172
173 3
        return array_map($mapper, $this->pairs);
174
    }
175
176 3
    /**
177 3
     * {@inheritDoc}
178
     */
179
    public function isEmpty(): bool
180
    {
181
        return [] === $this->pairs;
182
    }
183 18
184
    /**
185 18
     * {@inheritDoc}
186
     */
187
    public function labels(): array
188
    {
189
        return array_column($this->pairs, 0);
190
    }
191 6
192
    /**
193 6
     * {@inheritDoc}
194
     */
195
    public function items(): array
196
    {
197
        return array_column($this->pairs, 1);
198
    }
199 9
200
    /**
201 9
     * {@inheritDoc}
202
     */
203
    public function boundaries(): ?Period
204
    {
205
        return $this->boundaries;
206
    }
207 15
208
    /**
209 15
     * {@inheritDoc}
210
     */
211
    public function labelMaxLength(): int
212
    {
213
        return $this->labelMaxLength;
214
    }
215 6
216
    /**
217 6
     * {@inheritDoc}
218
     */
219
    public function withLabels(LabelGenerator $labelGenerator): Data
220
    {
221
        return self::fromItems($this->items(), $labelGenerator);
222
    }
223
}
224