GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — master ( 61bf69...3a1917 )
by Nicholas
03:32
created

FileRepository   B

Complexity

Total Complexity 30

Size/Duplication

Total Lines 278
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 16

Importance

Changes 7
Bugs 1 Features 2
Metric Value
wmc 30
c 7
b 1
f 2
lcom 1
cbo 16
dl 0
loc 278
rs 8.4614

17 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 13 1
A getByCodepoint() 0 12 2
A getByCodepoints() 0 6 1
A yieldByCodepoints() 0 8 3
A getFileByCodepoint() 0 10 2
A addMany() 0 13 2
A createFileWithCharacters() 0 7 1
A flattenCharacters() 0 12 2
A flattenRanges() 0 11 2
A addCharactersToAggregators() 0 4 1
A writeAggregations() 0 8 2
A getAll() 0 6 1
A readAll() 0 12 3
A getCodepointsByBlock() 0 8 1
A getCodepointsByCategory() 0 8 1
A resolveCodepointsByProperty() 0 15 3
A count() 0 11 2
1
<?php
2
3
namespace UCD\Infrastructure\Repository\CharacterRepository;
4
5
use UCD\Exception;
6
use UCD\Unicode\Character;
7
use UCD\Unicode\Character\Collection;
8
use UCD\Unicode\Character\Properties\General\Block;
9
use UCD\Unicode\Character\Properties\General\GeneralCategory;
10
use UCD\Unicode\Character\Repository;
11
use UCD\Unicode\Character\Repository\CharacterNotFoundException;
12
use UCD\Unicode\Character\WritableRepository;
13
use UCD\Unicode\Codepoint;
14
use UCD\Unicode\Codepoint\AggregatorRelay;
15
use UCD\Unicode\CodepointAssigned;
16
17
use UCD\Infrastructure\Repository\CharacterRepository\FileRepository\CharacterSlicer;
18
use UCD\Infrastructure\Repository\CharacterRepository\FileRepository\Property;
19
use UCD\Infrastructure\Repository\CharacterRepository\FileRepository\PropertyAggregators;
20
use UCD\Infrastructure\Repository\CharacterRepository\FileRepository\PropertyFileDirectory;
21
use UCD\Infrastructure\Repository\CharacterRepository\FileRepository\Range;
22
use UCD\Infrastructure\Repository\CharacterRepository\FileRepository\RangeFile;
23
use UCD\Infrastructure\Repository\CharacterRepository\FileRepository\RangeFileDirectory;
24
use UCD\Infrastructure\Repository\CharacterRepository\FileRepository\Serializer;
25
26
class FileRepository implements WritableRepository
27
{
28
    use Repository\Capability\Notify;
29
30
    const DEFAULT_SLICE_SIZE = 1000;
31
32
    /**
33
     * @var RangeFileDirectory
34
     */
35
    private $charactersDirectory;
36
37
    /**
38
     * @var PropertyFileDirectory
39
     */
40
    private $propertiesDirectory;
41
42
    /**
43
     * @var PropertyAggregators|AggregatorRelay[]
44
     */
45
    private $aggregators;
46
47
    /**
48
     * @var Serializer
49
     */
50
    private $serializer;
51
52
    /**
53
     * @var int
54
     */
55
    private $sliceSize;
56
57
    /**
58
     * @param RangeFileDirectory $charactersDirectory
59
     * @param PropertyFileDirectory $propertiesDirectory
60
     * @param PropertyAggregators $aggregators
61
     * @param Serializer $serializer
62
     * @param int $sliceSize
63
     */
64
    public function __construct(
65
        RangeFileDirectory $charactersDirectory,
66
        PropertyFileDirectory $propertiesDirectory,
67
        PropertyAggregators $aggregators,
68
        Serializer $serializer,
69
        $sliceSize = self::DEFAULT_SLICE_SIZE
70
    ) {
71
        $this->charactersDirectory = $charactersDirectory;
72
        $this->serializer = $serializer;
73
        $this->sliceSize = $sliceSize;
74
        $this->propertiesDirectory = $propertiesDirectory;
75
        $this->aggregators = $aggregators;
76
    }
77
78
    /**
79
     * {@inheritDoc}
80
     */
81
    public function getByCodepoint(Codepoint $codepoint)
82
    {
83
        $value = $codepoint->getValue();
84
        $file = $this->getFileByCodepoint($codepoint);
85
        $characters = $file->read();
86
87
        if (!array_key_exists($value, $characters)) {
88
            throw CharacterNotFoundException::withCodepoint($codepoint);
89
        }
90
91
        return $this->serializer->unserialize($characters[$value]);
92
    }
93
94
    /**
95
     * {@inheritDoc}
96
     */
97
    public function getByCodepoints(Codepoint\Collection $codepoints)
98
    {
99
        return new Character\Collection(
0 ignored issues
show
Bug Best Practice introduced by
The return type of return new \UCD\Unicode\...depoints($codepoints)); (UCD\Unicode\Character\Collection) is incompatible with the return type declared by the interface UCD\Unicode\Character\Repository::getByCodepoints of type UCD\Unicode\CodepointAssigned[].

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
100
            $this->yieldByCodepoints($codepoints)
101
        );
102
    }
103
104
    /**
105
     * @param Codepoint\Collection $codepoints
106
     * @return \Generator
107
     */
108
    private function yieldByCodepoints(Codepoint\Collection $codepoints)
