1
|
|
|
<?php |
2
|
|
|
namespace samsonframework\orm; |
3
|
|
|
|
4
|
|
|
/** |
5
|
|
|
* Universal class for creating database queries |
6
|
|
|
* @author Vitaly Iegorov <[email protected]> |
7
|
|
|
* @version 2.0 |
8
|
|
|
*/ |
9
|
|
|
class Query extends QueryHandler |
10
|
|
|
{ |
11
|
|
|
/** Class name for interacting with database */ |
12
|
|
|
protected $class_name; |
13
|
|
|
|
14
|
|
|
/** |
15
|
|
|
* Collection of query parameters objects |
16
|
|
|
* @see \samson\activerecord\QueryParams |
17
|
|
|
*/ |
18
|
|
|
protected $parameters = array(); |
19
|
|
|
|
20
|
|
|
/** |
21
|
|
|
* Reset all query parameters |
22
|
|
|
* @return self Chaining |
23
|
|
|
*/ |
24
|
|
|
public function flush() |
25
|
|
|
{ |
26
|
|
|
foreach ($this->parameters as $param) { |
27
|
|
|
$param->flush(); |
28
|
|
|
} |
29
|
|
|
|
30
|
|
|
return $this; |
31
|
|
|
} |
32
|
|
|
|
33
|
|
|
/** |
34
|
|
|
* Perform database request and get collection of database record objects |
35
|
|
|
* @see \samson\activerecord\Query::execute() |
36
|
|
|
* @param mixed $return External variable to store query results |
37
|
|
|
* @return mixed If no arguments passed returns query results collection, otherwise query success status |
38
|
|
|
*/ |
39
|
|
|
public function exec(& $return = null) |
40
|
|
|
{ |
41
|
|
|
$args = func_num_args(); |
42
|
|
|
return $this->execute($return, $args); |
43
|
|
|
} |
44
|
|
|
|
45
|
|
|
/** |
46
|
|
|
* Perform database request and get first record from results collection |
47
|
|
|
* @see \samson\activerecord\Query::execute() |
48
|
|
|
* @param mixed $return External variable to store query results |
49
|
|
|
* @return mixed If no arguments passed returns query results first database record object, |
50
|
|
|
* otherwise query success status |
51
|
|
|
*/ |
52
|
|
|
public function first(& $return = null) |
53
|
|
|
{ |
54
|
|
|
$args = func_num_args(); |
55
|
|
|
return $this->execute($return, $args, 1); |
56
|
|
|
} |
57
|
|
|
|
58
|
|
|
/** |
59
|
|
|
* Perform database request and get array of record field values |
60
|
|
|
* @see \samson\activerecord\Query::execute() |
61
|
|
|
* @param string $fieldName Record field name to get value from |
62
|
|
|
* @param string $return External variable to store query results |
63
|
|
|
* @return Ambigous <boolean, NULL, mixed> |
64
|
|
|
*/ |
65
|
|
|
public function fields($fieldName, & $return = null) |
66
|
|
|
{ |
67
|
|
|
// Call handlers stack |
68
|
|
|
$this->_callHandlers(); |
69
|
|
|
|
70
|
|
|
// Perform DB request |
71
|
|
|
$return = db()->fetchColumn($this->class_name, $this, $fieldName); |
72
|
|
|
|
73
|
|
|
$success = is_array($return) && sizeof($return); |
74
|
|
|
|
75
|
|
|
// If parent function has arguments - consider them as return value and return request status |
76
|
|
|
if (func_num_args() - 1 > 0) { |
77
|
|
|
return $success; |
|
|
|
|
78
|
|
|
} else { // Parent function has no arguments, return request result |
79
|
|
|
return $return; |
80
|
|
|
} |
81
|
|
|
} |
82
|
|
|
|
83
|
|
|
/** |
84
|
|
|
* Perform database request and return different results depending on function arguments. |
85
|
|
|
* @see \samson\activerecord\Record |
86
|
|
|
* @param array $result External variable to store dabatase request results collection |
87
|
|
|
* @param integer|bool $rType Amount of arguments passed to parent function |
88
|
|
|
* @param integer $limit Quantity of records to return |
89
|
|
|
* @param callable $handler External callable handler for results modification |
90
|
|
|
* @param array $handlerArgs External callable handler arguments |
91
|
|
|
* @return boolean/array Boolean if $r_type > 0, otherwise array of request results |
|
|
|
|
92
|
|
|
*/ |
93
|
|
|
protected function & execute( |
94
|
|
|
& $result = null, |
95
|
|
|
$rType = false, |
96
|
|
|
$limit = null, |
97
|
|
|
$handler = null, |
98
|
|
|
$handlerArgs = array() |
99
|
|
|
) { |
100
|
|
|
// Call handlers stack |
101
|
|
|
$this->_callHandlers(); |
102
|
|
|
|
103
|
|
|
// Perform DB request |
104
|
|
|
$result = db()->find($this->class_name, $this); |
105
|
|
|
|
106
|
|
|
// If external result handler is passed - use it |
107
|
|
|
if (isset($handler)) { |
108
|
|
|
// Add results collection to array |
109
|
|
|
array_unshift($handlerArgs, $result); |
110
|
|
|
|
111
|
|
|
// Call external handler with parameters |
112
|
|
|
$result = call_user_func_array($handler, $handlerArgs); |
113
|
|
|
} |
114
|
|
|
|
115
|
|
|
// Clear this query |
116
|
|
|
$this->flush(); |
117
|
|
|
|
118
|
|
|
// Count records |
119
|
|
|
$count = sizeof($result); |
120
|
|
|
|
121
|
|
|
// Define is request was successful |
122
|
|
|
$success = is_array($result) && $count; |
123
|
|
|
|
124
|
|
|
// Is amount of records is specified |
125
|
|
|
if (isset($limit)) { |
126
|
|
|
// If we have not enough records - return null |
127
|
|
|
if ($count < $limit) { |
128
|
|
|
$result = null; |
129
|
|
|
} elseif ($limit === 1) { // If we need first record |
130
|
|
|
$result = array_shift($result); |
131
|
|
|
} elseif ($limit > 1) { // Slice array for necessary amount |
132
|
|
|
$result = array_slice($result, 0, $limit); |
133
|
|
|
} |
134
|
|
|
} |
135
|
|
|
|
136
|
|
|
// If parent function has arguments - consider them as return value and return request status |
137
|
|
|
if ($rType > 0) { |
138
|
|
|
return $success; |
139
|
|
|
} else { // Parent function has no arguments, return request result |
140
|
|
|
return $result; |
141
|
|
|
} |
142
|
|
|
} |
143
|
|
|
} |
144
|
|
|
|
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:
Our function
my_function
expects aPost
object, and outputs the author of the post. The base classPost
returns a simple string and outputting a simple string will work just fine. However, the child classBlogPost
which is a sub-type ofPost
instead decided to return anobject
, and is therefore violating the SOLID principles. If aBlogPost
were passed tomy_function
, PHP would not complain, but ultimately fail when executing thestrtoupper
call in its body.