Completed
Push — master ( 72415f...642f12 )
by Vitaly
07:27
created

Query::join()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 2
Metric Value
c 2
b 0
f 2
dl 0
loc 7
rs 9.4286
cc 1
eloc 2
nc 1
nop 1
1
<?php
2
namespace samsonframework\orm;
3
4
/**
5
 * Database query builder and executer.
6
 * @author Vitaly Iegorov <[email protected]>
7
 * @version 2.0
8
 */
9
class Query extends QueryHandler implements QueryInterface
10
{
11
    /** @var string Class name for interacting with database */
12
    protected $class_name;
13
14
    /** @var self[] Collection of query parameters objects */
15
    protected $parameters = array();
16
17
    /** @var array Collection of entity field names for sorting order */
18
    protected $sorting = array();
19
20
    /** @var array Collection of entity field names for grouping query results */
21
    protected $grouping = array();
22
23
    /** @var array Collection of query results limitations */
24
    protected $limitation = array();
25
26
    /**
27
     * Reset all query parameters
28
     * @return self Chaining
29
     */
30
    public function flush()
31
    {
32
        // TODO: Do we need it?
33
        foreach ($this->parameters as $param) {
34
            $param->flush();
35
        }
36
37
        return $this;
38
    }
39
40
    /**
41
     * Perform database request and get collection of database record objects
42
     * @see \samson\activerecord\Query::execute()
43
     * @param mixed $return External variable to store query results
44
     * @return mixed If no arguments passed returns query results collection, otherwise query success status
45
     */
46
    public function exec(& $return = null)
47
    {
48
        $args = func_num_args();
49
        return $this->execute($return, $args);
50
    }
51
52
    /**
53
     * Perform database request and get first record from results collection
54
     * @see \samson\activerecord\Query::execute()
55
     * @param mixed $return External variable to store query results
56
     * @return mixed If no arguments passed returns query results first database record object,
57
     * otherwise query success status
58
     */
59
    public function first(& $return = null)
60
    {
61
        $args = func_num_args();
62
        return $this->execute($return, $args, 1);
63
    }
64
65
    /**
66
     * Perform database request and get array of record field values
67
     * @see \samson\activerecord\Query::execute()
68
     * @param string $fieldName Record field name to get value from
69
     * @param string $return External variable to store query results
70
     * @return Ambigous <boolean, NULL, mixed>
71
     */
72
    public function fields($fieldName, & $return = null)
73
    {
74
        // Call handlers stack
75
        $this->_callHandlers();
76
77
        // Perform DB request
78
        $return = db()->fetchColumn($this->class_name, $this, $fieldName);
79
80
        $success = is_array($return) && sizeof($return);
81
82
        // If parent function has arguments - consider them as return value and return request status
83
        if (func_num_args() - 1 > 0) {
84
            return $success;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $success; (boolean) is incompatible with the return type documented by samsonframework\orm\Query::fields of type samsonframework\orm\Ambigous.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
85
        } else { // Parent function has no arguments, return request result
86
            return $return;
87
        }
88
    }
89
90
91
    /**
92
     * Perform database request and return different results depending on function arguments.
93
     * @see \samson\activerecord\Record
94
     * @param array $result External variable to store dabatase request results collection
95
     * @param integer|bool $rType Amount of arguments passed to parent function
96
     * @param integer $limit Quantity of records to return
97
     * @param callable $handler External callable handler for results modification
98
     * @param array $handlerArgs External callable handler arguments
99
     * @return boolean/array Boolean if $r_type > 0, otherwise array of request results
0 ignored issues
show
Documentation introduced by
The doc-type boolean/array could not be parsed: Unknown type name "boolean/array" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
100
     */
101
    protected function &execute(
102
        & $result = null,
103
        $rType = false,
104
        $limit = null,
105
        $handler = null,
106
        $handlerArgs = array()
107
    )
0 ignored issues
show
Coding Style introduced by
There must be a single space between the closing parenthesis and the opening brace of a multi-line function declaration; found newline
Loading history...
108
    {
109
        // Call handlers stack
110
        $this->_callHandlers();
111
112
        // Perform DB request
113
        $result = db()->find($this->class_name, $this);
114
115
        // If external result handler is passed - use it
116
        if (isset($handler)) {
117
            // Add results collection to array
118
            array_unshift($handlerArgs, $result);
119
120
            // Call external handler with parameters
121
            $result = call_user_func_array($handler, $handlerArgs);
122
        }
123
124
        // Clear this query
125
        $this->flush();
126
127
        // Count records
128
        $count = sizeof($result);
129
130
        // Define is request was successful
131
        $success = is_array($result) && $count;
132
133
        // Is amount of records is specified
134
        if (isset($limit)) {
135
            // If we have not enought records - return null
136
            if ($count < $limit) {
137
                $result = null;
138
            } elseif ($limit === 1) { // If we need first record
139
                $result = array_shift($result);
140
            } elseif ($limit > 1) { // Slice array for nessesar amount
141
                $result = array_slice($result, 0, $limit);
142
            }
143
        }
144
145
        // If parent function has arguments - consider them as return value and return request status
146
        if ($rType > 0) {
147
            return $success;
148
        } else { // Parent function has no arguments, return request result
149
            return $result;
150
        }
151
    }
152
153
    /**
154
     * Set query entity to work with.
155
     *
156
     * @param string $entity Entity identifier
157
     * @return self|string Chaining or current entity identifier if nothing is passed
158
     */
159
    public function entity($entity = null)
160
    {
161
        $this->class_name = isset($entity) ? $entity : $this->class_name;
162
163
        return func_num_args() > 0 ? $this->class_name : $this;
164
    }
165
166
    /**
167
     * Add condition to current query.
168
     *
169
     * @param string $fieldName Entity field name
170
     * @param string $fieldValue Value
171
     * @param string $relation Relation between field name and its value
172
     * @return self Chaining
173
     */
174
    public function cond($fieldName, $fieldValue, $relation = '=')
175
    {
176
        // If empty array is passed
177
        if (is_array($fieldValue) && !sizeof($fieldValue)) {
178
            $this->empty = true;
0 ignored issues
show
Bug introduced by
The property empty does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
179
            return $this;
180
        }
181
182
        $fieldName = new Argument($fieldName, $fieldValue, $relation);
183
184
        // If this field condition relates to base query entity
185
        $destination = &$this->cConditionGroup;
0 ignored issues
show
Bug introduced by
The property cConditionGroup does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
186
        if (property_exists($this->class_name, $fieldName)) {
187
            // Add this condition to base entity condition group
188
            $destination = &$this->own_condition;
0 ignored issues
show
Bug introduced by
The property own_condition does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
189
        }
190
191
        // Добавим аргумент условия в выбранную группу условий
192
        $destination->arguments[] = $fieldName;
193
194
        // Вернем себя для цепирования
195
        return $this;
196
    }
197
198
    /**
199
     * Join entity to query.
200
     *
201
     * @param string $entityName Entity identifier
202
     * @return self Chaining
203
     */
204
    public function join($entityName)
205
    {
206
        // TODO: We need to implement this logic
207
208
        // Chaining
209
        return $this;
210
    }
211
212
    /**
213
     * Add query result grouping.
214
     *
215
     * @param string $fieldName Entity field identifier for grouping
216
     * @return self Chaining
217
     */
218
    public function groupBy($fieldName)
219
    {
220
        $this->grouping[] = $fieldName;
221
222
        // Chaining
223
        return $this;
224
    }
225
226
    /**
227
     * Add query result quantity limitation.
228
     *
229
     * @param int $offset Resulting offset
230
     * @param null|int $quantity Amount of RecordInterface object to return
231
     * @return self Chaining
232
     */
233
    public function limit($offset, $quantity = null)
234
    {
235
        $this->limitation = array($offset, $quantity);
236
237
        // Chaining
238
        return $this;
239
    }
240
241
    /**
242
     * Add query result sorting.
243
     *
244
     * @param string $fieldName Entity field identifier for worting
245
     * @param string $order Sorting order
246
     * @return self Chaining
247
     */
248
    public function orderBy($fieldName, $order = 'ASC')
249
    {
250
        $this->sorting[] = array($fieldName, $order);
251
252
        // Chaining
253
        return $this;
254
    }
255
}
256