Completed
Push — master ( 764b4d...d8757f )
by Matteo
02:29
created

Parser::parseTreeExpression()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 13
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 3

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 13
ccs 8
cts 8
cp 1
rs 9.4285
cc 3
eloc 7
nc 3
nop 3
crap 3
1
<?php
2
3
namespace Mattbit\Flat\Query;
4
5
use Mattbit\Flat\Query\Expression\Factory;
6
use Mattbit\Flat\Query\Expression\Leaf\EqExpression;
7
use Mattbit\Flat\Query\Expression\Tree\AndExpression;
8
use Mattbit\Flat\Query\Expression\Tree\Expression as TreeExpression;
9
10
class Parser
11
{
12
    protected $factory;
13
14 8
    public function __construct(Factory $factory)
15
    {
16 8
        $this->factory = $factory;
17 8
    }
18
19
    /**
20
     * Parses a query and returns an ExpressionInterface.
21
     * That’s the core logic of the database.
22
     *
23
     * @param $query
24
     *
25
     * @return ExpressionInterface
26
     */
27 8
    public function parse(array $query)
28
    {
29 8
        return $this->parseExpression($query);
30
    }
31
32 8
    protected function parseExpression($element, $path = null)
33
    {
34 8
        $expressions = [];
35
36
        // If the element is a simple value, we return an EqualityExpression.
37 8
        if (!is_array($element)) {
38 2
            return new EqExpression($path, $element);
39
        }
40
41
        // Otherwise we parse each nested expression. If we find an operator
42
        // we parse the expression, otherwise we recursively call
43
        // `parseExpression` with the nested path.
44 8
        foreach ($element as $key => $value) {
45 8
            if ($this->isOperator($key)) {
46 6
                $expressions[] = $this->parseOperator($key, $value, $path);
47 5
            } else {
48 7
                $nextPath = $path ? "{$path}.{$key}" : $key;
49 7
                $expressions[] = $this->parseExpression($value, $nextPath);
50
            }
51 7
        }
52
53
        // If we have one expression, we just return that. If there are
54
        // more than one, we should wrap them into a LogicAnd.
55 7
        if (count($expressions) === 1) {
56 7
            return $expressions[0];
57
        }
58
59 2
        return new AndExpression($expressions);
60
    }
61
62 6
    protected function parseOperator($operator, $value, $path)
63
    {
64 6
        $expression = $this->factory->make($operator, $path, $value);
65
66
        // If the expression is a TreeExpression we must parse the nested
67
        // elements and add them to the expression.
68 6
        if ($expression instanceof TreeExpression) {
69 3
            return $this->parseTreeExpression($expression, $value, $path);
70
        }
71
72 5
        return $expression;
73
    }
74
75 3
    protected function parseTreeExpression(TreeExpression $expression, $element, $path)
76
    {
77 3
        if (!is_array($element)) {
78 1
            $class = get_class($expression);
79 1
            throw new \Exception("The `{$class}` element must be an array");
80
        }
81
82 2
        foreach ($element as $value) {
83 2
            $expression->add($this->parseExpression($value, $path));
84 2
        }
85
86 2
        return $expression;
87
    }
88
89 8
    protected function isOperator($key)
90
    {
91 8
        return $key[0] === '$';
92
    }
93
}
94