Passed
Push — master ( d78aad...ae2861 )
by Dominik
02:24
created

IteratableToNodeConverter::getParentNode()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 8
ccs 4
cts 4
cp 1
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 4
nc 2
nop 1
crap 2
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Saxulum\ElasticSearchQueryBuilder\Converter;
6
7
use Saxulum\ElasticSearchQueryBuilder\Node\AbstractNode;
8
use Saxulum\ElasticSearchQueryBuilder\Node\AbstractParentNode;
9
use Saxulum\ElasticSearchQueryBuilder\Node\ArrayNode;
10
use Saxulum\ElasticSearchQueryBuilder\Node\ObjectNode;
11
12
final class IteratableToNodeConverter implements IteratableToNodeConverterInterface
13
{
14
    /**
15
     * @var ScalarToNodeConverterInterface
16
     */
17
    private $scalarToNodeConverter;
18
19
    /**
20
     * @param ScalarToNodeConverterInterface $scalarToNodeConverter
21
     */
22 3
    public function __construct(ScalarToNodeConverterInterface $scalarToNodeConverter)
23
    {
24 3
        $this->scalarToNodeConverter = $scalarToNodeConverter;
25 3
    }
26
27
    /**
28
     * @param array|\Traversable $data
29
     * @param string             $path
30
     *
31
     * @return AbstractParentNode
32
     *
33
     * @throws \InvalidArgumentException
34
     */
35 3
    public function convert($data, string $path = ''): AbstractParentNode
36
    {
37 3
        if (!is_array($data) && !$data instanceof \Traversable) {
38 1
            throw new \InvalidArgumentException(sprintf('Params need to be array or %s', \Traversable::class));
39
        }
40
41 2
        $isArray = $this->isArray($data);
42 2
        $parentNode = $this->getParentNode($isArray);
43
44 2
        foreach ($data as $key => $value) {
45 2
            $this->addChildNode($parentNode, $key, $value, $path, $isArray);
46
        }
47
48 1
        return $parentNode;
49
    }
50
51
    /**
52
     * @param array|\Traversable $data
53
     *
54
     * @return bool
55
     */
56 2
    private function isArray($data): bool
57
    {
58 2
        $counter = 0;
59 2
        foreach ($data as $key => $value) {
60 2
            if ($key !== $counter) {
61 2
                return false;
62
            }
63
64 2
            ++$counter;
65
        }
66
67 2
        return true;
68
    }
69
70
    /**
71
     * @param bool $isArray
72
     *
73
     * @return AbstractParentNode
74
     */
75 2
    private function getParentNode(bool $isArray): AbstractParentNode
76
    {
77 2
        if ($isArray) {
78 2
            return ArrayNode::create();
79
        }
80
81 2
        return ObjectNode::create();
82
    }
83
84
    /**
85
     * @param AbstractParentNode $parentNode
86
     * @param int|string         $key
87
     * @param mixed              $value
88
     * @param string             $path
89
     * @param bool               $isArray
90
     */
91 2
    private function addChildNode(AbstractParentNode $parentNode, $key, $value, string $path, bool $isArray)
92
    {
93 2
        $subPath = $this->getSubPath($path, $key, $isArray);
94 2
        $node = $this->getNode($value, $subPath);
95
96 1
        if ($isArray) {
97 1
            $parentNode->add($node);
98
        } else {
99 1
            $parentNode->add((string) $key, $node);
100
        }
101 1
    }
102
103
    /**
104
     * @param string     $path
105
     * @param string|int $key
106
     * @param bool       $isArray
107
     *
108
     * @return string
109
     */
110 2
    private function getSubPath(string $path, $key, bool $isArray): string
111
    {
112 2
        $key = (string) $key;
113
114 2
        if ($isArray) {
115 2
            return $path.'['.$key.']';
116
        }
117
118 2
        return $path !== '' ? $path.'.'.$key : $key;
119
    }
120
121
    /**
122
     * @param mixed  $value
123
     * @param string $path
124
     *
125
     * @return AbstractNode
126
     */
127 2
    private function getNode($value, string $path): AbstractNode
128
    {
129 2
        if (is_array($value) || $value instanceof \Traversable) {
130 2
            return $this->convert($value, $path);
131
        }
132
133 2
        return $this->scalarToNodeConverter->convert($value, $path);
134
    }
135
}
136