Completed
Push — feature/update_all_the_things ( 324e2a...b9ab83 )
by Lucas
30:14 queued 13:01
created

RqlTranslator::translateSearchNode()   C

Complexity

Conditions 7
Paths 13

Size

Total Lines 46
Code Lines 28

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 30
CRAP Score 7.0016

Importance

Changes 4
Bugs 0 Features 0
Metric Value
dl 0
loc 46
ccs 30
cts 31
cp 0.9677
rs 6.7272
c 4
b 0
f 0
cc 7
eloc 28
nc 13
nop 2
crap 7.0016
1
<?php
2
/**
3
 * Translator for RQL modification before execution
4
 */
5
6
namespace Graviton\RestBundle\Service;
7
8
use Graviton\Rql\Node\SearchNode;
9
use MongoDate;
10
use Xiag\Rql\Parser\AbstractNode;
11
use Xiag\Rql\Parser\DataType\Glob;
12
use Xiag\Rql\Parser\Node\AbstractQueryNode;
13
use Xiag\Rql\Parser\Node\Query\LogicOperator\AndNode;
14
use Xiag\Rql\Parser\Node\Query\LogicOperator\OrNode;
15
use Xiag\Rql\Parser\Node\Query\ScalarOperator\EqNode;
16
use Xiag\Rql\Parser\Node\Query\ScalarOperator\GeNode;
17
use Xiag\Rql\Parser\Node\Query\ScalarOperator\LeNode;
18
use Xiag\Rql\Parser\Node\Query\ScalarOperator\LikeNode;
19
use Xiag\Rql\Parser\Query;
20
21
/**
22
 * Class RqlTranslator
23
 *
24
 * @package Graviton\RestBundle\Service
25
 *
26
 * @author  List of contributors <https://github.com/libgraviton/graviton/graphs/contributors>
27
 * @license http://opensource.org/licenses/gpl-license.php GNU Public License
28
 * @link    http://swisscom.ch
29
 */
30
class RqlTranslator
31
{
32
33
    /**
34
     * Translate a search node into LikeNodes connected with an OrNode
35
     *
36
     * @param  SearchNode $searchNode   The given search node to transform
37
     * @param  array      $searchFields Which fields should be searched for all terms in SearchNode
38
     * @return SearchNode|OrNode|EqNode
39
     */
40 10
    public function translateSearchNode(SearchNode $searchNode, $searchFields = array())
41
    {
42 10
        if (sizeof($searchFields) === 0) {
43
            return new EqNode('id', "");
44
        }
45
46 10
        $orNode = new OrNode();
47
48 10
        foreach ($searchFields as $searchField) {
0 ignored issues
show
Coding Style introduced by
Blank line found at start of control structure
Loading history...
49
50 10
            foreach ($searchNode->getSearchTerms() as $searchTerm) {
51 8
                $searchGlob = new Glob('*' . $searchTerm . '*');
52 8
                $likeNode = new LikeNode($searchField, $searchGlob);
53 8
                $orNode->addQuery($likeNode);
54
55 8
                if (is_numeric($searchTerm)) {
56
                    # handle numbers
57 2
                    $searchNumber = (int) $searchTerm;
58 2
                    $numberNode = new EqNode($searchField, $searchNumber);
59 2
                    $orNode->addQuery($numberNode);
60 1
                }
61
62 8
                if ($this->isParsableDate($searchTerm)) {
63
                    # handle dates
64 2
                    $parsedDate = new \DateTime($searchTerm);
65 2
                    $searchDate = $parsedDate->format('Y-m-d');
66
67 2
                    $dateNode = new AndNode();
68 2
                    $searchFrom = new MongoDate(strtotime($searchDate." 00:00:00"));
69 2
                    $searchTo = new MongoDate(strtotime($searchDate." 23:59:59"));
70 2
                    $dateFrom = new GeNode($searchField, $searchFrom);
71 2
                    $dateTo = new LeNode($searchField, $searchTo);
72
73 2
                    $dateNode->addQuery($dateFrom);
74 2
                    $dateNode->addQuery($dateTo);
75 6
                    $orNode->addQuery($dateNode);
76 1
                }
77 5
            }
78 5
        }
79
80 10
        if (sizeof($orNode->getQueries()) > 0) {
81 8
            return $orNode;
82
        } else {
83 2
            return $searchNode;
84
        }
85
    }
86
87
    /**
88
     * Check Query for search nodes and translate them into corresponding like nodes
89
     *
90
     * @param AbstractNode $query        Query to translate
91
     * @param array        $searchFields Which fields should be searched for all terms in SearchNode
92
     * @return Query
93
     */
94 6
    public function translateSearchQuery(AbstractNode $query, $searchFields = array())
95
    {
96 6
        if (!($query instanceof Query)) {
97
            return $query;
98
        }
99
100 6
        $innerQuery = $query->getQuery();
101
102 6
        if ($innerQuery instanceof SearchNode) {
103
            $newNode = $this->translateSearchNode($innerQuery, $searchFields);
104
105
            if ($newNode instanceof OrNode) {
106
                $query->setQuery($newNode);
107
            }
108 3
        } elseif ($innerQuery instanceof AndNode) {
109 6
            $andNodeReplacement = new AndNode();
110 6
            foreach ($innerQuery->getQueries() as $innerNodeFromAnd) {
0 ignored issues
show
Coding Style introduced by
Blank line found at start of control structure
Loading history...
111
112 6
                if ($innerNodeFromAnd instanceof SearchNode) {
113
                    // Transform to OrNode with inner like queries and add to new query list
114 6
                    $andNodeReplacement->addQuery(
115 6
                        $this->translateSearchNode($innerNodeFromAnd, $searchFields)
116 3
                    );
117 3
                } else {
118
                    // Just recollect the node
119 6
                    $andNodeReplacement->addQuery($innerNodeFromAnd);
120
                }
121
0 ignored issues
show
Coding Style introduced by
Blank line found at end of control structure
Loading history...
122 3
            }
123
124 6
            $query->setQuery($andNodeReplacement);
125 3
        }
126
127 6
        return $query;
128
    }
129
130
    /**
131
     * Check if string can be parsed to date
132
     *
133
     * @param string $dateString The date string to be parsed
134
     * @return bool
135
     */
136 8
    protected function isParsableDate($dateString)
137
    {
138
        try {
139 8
            $date = new \DateTime($dateString);
140 7
        } catch (\Exception $e) {
141
            // Expected here, go on
142 6
            return false;
143
        }
144 2
        return true;
145
    }
146
}
147