Completed
Pull Request — master (#100)
by ignace nyamagana
05:05
created

Dataset   A

Complexity

Total Complexity 28

Size/Duplication

Total Lines 200
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 28
eloc 51
c 1
b 0
f 0
dl 0
loc 200
ccs 69
cts 69
cp 1
rs 10

16 Methods

Rating   Name   Duplication   Size   Complexity  
A fromCollection() 0 8 2
A fromSequence() 0 21 4
A labels() 0 3 1
A count() 0 3 1
A __construct() 0 3 1
A append() 0 19 5
A setBoundaries() 0 9 2
A labelMaxLength() 0 3 1
A items() 0 3 1
A withLabels() 0 3 1
A isEmpty() 0 3 1
A boundaries() 0 3 1
A getIterator() 0 4 2
A jsonSerialize() 0 5 1
A setLabelMaxLength() 0 5 2
A appendAll() 0 4 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_array;
22
use function is_scalar;
23
use function method_exists;
24
use function strlen;
25
26
final class Dataset implements Data
27
{
28
    /**
29
     * @var array<int, array{0:string, 1:Sequence}>.
30
     */
31
    private $pairs = [];
32
33
    /**
34
     * @var int
35
     */
36
    private $labelMaxLength = 0;
37
38
    /**
39
     * @var Period|null
40
     */
41
    private $boundaries;
42
43
    /**
44
     * constructor.
45
     */
46 39
    public function __construct(iterable $pairs = [])
47
    {
48 39
        $this->appendAll($pairs);
49 33
    }
50
51
    /**
52
     * Creates a new collection from a countable iterable structure.
53
     *
54
     * @param array|(\Countable&\Iterator)|(\Countable&\IteratorAggregate) $items
55
     * @param ?LabelGenerator                                              $labelGenerator
56
     */
57 9
    public static function fromSequence($items, ?LabelGenerator $labelGenerator = null): self
58
    {
59 9
        $nbItems = count($items);
60 9
        if (is_array($items)) {
61
            $items = (function () use ($items): \Iterator {
62 6
                foreach ($items as $key => $value) {
63 6
                    yield $key => $value;
64
                }
65 6
            })();
66 3
        } elseif ($items instanceof \IteratorAggregate) {
67
            /** @var \Iterator<Sequence|Period> $items */
68 3
            $items = $items->getIterator();
0 ignored issues
show
Bug introduced by
The method getIterator() does not exist on Iterator. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

68
            /** @scrutinizer ignore-call */ 
69
            $items = $items->getIterator();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
69
        }
70
71 9
        $labelGenerator = $labelGenerator ?? new LatinLetter();
72
73 9
        $iterator = new \MultipleIterator(\MultipleIterator::MIT_NEED_ALL|\MultipleIterator::MIT_KEYS_ASSOC);
74 9
        $iterator->attachIterator($labelGenerator->generate($nbItems), '0');
75 9
        $iterator->attachIterator($items, '1');
76
77 9
        return new self($iterator);
78
    }
79
80
    /**
81
     * Creates a new collection from a generic iterable structure.
82
     */
83 15
    public static function fromCollection(iterable $iterable): self
84
    {
85 15
        $dataset = new self();
86 15
        foreach ($iterable as $label => $item) {
87 12
            $dataset->append($label, $item);
88
        }
89
90 15
        return $dataset;
91
    }
92
93
    /**
94
     * {@inheritDoc}
95
     */
96 39
    public function appendAll(iterable $pairs): void
97
    {
98 39
        foreach ($pairs as [$label, $item]) {
99 21
            $this->append($label, $item);
100
        }
101 33
    }
102
103
    /**
104
     * {@inheritDoc}
105
     */
106 33
    public function append($label, $item): void
107
    {
108 33
        if (!is_scalar($label) && !method_exists($label, '__toString')) {
109 3
            throw new \TypeError('The label passed to '.__METHOD__.' must be a scalar or an stringable object, '.gettype($label).' given.');
110
        }
111
112 30
        if ($item instanceof Period) {
113 15
            $item = new Sequence($item);
114
        }
115
116 30
        if (!$item instanceof Sequence) {
117 3
            throw new \TypeError('The item passed to '.__METHOD__.' must be a '.Period::class.' or a '.Sequence::class.' instance, '.gettype($item).' given.');
118
        }
119
120 27
        $label = (string) $label;
121 27
        $this->setLabelMaxLength($label);
122 27
        $this->setBoundaries($item);
123
124 27
        $this->pairs[] = [$label, $item];
125 27
    }
126
127
    /**
128
     * Computes the label maximum length for the dataset.
129
     */
130 27
    private function setLabelMaxLength(string $label): void
131
    {
132 27
        $labelLength = strlen($label);
133 27
        if ($this->labelMaxLength < $labelLength) {
134 27
            $this->labelMaxLength = $labelLength;
135
        }
136 27
    }
137
138
    /**
139
     * Computes the Period boundary for the dataset.
140
     */
141 27
    private function setBoundaries(Sequence $sequence): void
142
    {
143 27
        if (null === $this->boundaries) {
144 27
            $this->boundaries = $sequence->boundaries();
145
146 27
            return;
147
        }
148
149 18
        $this->boundaries = $this->boundaries->merge(...$sequence);
150 18
    }
151
152
    /**
153
     * {@inheritDoc}
154
     */
155 21
    public function count(): int
156
    {
157 21
        return count($this->pairs);
158
    }
159
160
    /**
161
     * {@inheritDoc}
162
     */
163 3
    public function getIterator(): \Iterator
164
    {
165 3
        foreach ($this->pairs as $pair) {
166 3
            yield $pair;
167
        }
168 3
    }
169
170
    /**
171
     * {@inheritDoc}
172
     */
173 3
    public function jsonSerialize(): array
174
    {
175
        return array_map(function (array $pair): array {
176 3
            return ['label' => $pair[0], 'item' => $pair[1]];
177 3
        }, $this->pairs);
178
    }
179
180
    /**
181
     * {@inheritDoc}
182
     */
183 18
    public function isEmpty(): bool
184
    {
185 18
        return [] === $this->pairs;
186
    }
187
188
    /**
189
     * {@inheritDoc}
190
     */
191 6
    public function labels(): array
192
    {
193 6
        return array_column($this->pairs, 0);
194
    }
195
196
    /**
197
     * {@inheritDoc}
198
     */
199 9
    public function items(): array
200
    {
201 9
        return array_column($this->pairs, 1);
202
    }
203
204
    /**
205
     * {@inheritDoc}
206
     */
207 15
    public function boundaries(): ?Period
208
    {
209 15
        return $this->boundaries;
210
    }
211
212
    /**
213
     * {@inheritDoc}
214
     */
215 6
    public function labelMaxLength(): int
216
    {
217 6
        return $this->labelMaxLength;
218
    }
219
220
    /**
221
     * {@inheritDoc}
222
     */
223 6
    public function withLabels(LabelGenerator $labelGenerator): Data
224
    {
225 6
        return self::fromSequence($this->items(), $labelGenerator);
226
    }
227
}
228