Completed
Push — master ( d32147...dfbd66 )
by Vitaly
08:49 queued 05:48
created

Query::id()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 9
rs 9.6667
cc 1
eloc 4
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
     * @see \samson\activerecord\Query::execute()
65
     * @param mixed $return External variable to store query results
66
     * @return mixed If no arguments passed returns query results collection, otherwise query success status
67
     */
68 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...
69
    {
70
        // Call handlers stack
71
        $this->_callHandlers();
72
73
        /** @var RecordInterface[] Perform DB request */
74
        $return = $this->database->find($this->class_name, $this);
0 ignored issues
show
Bug introduced by
The method find() does not seem to exist on object<samsonframework\orm\Database>.

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...
75
76
        // Clear this query
77
        $this->flush();
78
79
        // Return bool or collection
80
        return func_num_args() ? sizeof($return) : $return;
81
    }
82
83
    /**
84
     * Perform database request and get first record from results collection
85
     * @see \samson\activerecord\Query::execute()
86
     * @param mixed $return External variable to store query results
87
     * @return mixed If no arguments passed returns query results first database record object,
88
     * otherwise query success status
89
     */
90 View Code Duplication
    public function first(& $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...
91
    {
92
        // Call handlers stack
93
        $this->_callHandlers();
94
95
        /** @var RecordInterface[] Perform DB request */
96
        $return = array_shift($this->database->find($this->class_name, $this));
0 ignored issues
show
Bug introduced by
$this->database->find($this->class_name, $this) cannot be passed to array_shift() as the parameter $array expects a reference.
Loading history...
Bug introduced by
The method find() does not seem to exist on object<samsonframework\orm\Database>.

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...
97
98
        // Clear this query
99
        $this->flush();
100
101
        // Return bool or collection
102
        return func_num_args() ? sizeof($return) : $return;
103
    }
104
105
    /**
106
     * Perform database request and get array of record field values
107
     * @see \samson\activerecord\Query::execute()
108
     * @param string $fieldName Record field name to get value from
109
     * @param string $return External variable to store query results
110
     * @return Ambigous <boolean, NULL, mixed>
111
     */
112 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...
113
    {
114
        // Call handlers stack
115
        $this->_callHandlers();
116
117
        // Perform DB request
118
        $return = $this->database->fetchColumn($this->class_name, $this, $fieldName);
119
120
        // Return bool or collection
121
        return func_num_args() > 1 ? sizeof($return) : $return;
122
    }
123
124
    /**
125
     * Set query entity to work with.
126
     *
127
     * @param string $entity Entity identifier
128
     * @return Query|string Chaining or current entity identifier if nothing is passed
129
     * @throws EntityNotFound
130
     */
131
    public function entity($entity = null)
132
    {
133
        if (func_num_args() > 0) {
134 View Code Duplication
            if (class_exists($entity)) {
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...
135
                $this->flush();
136
                $this->class_name = $entity;
137
            } else {
138
                throw new EntityNotFound('['.$entity.'] not found');
139
            }
140
141
            return $this;
142
        }
143
144
        return $this->class_name;
145
    }
146
147
    /**
148
     * Get correct query condition depending on entity field name.
149
     * If base entity has field with this name - use base entity condition
150
     * group, otherwise default condition group.
151
     *
152
     * @param string $fieldName Entity field name
153
     * @return Condition Correct query condition group
154
     */
155
    protected function &getConditionGroup($fieldName)
156
    {
157
        if (property_exists($this->class_name, $fieldName)) {
158
            // Add this condition to base entity condition group
159
            return $this->own_condition;
160
        }
161
162
        return $this->cConditionGroup;
163
    }
164
165
    /**
166
     * Add query condition as prepared Condition instance.
167
     *
168
     * @param ConditionInterface $condition Condition to be added
169
     * @return self Chaining
170
     */
171
    public function whereCondition(ConditionInterface $condition)
172
    {
173
        // Iterate condition arguments
174
        foreach ($condition as $argument) {
175
            // If passed condition group has another condition group as argument
176
            if (is_a($argument, __NAMESPACE__ . '\Condition')) {
177
                // Go deeper in recursion
178
                $this->whereCondition($argument);
179
            } else { // Otherwise add condition argument to correct condition group
180
                $this->getConditionGroup($argument->field)->addArgument($argument);
181
            }
182
        }
183
184
        return $this;
185
    }
186
187
    /**
188
     * Add condition to current query.
189
     *
190
     * @param string $fieldName Entity field name
191
     * @param string $fieldValue Value
192
     * @param string $relation Relation between field name and its value
193
     * @return self Chaining
194
     */
195
    public function where($fieldName, $fieldValue = null, $relation = '=')
196
    {
197
        // If empty array is passed
198
        if (is_string($fieldName)) {
199
            // Handle empty field value passing to avoid unexpected behaviour
200
            if (!isset($fieldValue)) {
201
                $relation = ArgumentInterface::ISNULL;
202
                $fieldValue = '';
203
            }
204
205
            // Add condition argument
206
            $this->getConditionGroup($fieldName)->add($fieldName, $fieldValue, $relation);
207
        } else {
208
            throw new \InvalidArgumentException('You can only pass string as first argument');
209
        }
210
211
        return $this;
212
    }
213
214
    /**
215
     * Join entity to query.
216
     *
217
     * @param string $entityName Entity identifier
218
     * @return self Chaining
219
     */
220
    public function join($entityName)
221
    {
222
        // TODO: We need to implement this logic
223
        $entityName .= '';
224
225
        // Chaining
226
        return $this;
227
    }
228
229
    /**
230
     * Add query result grouping.
231
     *
232
     * @param string $fieldName Entity field identifier for grouping
233
     * @return self Chaining
234
     */
235
    public function groupBy($fieldName)
236
    {
237
        $this->grouping[] = $fieldName;
238
239
        // Chaining
240
        return $this;
241
    }
242
243
    /**
244
     * Add query result quantity limitation.
245
     *
246
     * @param int $offset Resulting offset
247
     * @param null|int $quantity Amount of RecordInterface object to return
248
     * @return self Chaining
249
     */
250
    public function limit($offset, $quantity = null)
251
    {
252
        $this->limitation = array($offset, $quantity);
253
254
        // Chaining
255
        return $this;
256
    }
257
258
    /**
259
     * Add query result sorting.
260
     *
261
     * @param string $fieldName Entity field identifier for worting
262
     * @param string $order Sorting order
263
     * @return self Chaining
264
     */
265
    public function orderBy($fieldName, $order = 'ASC')
266
    {
267
        $this->sorting[] = array($fieldName, $order);
268
269
        // Chaining
270
        return $this;
271
    }
272
}
273