Passed
Push — master ( c493bc...401b4d )
by Nikita
03:14 queued 11s
created

BinnMapEncoder::encode()   A

Complexity

Conditions 5
Paths 5

Size

Total Lines 30
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 18
c 1
b 0
f 0
dl 0
loc 30
rs 9.3554
cc 5
nc 5
nop 1
1
<?php
2
3
namespace Knik\Binn\Encoder\Containers;
4
5
use Knik\Binn\Binn;
6
use Knik\Binn\Contracts\BinnValueEncoder;
7
use Knik\Binn\Encoder\EncoderCollection;
8
use Knik\Binn\Encoder\Packer;
9
use Knik\Binn\Exceptions\InvalidArrayException;
10
11
class BinnMapEncoder implements BinnValueEncoder
12
{
13
    public const TYPE = Binn::BINN_MAP;
14
15
    /** @var EncoderCollection */
16
    private $encoders;
17
18
    public function __construct(EncoderCollection $encoders)
19
    {
20
        $this->encoders = $encoders;
21
    }
22
23
    public function encode($value): string
24
    {
25
        if (!$this->isArrayKeyNumbers($value)) {
26
            throw new InvalidArrayException('Array keys should be numbers');
27
        }
28
29
        $encodedData = '';
30
31
        foreach ($value as $key => $item) {
32
            /** @var BinnValueEncoder $encoder */
33
            foreach ($this->encoders->getAll() as $encoder) {
34
                if ($encoder->supportsEncoding($item)) {
35
                    $encodedData .= Packer::packInt32($key);
36
                    $encodedData .= $encoder->encode($item);
37
                    break;
38
                }
39
            }
40
        }
41
42
        $encodedType  = Packer::packUint8(self::TYPE);
43
        $encodedCount = Packer::packSize(count($value));
44
        $encodedSize  = Packer::packSize(
45
            strlen($encodedType) + strlen($encodedCount) + strlen($encodedData),
46
            true
47
        );
48
49
        return $encodedType
50
            . $encodedSize
51
            . $encodedCount
52
            . $encodedData;
53
    }
54
55
    public function supportsEncoding($value): bool
56
    {
57
        return is_array($value) && $this->isArrayKeyNumbers($value);
58
    }
59
60
    private function isArrayKeyNumbers($arr): bool
61
    {
62
        $arr = (array)$arr;
63
64
        if ([] === $arr) {
65
            return false;
66
        }
67
68
        foreach (array_keys($arr) as $key) {
69
            if (!is_int($key)) {
70
                return false;
71
            }
72
        }
73
74
        return true;
75
    }
76
}
77