Completed
Push — master ( ce0d98...2b6032 )
by Mehmet
02:11
created

SQL::buildQueryFilters()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 11
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 4

Importance

Changes 3
Bugs 0 Features 0
Metric Value
c 3
b 0
f 0
dl 0
loc 11
ccs 8
cts 8
cp 1
rs 9.2
cc 4
eloc 7
nc 3
nop 2
crap 4
1
<?php
2
3
namespace Soupmix;
4
/*
5
SQL Adapter
6
*/
7
8
use Doctrine\DBAL\Connection;
9
10
11
class SQL implements Base
12
{
13
    protected $doctrine = null;
14
    protected $dbName = null;
15
16
17 3
    public function __construct($config, Connection $client)
18
    {
19 3
        $this->doctrine = $client;
20 3
        $this->dbName = $config['db_name'];
21 3
    }
22
23 2
    public function getConnection()
24
    {
25 2
        return $this->doctrine;
26
    }
27
28 3
    public function create($collection, $fields)
29
    {
30 3
        $schemaManager = $this->doctrine->getSchemaManager();
31 3
        $table = new SQLTable($schemaManager, $collection, $fields);
32 3
        return $table->createTable();
33
    }
34
35
36 3
    public function drop($collection)
37
    {
38 3
        $schemaManager = $this->doctrine->getSchemaManager();
39 3
        if ($schemaManager->tablesExist([$collection])) {
40 3
            return $schemaManager->dropTable($collection);
41
        }
42 1
        return null;
43
    }
44
45
    public function truncate($collection)
46
    {
47
        return $this->client->doctrine->query('TRUNCATE TABLE `' . $collection . '`');
0 ignored issues
show
Bug introduced by
The property client does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
48
    }
49
50
    public function createIndexes($collection, $fields)
51
    {
52
53
        $schemaManager = $this->doctrine->getSchemaManager();
54
        $table = new SQLTable($schemaManager, $collection, $fields);
55
        return $table->createIndexes();
0 ignored issues
show
Bug introduced by
The method createIndexes() does not seem to exist on object<Soupmix\SQLTable>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
56
    }
57
58 3
    public function insert($collection, $values)
59
    {
60 3
        $insertion = $this->doctrine->insert($collection, $values);
61 3
        if($insertion !== 0) {
62 3
            return $this->doctrine->lastInsertId();
63
        }
64
        return null;
65
    }
66
67
    public function update($collection, $filter, $values)
68
    {
69
        return $this->doctrine->update($collection, $values, $filter);
70
    }
71
72 2
    public function delete($collection, $filter)
73
    {
74 2
        $numberOfDeletedItems = $this->doctrine->delete($collection, $filter);
75 2
        if ($numberOfDeletedItems>0) {
76 2
            return 1;
77
        }
78
        return 0;
79
    }
80
81 1
    public function get($collection, $docId)
82
    {
83 1
        return $this->doctrine->fetchAssoc('SELECT * FROM ' . $collection . ' WHERE id = ?', array($docId));
84
    }
85
86 1
    public function find($collection, $filters, $fields = null, $sort = null, $offset = 0, $limit = 25, $debug = false)
87
    {
88 1
        $query = $this->query($collection);
89 1
        foreach ($filters as $filter => $value) {
90 1
            if (is_array($value)) {
91 1
                $query->orFilters($value);
92 1
            } else {
93 1
                $query->andFilter($filter, $value);
94
            }
95 1
        }
96 1
        return $query->returnFields($fields)
97 1
            ->sortFields($sort)
98 1
            ->offset($offset)
99 1
            ->limit($limit)
100 1
            ->run();
101
    }
102
103 2
    public function buildQuery($collection, $filters)
104
    {
105 2
        $queryBuilder = $this->doctrine->createQueryBuilder();
106 2
        $queryBuilder->from($collection);
107 2
        if ($filters === null) {
108
            return $queryBuilder;
109
        }
110 2
        return $this->buildQueryFilters($queryBuilder, $filters);
111
    }
112
113 2
    protected function buildQueryFilters($queryBuilder, $filters)
114
    {
115 2
        foreach ($filters as $key => $value) {
116 2
            if (strpos($key, '__') === false && is_array($value)) {
117 2
                $queryBuilder = $this->buildQueryForOr($queryBuilder, $value);
118 2
                continue;
119
            }
120 2
            $queryBuilder = $this->buildQueryForAnd($queryBuilder, $key, $value);
121 2
        }
122 2
        return $queryBuilder;
123
    }
124
125 2
    protected function buildQueryForAnd($queryBuilder, $key, $value)
126
    {
127 2
        $sqlOptions = self::buildFilter([$key => $value]);
128 2 View Code Duplication
        if (in_array($sqlOptions['method'], ['in', 'notIn'])) {
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
            $queryBuilder->andWhere(
130
                $queryBuilder->expr()->{$sqlOptions['method']}( $sqlOptions['key'], $sqlOptions['value'])
131
            );
132
            return $queryBuilder;
133
        }
134 2
        $queryBuilder->andWhere(
135 2
                '`'.$sqlOptions['key'].'`'
136 2
                . ' ' . $sqlOptions['operand']
137 2
                . ' ' . $queryBuilder->createNamedParameter($sqlOptions['value'])
138 2
            );
139 2
        return $queryBuilder;
140
    }
141 2
    protected function buildQueryForOr($queryBuilder, $value)
142
    {
143 2
        $orQuery =[];
144 2
        foreach ($value as $orValue) {
145 2
            $subKey = array_keys($orValue)[0];
146 2
            $subValue = $orValue[$subKey];
147 2
            $sqlOptions = self::buildFilter([$subKey => $subValue]);
148 2 View Code Duplication
            if (in_array($sqlOptions['method'], ['in', 'notIn'])) {
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...
149 1
                $orQuery[] =  $queryBuilder->expr()->{$sqlOptions['method']}( $sqlOptions['key'], $sqlOptions['value']);
150 1
                continue;
151
            }
152 2
            $orQuery[] =
153 2
                '`'.$sqlOptions['key'].'`'
154 2
                . ' ' . $sqlOptions['operand']
155 2
                . ' ' . $queryBuilder->createNamedParameter($sqlOptions['value']);
156
157 2
        }
158 2
        $queryBuilder->andWhere(
159 2
            '(' . implode(' OR ', $orQuery) . ')'
160 2
        );
161 2
        return $queryBuilder;
162
    }
163
164 2
    public function query($collection)
165
    {
166 2
        return new SQLQueryBuilder($collection, $this);
167
    }
168
169 2
    public static function buildFilter($filter)
170
    {
171 2
        $key = array_keys($filter)[0];
172 2
        $value = $filter[$key];
173 2
        $operator = ' = ';
174 2
        $method = 'eq';
175
        $options =[
176 2
            'gte'       => ['method' => 'gte', 'operand' => ' >= '],
177 2
            'gt'        => ['method' => 'gt', 'operand' => ' > '],
178 2
            'lte'       => ['method' => 'lte', 'operand' => ' <= '],
179 2
            'lt'        => ['method' => 'lt', 'operand' => ' < '],
180 2
            'in'        => ['method' => 'in', 'operand' => ' IN '],
181 2
            '!in'       => ['method' => 'notIn', 'operand' => ' NOT IN '],
182 2
            'not'       => ['method' => 'not', 'operand' => ' NOT '],
183 2
            'wildcard'  => ['method' => 'like', 'operand' => ' LIKE '],
184 2
            'prefix'    => ['method' => 'like', 'operand' => ' LIKE '],
185 2
        ];
186 2
        if (strpos($key, '__') !== false) {
187 2
            preg_match('/__(.*?)$/i', $key, $matches);
188 2
            $key        = str_replace($matches[0], '', $key);
189 2
            $queryOperator   = $matches[1];
190 2
            $method     = $options[$queryOperator]['method'];
191 2
            $operator   = $options[$queryOperator]['operand'];
192
            switch ($queryOperator) {
193 2
                case 'wildcard':
194 1
                    $value = '%'.str_replace(array('?', '*'), array('_', '%'), $value).'%';
195 1
                    break;
196 2
                case 'prefix':
197 1
                    $value = $value.'%';
198 1
                    break;
199
            }
200 2
        }
201
        return [
202 2
            'key'       => $key,
203 2
            'operand'   => $operator,
204 2
            'method'    => $method,
205
            'value'     => $value
206 2
        ];
207
    }
208
209
}
210