Completed
Pull Request — master (#19)
by
unknown
02:00
created

Translator::filteredByFields()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 0
cts 2
cp 0
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
crap 2
1
<?php
2
3
namespace leandrogehlen\querybuilder;
4
5
use yii\base\BaseObject;
6
use yii\helpers\ArrayHelper;
7
8
/**
9
 * Translator is used to build WHERE clauses from rules configuration
10
 *
11
 * The typical usage of Translator is as follows,
12
 *
13
 * ```php
14
 * public function actionIndex()
15
 * {
16
 *     $query = Customer::find();
17
 *     $rules = Yii::$app->request->post('rules');
18
 *
19
 *     if ($rules) {
20
 *         $translator = new Translator(Json::decode($rules));
21
 *         $query->andWhere($translator->where())
22
 *               ->addParams($translator->params());
23
 *     }
24
 *
25
 *     $dataProvider = new ActiveDataProvider([
26
 *         'query' => $query,
27
 *     ]);
28
 *
29
 *     return $this->render('index', [
30
 *         'dataProvider' => $dataProvider,
31
 *     ]);
32
 * }
33
 * ```
34
 * @author Leandro Gehlen <[email protected]>
35
 */
36
class Translator extends BaseObject
37
{
38
    protected $_where;
39
    protected $_params = [];
40
    protected $_operators;
41
    protected $_filteredByFields = [];
42
43
    /**
44
     * Constructors.
45
     * @param array $data Rules configuraion
46
     * @param array $config the configuration array to be applied to this object.
47
     */
48 1
    public function __construct($data, $config = [])
49
    {
50 1
        parent::__construct($config);
51 1
        $this->_where = $this->buildWhere($data);
52 1
    }
53
54
    /**
55
     * @inheritdoc
56
     */
57 1
    public function init()
58
    {
59 1
        $this->_operators = [
60 1
            'equal' =>            '= ?',
61 1
            'not_equal' =>        '<> ?',
62
            'in' =>               ['op' => 'IN (?)',     'list' => true, 'sep' => ', ' ],
63
            'not_in' =>           ['op' => 'NOT IN (?)', 'list' => true, 'sep' => ', '],
64 1
            'less' =>             '< ?',
65 1
            'less_or_equal' =>    '<= ?',
66 1
            'greater' =>          '> ?',
67 1
            'greater_or_equal' => '>= ?',
68
            'between' =>          ['op' => 'BETWEEN ?',   'list' => true, 'sep' => ' AND '],
69
            'begins_with' =>      ['op' => 'LIKE ?',     'fn' => function($value){ return "$value%"; } ],
70
            'not_begins_with' =>  ['op' => 'NOT LIKE ?', 'fn' => function($value){ return "$value%"; } ],
71
            'contains' =>         ['op' => 'LIKE ?',     'fn' => function($value){ return "%$value%"; } ],
72
            'not_contains' =>     ['op' => 'NOT LIKE ?', 'fn' => function($value){ return "%$value%"; } ],
73
            'ends_with' =>        ['op' => 'LIKE ?',     'fn' => function($value){ return "%$value"; } ],
74
            'not_ends_with' =>    ['op' => 'NOT LIKE ?', 'fn' => function($value){ return "%$value"; } ],
75 1
            'is_empty' =>         '= ""',
76 1
            'is_not_empty' =>     '<> ""',
77 1
            'is_null' =>          'IS NULL',
78 1
            'is_not_null' =>      'IS NOT NULL'
79
        ];
80 1
    }
81
82
83
    /**
84
     * Encodes filter rule into SQL condition
85
     * @param string $field field name
86
     * @param string|array $type operator type
87
     * @param string|array $params query parameters
88
     * @return string encoded rule
89
     */
90 1
    protected function encodeRule($field, $type, $params)
91
    {
92 1
        $pattern = $this->_operators[$type];
93 1
        $keys = array_keys($params);
94
95 1
        if (is_string($pattern)) {
96 1
            $replacement = !empty($keys) ? $keys[0] : null;
97
        } else {
98 1
            $op = ArrayHelper::getValue($pattern, 'op');
99 1
            $list = ArrayHelper::getValue($pattern, 'list');
100 1
            if ($list){
101 1
                $sep = ArrayHelper::getValue($pattern, 'sep');
102 1
                $replacement = implode($sep, $keys);
103
            } else {
104 1
                $fn = ArrayHelper::getValue($pattern, 'fn');
105 1
                $replacement = key($params);
106 1
                $params[$replacement] = call_user_func($fn, $params[$replacement]);
107
            }
108 1
            $pattern = $op;
109
        }
110
111 1
        $this->_params = array_merge($this->_params, $params);
112 1
        return $field . " " . ($replacement ? str_replace("?", $replacement, $pattern) : $pattern);
113
    }
114
115
     /**
116
     * @param array $data rules configuration
117
     * @return string the WHERE clause
118
     */
119 1
    protected function buildWhere($data)
120
    {
121 1
        if (!isset($data['rules']) || !$data['rules']) {
122
            return '';
123
        }
124
125 1
        $where = [];
126 1
        $condition = " " . $data['condition'] . " ";
127
128 1
        foreach ($data['rules'] as $rule) {
129 1
            if (isset($rule['condition'])) {
130 1
                $where[] = $this->buildWhere($rule);
131
            } else {
132 1
                $params = [];
133 1
                $operator = $rule['operator'];
134 1
                $field = $rule['field'];
135 1
                $value = ArrayHelper::getValue($rule, 'value');
136
137 1
                if ($value !== null) {
138 1
                    $i = count($this->_params);
139
140 1
                    if (!is_array($value)) {
141 1
                        $value = [$value];
142
                    }
143
144 1
                    foreach ($value as $v) {
145 1
                        $params[":p$i"] = $v;
146 1
                        $i++;
147
                    }
148
                }
149 1
                $where[] = $this->encodeRule($field, $operator, $params);
150 1
                $this->_filteredByFields[$field] = true;
151
            }
152
        }        
153
154 1
        return  !empty($where) ? "(" . implode($condition, $where) . ")" :  '';
155
    }
156
157
    /**
158
     * Returns query WHERE condition.
159
     * @return string
160
     */
161 1
    public function where()
162
    {
163 1
        return $this->_where;
164
    }
165
166
    /**
167
     * Returns the parameters to be bound to the query.
168
     * @return array
169
     */
170 1
    public function params()
171
    {
172 1
        return $this->_params;
173
    }
174
175
    /**.
176
     * Returns array of rules which were applied.
177
     * @return array
178
     */
179
    public function filteredByFields()
180
    {
181
        return $this->_filteredByFields;
182
    }
183
184
    /**
185
     * Returns true if where condition not empty.
186
     * @return bool
187
     */
188
    public function hasWhere()
189
    {
190
        return  $this->_where && $this->_where !== '()';
191
    }
192
} 
193