Completed
Push — master ( a5abe6...691192 )
by Dominik
04:44 queued 52s
created

Generator::appendChildren()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 8
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 4
nc 2
nop 3
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Saxulum\ElasticSearchQueryBuilder;
6
7
use PhpParser\Node\Arg;
8
use PhpParser\Node\Expr;
9
use PhpParser\Node\Expr\Assign;
10
use PhpParser\Node\Expr\ConstFetch;
11
use PhpParser\Node\Expr\MethodCall;
12
use PhpParser\Node\Expr\New_;
13
use PhpParser\Node\Expr\Variable;
14
use PhpParser\Node\Name;
15
use PhpParser\Node\Scalar\DNumber;
16
use PhpParser\Node\Scalar\LNumber;
17
use PhpParser\Node\Scalar\String_;
18
use PhpParser\PrettyPrinter\Standard;
19
20
final class Generator
21
{
22
    /**
23
     * @param $query
24
     * @return string
25
     */
26
    public function generateByJson($query): string
27
    {
28
        $data = json_decode($query, false);
29
        if (JSON_ERROR_NONE !== json_last_error()) {
30
            throw new \InvalidArgumentException(sprintf('Message: %s, query: %s', json_last_error_msg(), $query));
31
        }
32
33
        $stmts = [$this->createQueryBuilderNode()];
34
35
        $queryBuilder = new Variable('queryBuilder');
36
37
        if ($data instanceof \stdClass) {
38
            $stmts[] = $this->appendChildrenToObjectNode($queryBuilder, $queryBuilder, $data);
39
        } else {
40
            $stmts[] = $this->appendChildrenToArrayNode($queryBuilder, $queryBuilder, $data);
41
        }
42
43
        $prettyPrinter = new Standard();
44
45
        $code = $prettyPrinter->prettyPrint($stmts);
46
47
        return $code;
48
    }
49
50
    /**
51
     * @return Expr
52
     */
53
    private function createQueryBuilderNode(): Expr
54
    {
55
        return new Assign(new Variable('queryBuilder'), new New_(new Name('\\' . QueryBuilder::class)));
56
    }
57
58
    /**
59
     * @param Expr $expr
60
     * @return Expr
61
     */
62
    private function createObjectNode(Expr $expr): Expr
63
    {
64
        return new MethodCall($expr, 'objectNode');
65
    }
66
67
    /**
68
     * @param Expr $expr
69
     * @return Expr
70
     */
71
    private function createArrayNode(Expr $expr): Expr
72
    {
73
        return new MethodCall($expr, 'arrayNode');
74
    }
75
76
    /**
77
     * @param Expr $expr
78
     * @param string|float|int|bool|null $value
79
     * @return Expr
80
     */
81
    private function createScalarNode(Expr $expr, $value): Expr
82
    {
83
        if (is_string($value)) {
84
            $valueExpr = new String_($value);
85
        } elseif (is_int($value)) {
86
            $valueExpr = new LNumber($value);
87
        } elseif (is_float($value)) {
88
            $valueExpr = new DNumber($value);
89
        } elseif (is_bool($value)) {
90
            $valueExpr = new ConstFetch(new Name($value ? 'true' : 'false'));
91
        } else {
92
            $valueExpr = new ConstFetch(new Name('null'));
93
        }
94
95
        // todo: append value based on type...
96
        return new MethodCall($expr, 'scalarNode', [new Arg($valueExpr)]);
97
    }
98
99
    /**
100
     * @param Expr $expr
101
     * @param \stdClass|array $data
102
     * @return Expr
103
     */
104
    private function appendChildren(Expr $queryBuilder, Expr $expr, $data): Expr
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
105
    {
106
        if ($data instanceof \stdClass) {
107
            return $this->appendChildrenToObjectNode($queryBuilder, $expr, $data);
108
        }
109
110
        return $this->appendChildrenToArrayNode($queryBuilder, $expr, $data);
111
    }
112
113
    /**
114
     * @param Expr $queryBuilder
115
     * @param Expr $expr
116
     * @param array $data
117
     * @return Expr
118
     */
119
    private function appendChildrenToArrayNode(Expr $queryBuilder, Expr $expr, array $data)
120
    {
121
        foreach ($data as $key => $value) {
122
            if ($value instanceof \stdClass) {
123
                $expr = new MethodCall($expr, 'addToArrayNode', [new Arg($this->createObjectNode($queryBuilder))]);
124
                $expr = $this->appendChildrenToObjectNode($queryBuilder, $expr, $value);
125
                $expr = new MethodCall($expr, 'end');
126
            } elseif (is_array($value)) {
127
                $expr = new MethodCall($expr, 'addToArrayNode', [new Arg($this->createArrayNode($queryBuilder))]);
128
                $expr = $this->appendChildrenToArrayNode($queryBuilder, $expr, $value);
129
                $expr = new MethodCall($expr, 'end');
130
            } else {
131
                $expr = new MethodCall($expr, 'addToArrayNode', [new Arg($this->createScalarNode($queryBuilder, $value))]);
132
            }
133
        }
134
        return $expr;
135
    }
136
137
    /**
138
     * @param Expr $expr
139
     * @param \stdClass $data
140
     * @return Expr
141
     */
142
    private function appendChildrenToObjectNode(Expr $queryBuilder, Expr $expr, \stdClass $data)
143
    {
144
        foreach ($data as $key => $value) {
0 ignored issues
show
Bug introduced by
The expression $data of type object<stdClass> is not traversable.
Loading history...
145
            if ($value instanceof \stdClass) {
146
                $expr = new MethodCall($expr, 'addToObjectNode', [new Arg(new String_($key)), new Arg($this->createObjectNode($queryBuilder))]);
147
                $expr = $this->appendChildrenToObjectNode($queryBuilder, $expr, $value);
148
                $expr = new MethodCall($expr, 'end');
149
            } elseif (is_array($value)) {
150
                $expr = new MethodCall($expr, 'addToObjectNode', [new Arg(new String_($key)), new Arg($this->createArrayNode($queryBuilder))]);
151
                $expr = $this->appendChildrenToArrayNode($queryBuilder, $expr, $value);
152
                $expr = new MethodCall($expr, 'end');
153
            } else {
154
                $expr = new MethodCall($expr, 'addToObjectNode', [new Arg(new String_($key)), new Arg($this->createScalarNode($queryBuilder, $value))]);
155
            }
156
        }
157
158
        return $expr;
159
    }
160
}
161