109
    {
110
        foreach ($codepoints as $codepoint) {
111
            try {
112
                yield $this->getByCodepoint($codepoint);
113
            } catch (CharacterNotFoundException $e) { }
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
114
        }
115
    }
116
117
    /**
118
     * @param Codepoint $codepoint
119
     * @return RangeFile
120
     * @throws CharacterNotFoundException
121
     */
122
    private function getFileByCodepoint(Codepoint $codepoint)
123
    {
124
        $file = $this->charactersDirectory->getFileFromValue($codepoint->getValue());
125
126
        if ($file === null) {
127
            throw CharacterNotFoundException::withCodepoint($codepoint);
128
        }
129
130
        return $file;
131
    }
132
133
    /**
134
     * {@inheritDoc}
135
     */
136
    public function addMany(Collection $characters)
137
    {
138
        $slices = CharacterSlicer::slice($characters, $this->sliceSize);
139
140
        foreach ($slices as $range => $chunk) {
141
            /** @var Range $range */
142
            $this->createFileWithCharacters($range, $chunk);
143
            $this->addCharactersToAggregators($chunk);
144
            $this->notify();
145
        }
146
147
        $this->writeAggregations();
148
    }
149
150
    /**
151
     * @param Range $range
152
     * @param CodepointAssigned[] $characters
153
     * @return CodepointAssigned[]
154
     */
155
    private function createFileWithCharacters(Range $range, array $characters)
156
    {
157
        $this->charactersDirectory->writeRange(
158
            $range,
159
            $this->flattenCharacters($characters)
160
        );
161
    }
162
163
    /**
164
     * @param CodepointAssigned[] $characters
165
     * @return string[]
166
     */
167
    private function flattenCharacters(array $characters)
168
    {
169
        $flattened = [];
170
171
        foreach ($characters as $character) {
172
            $codepoint = $character->getCodepoint();
173
            $key = $codepoint->getValue();
174
            $flattened[$key] = $this->serializer->serialize($character);;
175
        }
176
177
        return $flattened;
178
    }
179
180
    /**
181
     * @param Codepoint\Range\Collection[] $ranges
182
     * @return string[]
183
     */
184
    public function flattenRanges(array $ranges)
185
    {
186
        $flattened = [];
187
188
        foreach ($ranges as $key => $range) {
189
            $range = $range->toArray();
190
            $flattened[$key] = $this->serializer->serialize($range);
191
        }
192
193
        return $flattened;
194
    }
195
196
    /**
197
     * @param CodepointAssigned[] $characters
198
     */
199
    private function addCharactersToAggregators(array $characters)
200
    {
201
        $this->aggregators->addCharacters($characters);
202
    }
203
204
    /**
205
     * @return bool
206
     */
207
    private function writeAggregations()
208
    {
209
        foreach ($this->aggregators as $property => $aggregator) {
210
            /** @var Property $property */
211
            $ranges = $this->flattenRanges($aggregator->getAllRanges());
212
            $this->propertiesDirectory->writeProperty($property, $ranges);
0 ignored issues
show
Documentation introduced by
$ranges is of type array<integer,string>, but the function expects a array<integer,object<UCD...\FileRepository\Range>>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
213
        }
214
    }
215
216
    /**
217
     * {@inheritDoc}
218
     */
219
    public function getAll()
220
    {
221
        return new Collection(
222
            $this->readAll()
223
        );
224
    }
225
226
    /**
227
     * @return \Generator
228
     */
229
    private function readAll()
230
    {
231
        $files = $this->charactersDirectory->getFiles();
232
233
        foreach ($files as $file) {
234
            $characters = $file->read();
235
236
            foreach ($characters as $i => $character) {
237
                yield $i => $this->serializer->unserialize($character);
238
            }
239
        }
240
    }
241
242
    /**
243
     * {@inheritDoc}
244
     */
245
    public function getCodepointsByBlock(Block $block)
246
    {
247
        return $this->resolveCodepointsByProperty(
248
            Property::ofType(Property::BLOCK),
249
            (string)$block,
250
            Repository\BlockNotFoundException::withBlock($block)
251
        );
252
    }
253
254
    /**
255
     * {@inheritDoc}
256
     */
257
    public function getCodepointsByCategory(GeneralCategory $category)
258
    {
259
        return $this->resolveCodepointsByProperty(
260
            Property::ofType(Property::GENERAL_CATEGORY),
261
            (string)$category,
262
            Repository\GeneralCategoryNotFoundException::withCategory($category)
263
        );
264
    }
265
266
    /**
267
     * @param Property $property
268
     * @param string $key
269
     * @param Exception $notFoundException
270
     * @return Codepoint\Range[]
271
     * @throws Exception
272
     */
273
    private function resolveCodepointsByProperty(Property $property, $key, Exception $notFoundException)
274
    {
275
        $file = $this->propertiesDirectory->getFileForProperty($property);
276
        $map = $file->read();
277
278
        $codepoints = array_key_exists($key, $map)
279
            ? $this->serializer->unserialize($map[$key])
280
            : [];
281
282
        if (count($codepoints) === 0) {
283
            throw $notFoundException;
284
        }
285
286
        return Codepoint\Range\Collection::fromArray($codepoints);
287
    }
288
289
    /**
290
     * {@inheritDoc}
291
     */
292
    public function count()
293
    {
294
        $files = $this->charactersDirectory->getFiles();
295
        $tally = 0;
296
297
        foreach ($files as $file) {
298
            $tally += $file->getTotal();
299
        }
300
301
        return $tally;
302
    }
303
}