Completed
Push — master ( 77488f...c36c52 )
by Dominik
02:18
created

Generator::appendChildrenToArrayNode()   B

Complexity

Conditions 6
Paths 10

Size

Total Lines 24
Code Lines 16

Duplication

Lines 7
Ratio 29.17 %

Importance

Changes 0
Metric Value
dl 7
loc 24
rs 8.5125
c 0
b 0
f 0
cc 6
eloc 16
nc 10
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 as PhpGenerator;
19
20
final class Generator
21
{
22
    /**
23
     * @var PhpGenerator
24
     */
25
    private $phpGenerator;
26
27
    /**
28
     * @param PhpGenerator $phpGenerator
29
     */
30
    public function __construct(PhpGenerator $phpGenerator)
31
    {
32
        $this->phpGenerator = $phpGenerator;
33
    }
34
35
    /**
36
     * @param $query
37
     * @return string
38
     */
39
    public function generateByJson($query): string
40
    {
41
        $data = json_decode($query, false);
42
        if (JSON_ERROR_NONE !== json_last_error()) {
43
            throw new \InvalidArgumentException(sprintf('Message: %s, query: %s', json_last_error_msg(), $query));
44
        }
45
46
        $stmts = [$this->createQueryBuilderNode()];
47
48
        $queryBuilder = new Variable('queryBuilder');
49
50
        if ($data instanceof \stdClass) {
51
            $stmts[] = $this->appendChildrenToObjectNode($queryBuilder, $queryBuilder, $data);
52
        } else {
53
            $stmts[] = $this->appendChildrenToArrayNode($queryBuilder, $queryBuilder, $data);
54
        }
55
56
        $code = $this->phpGenerator->prettyPrint($stmts);
57
58
        return $code;
59
    }
60
61
    /**
62
     * @return Expr
63
     */
64
    private function createQueryBuilderNode(): Expr
65
    {
66
        return new Assign(new Variable('queryBuilder'), new New_(new Name('\\' . QueryBuilder::class)));
67
    }
68
69
    /**
70
     * @param Expr $expr
71
     * @return Expr
72
     */
73
    private function createObjectNode(Expr $expr): Expr
74
    {
75
        return new MethodCall($expr, 'objectNode');
76
    }
77
78
    /**
79
     * @param Expr $expr
80
     * @return Expr
81
     */
82
    private function createArrayNode(Expr $expr): Expr
83
    {
84
        return new MethodCall($expr, 'arrayNode');
85
    }
86
87
    /**
88
     * @param Expr $expr
89
     * @param string|float|int|bool|null $value
90
     * @return Expr
91
     */
92
    private function createScalarNode(Expr $expr, $value): Expr
93
    {
94
        if (is_string($value)) {
95
            $valueExpr = new String_($value);
96
        } elseif (is_int($value)) {
97
            $valueExpr = new LNumber($value);
98
        } elseif (is_float($value)) {
99
            $valueExpr = new DNumber($value);
100
        } elseif (is_bool($value)) {
101
            $valueExpr = new ConstFetch(new Name($value ? 'true' : 'false'));
102
        } else {
103
            $valueExpr = new ConstFetch(new Name('null'));
104
        }
105
106
        return new MethodCall($expr, 'scalarNode', [new Arg($valueExpr)]);
107
    }
108
109
    /**
110
     * @param Expr $queryBuilder
111
     * @param Expr $expr
112
     * @param array $data
113
     * @return Expr
114
     */
115
    private function appendChildrenToArrayNode(Expr $queryBuilder, Expr $expr, array $data)
116
    {
117
        foreach ($data as $key => $value) {
118
            if ($value instanceof \stdClass) {
119
                $arguments = [new Arg($this->createObjectNode($queryBuilder))];
120
            } elseif (is_array($value)) {
121
                $arguments = [new Arg($this->createArrayNode($queryBuilder))];
122
            } else {
123
                $arguments = [new Arg($this->createScalarNode($queryBuilder, $value))];
124
            }
125
126
            $expr = new MethodCall($expr, 'addToArrayNode', $arguments);
127
128 View Code Duplication
            if ($value instanceof \stdClass) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
129
                $expr = $this->appendChildrenToObjectNode($queryBuilder, $expr, $value);
130
                $expr = new MethodCall($expr, 'end');
131
            } elseif (is_array($value)) {
132
                $expr = $this->appendChildrenToArrayNode($queryBuilder, $expr, $value);
133
                $expr = new MethodCall($expr, 'end');
134
            }
135
        }
136
137
        return $expr;
138
    }
139
140
    /**
141
     * @param Expr $expr
142
     * @param \stdClass $data
143
     * @return Expr
144
     */
145
    private function appendChildrenToObjectNode(Expr $queryBuilder, Expr $expr, \stdClass $data)
146
    {
147
        foreach ($data as $key => $value) {
0 ignored issues
show
Bug introduced by
The expression $data of type object<stdClass> is not traversable.
Loading history...
148
            if ($value instanceof \stdClass) {
149
                $arguments = [new Arg(new String_($key)), new Arg($this->createObjectNode($queryBuilder))];
150
            } elseif (is_array($value)) {
151
                $arguments = [new Arg(new String_($key)), new Arg($this->createArrayNode($queryBuilder))];
152
            } else {
153
                $arguments = [new Arg(new String_($key)), new Arg($this->createScalarNode($queryBuilder, $value))];
154
            }
155
156
            $expr = new MethodCall($expr, 'addToObjectNode', $arguments);
157
158 View Code Duplication
            if ($value instanceof \stdClass) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
159
                $expr = $this->appendChildrenToObjectNode($queryBuilder, $expr, $value);
160
                $expr = new MethodCall($expr, 'end');
161
            } elseif (is_array($value)) {
162
                $expr = $this->appendChildrenToArrayNode($queryBuilder, $expr, $value);
163
                $expr = new MethodCall($expr, 'end');
164
            }
165
        }
166
167
        return $expr;
168
    }
169
}
170