Completed
Push — master ( 659f92...757aaf )
by Vitaly
02:43
created

Query::execute()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 18
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

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