Completed
Push — master ( c2185a...82d130 )
by Vitaly
02:29
created

Query::flush()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 11
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

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