Completed
Push — master ( e6062f...aa5cfe )
by Vitaly
02:30
created

Query::whereCondition()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 18
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 1 Features 1
Metric Value
c 3
b 1
f 1
dl 0
loc 18
rs 9.4286
cc 1
eloc 3
nc 1
nop 1
1
<?php
2
namespace samsonframework\orm;
3
4
use samsonframework\orm\exception\EntityNotFound;
5
6
/**
7
 * Database query builder.
8
 * @author Vitaly Iegorov <[email protected]>
9
 * @version 2.0
10
 */
11
class Query extends QueryHandler implements QueryInterface
12
{
13
    /** @var string Class name for interacting with database */
14
    protected $class_name;
15
16
    /** @var array Collection of entity field names for sorting order */
17
    protected $sorting = array();
18
19
    /** @var array Collection of entity field names for grouping query results */
20
    protected $grouping = array();
21
22
    /** @var array Collection of query results limitations */
23
    protected $limitation = array();
24
25
    /** @var Condition Query base entity condition group */
26
    protected $own_condition;
27
28
    /** @var Condition Query entity condition group */
29
    protected $cConditionGroup;
30
31
    /** @var Database Database instance */
32
    protected $database;
33
34
    /** Serialization handler */
35
    public function __sleep()
36
    {
37
        // Do not serialize anything
38
        return array();
39
    }
40
41
    /**
42
     * Query constructor.
43
     *
44
     * @param Database Database instance
45
     */
46
    public function __construct(Database &$database)
47
    {
48
        $this->database = &$database;
49
        $this->flush();
50
    }
51
52
    /**
53
     * Reset all query parameters
54
     * @return self Chaining
55
     */
56
    public function flush()
57
    {
58
        $this->grouping = array();
59
        $this->limitation = array();
60
        $this->sorting = array();
61
62
        $this->cConditionGroup = new Condition();
63
        $this->own_condition = new Condition();
64
65
        return $this;
66
    }
67
68
    /**
69
     * Proxy function for performing database request and get collection of database record objects.
70
     * This method encapsulates all logic needed for query to be done before and after actual database
71
     * manager request.
72
     *
73
     * @param string $fetcher Database manager fetching method
74
     * @return mixed Return fetching function result
75
     */
76
    protected function innerExecute($fetcher = 'find')
77
    {
78
        // Call handlers stack
79
        $this->callHandlers();
80
81
        // Remove first argument
82
        $args = func_get_args();
83
        array_shift($args);
84
85
        /** @var RecordInterface[] $return Perform DB request */
86
        $return = call_user_func_array(array($this->database, $fetcher), $args);
87
88
        // Clear this query
89
        $this->flush();
90
91
        // Return bool or collection
92
        return $return;
93
    }
94
95
    /**
96
     * Perform database request and get collection of database record objects.
97
     *
98
     * @param mixed $return External variable to store query results
99
     * @return mixed If no arguments passed returns query results collection, otherwise query success status
100
     */
101 View Code Duplication
    public function exec(&$return = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
102
    {
103
        /** @var RecordInterface[] $return Perform DB request */
104
        $return = $this->innerExecute('find', $this->class_name, $this);
105
106
        // Return bool or collection
107
        return func_num_args() ? sizeof($return) : $return;
108
    }
109
110
    /**
111
     * Execute current query and receive amount of resulting rows.
112
     *
113
     * @param null|RecordInterface $return If variable is passed resulting amount of rows would be
114
     *                                      stored in this variable.
115
     * @return bool|RecordInterface If method is called with $return parameter then then bool
116
     *                                  with query result status would be returned, otherwise
117
     *                                  query rows count would be returned.
118
     */
119 View Code Duplication
    public function count(&$return = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
120
    {
121
        /** @var RecordInterface[] $return Perform DB request */
122
        $return = $this->innerExecute('count', $this->class_name, $this);
123
124
        // Return bool or collection
125
        return func_num_args() ? sizeof($return) : $return;
126
    }
127
128
    /**
129
     * Perform database request and get first record from results collection.
130
     *
131
     * @param mixed $return External variable to store query results
132
     * @return mixed If no arguments passed returns query results first database record object,
133
     * otherwise query success status
134
     */
135
    public function first(&$return = null)
136
    {
137
        // Add limitation
138
        $this->limit(1);
139
140
        /** @var RecordInterface[] $return Perform DB request */
141
        $return = $this->innerExecute('find', $this->class_name, $this);
142
        $return = sizeof($return) ? array_shift($return) : null;
143
144
        // Return bool or collection
145
        return func_num_args() ? sizeof($return) : $return;
146
    }
147
148
    /**
149
     * Perform database request and get array of record field values
150
     * @see \samson\activerecord\Query::execute()
151
     * @param string $fieldName Record field name to get value from
152
     * @param string $return External variable to store query results
153
     * @return mixed If no arguments passed returns query results first database record object,
154
     * otherwise query success status
155
     */
156 View Code Duplication
    public function fields($fieldName, &$return = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
157
    {
158
        /** @var RecordInterface[] $return Perform DB request */
159
        $return = $this->innerExecute('fetchColumn', $this->class_name, $this, $fieldName);
160
161
        // Return bool or collection
162
        return func_num_args() > 1 ? sizeof($return) : $return;
163
    }
164
165
    /**
166
     * Set query entity to work with.
167
     *
168
     * @param string $entity Entity identifier
169
     * @return Query Chaining
170
     * @throws EntityNotFound
171
     */
172
    public function entity($entity)
173
    {
174
        if (class_exists($entity)) {
175
            $this->flush();
176
            $this->class_name = $entity;
177
        } else {
178
            throw new EntityNotFound('['.$entity.'] not found');
179
        }
180
181
        return $this;
182
    }
183
184
    /**
185
     * Get correct query condition depending on entity field name.
186
     * If base entity has field with this name - use base entity condition
187
     * group, otherwise default condition group.
188
     *
189
     * @param string $fieldName Entity field name
190
     * @return Condition Correct query condition group
191
     */
192
    protected function &conditionGroup($fieldName)
193
    {
194
        if (property_exists($this->class_name, $fieldName)) {
195
            // Add this condition to base entity condition group
196
            return $this->own_condition;
197
        }
198
199
        return $this->cConditionGroup;
200
    }
201
202
    /**
203
     * Add query condition as prepared Condition instance.
204
     *
205
     * @param ConditionInterface $condition Condition to be added
206
     * @return self Chaining
207
     */
208
    public function whereCondition(ConditionInterface $condition)
209
    {
210
        // TODO: We cannot define to which group this condition is related
211
        $this->own_condition->addCondition($condition);
212
213
//        // Iterate condition arguments
214
//        foreach ($condition as $argument) {
215
//            // If passed condition group has another condition group as argument
216
//            if (is_a($argument, __NAMESPACE__ . '\Condition')) {
217
//                // Go deeper in recursion
218
//                $this->whereCondition($argument);
219
//            } else { // Otherwise add condition argument to correct condition group
220
//                $this->conditionGroup($argument->field)->addArgument($argument);
221
//            }
222
//        }
223
224
        return $this;
225
    }
226
227
    /**
228
     * Add condition to current query.
229
     *
230
     * @param string $fieldName Entity field name
231
     * @param string $fieldValue Value
232
     * @param string $relation Relation between field name and its value
233
     * @return self Chaining
234
     */
235
    public function where($fieldName, $fieldValue = null, $relation = '=')
236
    {
237
        // If empty array is passed
238
        if (is_string($fieldName)) {
239
            // Handle empty field value passing to avoid unexpected behaviour
240
            if (!isset($fieldValue)) {
241
                $relation = ArgumentInterface::ISNULL;
242
                $fieldValue = '';
243
            } elseif (is_array($fieldValue) && !sizeof($fieldValue)) {
244
                // TODO: We consider empty array passed as condition value as NULL, illegal condition
245
                $relation = ArgumentInterface::EQUAL;
246
                $fieldName = '1';
247
                $fieldValue = '0';
248
            }
249
250
            // Add condition argument
251
            $this->conditionGroup($fieldName)->add($fieldName, $fieldValue, $relation);
252
        } else {
253
            throw new \InvalidArgumentException('You can only pass string as first argument');
254
        }
255
256
        return $this;
257
    }
258
259
    /**
260
     * Join entity to query.
261
     *
262
     * @param string $entityName Entity identifier
263
     * @return self Chaining
264
     */
265
    public function join($entityName)
266
    {
267
        // TODO: We need to implement this logic
268
        $entityName .= '';
269
270
        // Chaining
271
        return $this;
272
    }
273
274
    /**
275
     * Add query result grouping.
276
     *
277
     * @param string $fieldName Entity field identifier for grouping
278
     * @return self Chaining
279
     */
280
    public function groupBy($fieldName)
281
    {
282
        $this->grouping[] = $fieldName;
283
284
        // Chaining
285
        return $this;
286
    }
287
288
    /**
289
     * Add query result quantity limitation.
290
     *
291
     * @param int $offset Resulting offset
292
     * @param null|int $quantity Amount of RecordInterface object to return
293
     * @return self Chaining
294
     */
295
    public function limit($offset, $quantity = null)
296
    {
297
        $this->limitation = array($offset, $quantity);
298
299
        // Chaining
300
        return $this;
301
    }
302
303
    /**
304
     * Add query result sorting.
305
     *
306
     * @param string $fieldName Entity field identifier for worting
307
     * @param string $order Sorting order
308
     * @return self Chaining
309
     */
310
    public function orderBy($fieldName, $order = 'ASC')
311
    {
312
        $this->sorting[] = array($fieldName, $order);
313
314
        // Chaining
315
        return $this;
316
    }
317
}
318