Completed
Push — master ( 5a4e61...659f92 )
by Vitaly
06:31 queued 03:24
created

Query::whereCondition()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 15
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

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