1
|
|
|
<?php defined('SYSPATH') OR die('No direct script access.'); |
2
|
|
|
|
3
|
|
|
/** |
4
|
|
|
* Core class that all associations must extend |
5
|
|
|
* |
6
|
|
|
* @package Jam |
7
|
|
|
* @category Associations |
8
|
|
|
* @author Ivan Kerin |
9
|
|
|
* @copyright (c) 2011-2012 Despark Ltd. |
10
|
|
|
* @license http://www.opensource.org/licenses/isc-license.txt |
11
|
|
|
*/ |
12
|
|
|
abstract class Kohana_Jam_Query_Builder { |
13
|
|
|
|
14
|
|
|
/** |
15
|
|
|
* Convert a column to a `table`.`column` using the appropriate model info |
16
|
|
|
* @param string $column |
17
|
|
|
* @param string $model |
18
|
|
|
* @param mixed $value |
19
|
|
|
* @return string |
20
|
|
|
*/ |
21
|
135 |
|
public static function resolve_attribute_name($column, $model = NULL, $value = NULL) |
22
|
|
|
{ |
23
|
135 |
|
if (is_array($column)) |
24
|
135 |
|
{ |
25
|
9 |
|
list($column, $alias) = $column; |
26
|
9 |
|
} |
27
|
|
|
|
28
|
135 |
|
if ( ! ($column instanceof Database_Expression) AND $column !== '*') |
29
|
135 |
|
{ |
30
|
133 |
|
if (strpos($column, '.') !== FALSE) |
31
|
133 |
|
{ |
32
|
78 |
|
list($model, $column) = explode('.', $column); |
33
|
78 |
|
} |
34
|
|
|
|
35
|
133 |
|
if ($meta = Jam::meta(Jam_Query_Builder::aliased_model($model))) |
36
|
133 |
|
{ |
37
|
129 |
|
$column = Jam_Query_Builder::resolve_meta_attribute($column, $meta, $value); |
38
|
129 |
|
} |
39
|
|
|
|
40
|
|
|
if ($model) |
41
|
133 |
|
{ |
42
|
132 |
|
if (is_array($model)) |
43
|
132 |
|
{ |
44
|
9 |
|
$model = $model[1]; |
45
|
9 |
|
} |
46
|
130 |
|
elseif ($meta) |
47
|
|
|
{ |
48
|
127 |
|
$model = $meta->table(); |
49
|
127 |
|
} |
50
|
|
|
|
51
|
132 |
|
$column = $model.'.'.$column; |
52
|
132 |
|
} |
53
|
133 |
|
} |
54
|
|
|
|
55
|
135 |
|
if ( ! empty($alias)) |
56
|
135 |
|
{ |
57
|
9 |
|
return array($column, $alias); |
|
|
|
|
58
|
|
|
} |
59
|
|
|
else |
60
|
|
|
{ |
61
|
132 |
|
return $column; |
62
|
|
|
} |
63
|
|
|
} |
64
|
|
|
|
65
|
|
|
/** |
66
|
|
|
* Set a primary key condition. If its an array make in an IN condition. |
67
|
|
|
* @param Database_Query $query |
68
|
|
|
* @param string $key |
69
|
|
|
* @return Database_Query |
70
|
|
|
*/ |
71
|
24 |
|
public static function find_by_primary_key(Database_Query $query, $key) |
72
|
|
|
{ |
73
|
24 |
|
if (is_array($key)) |
74
|
24 |
|
{ |
75
|
3 |
|
if ( ! $key) |
|
|
|
|
76
|
3 |
|
throw new Kohana_Exception('Arrays of primary keys is empty'); |
77
|
|
|
|
78
|
3 |
|
$query->where(':primary_key', 'IN', $key); |
|
|
|
|
79
|
3 |
|
} |
80
|
|
|
else |
81
|
|
|
{ |
82
|
23 |
|
if ( ! $key) |
83
|
23 |
|
throw new Kohana_Exception('Primary key must not be empty'); |
84
|
|
|
|
85
|
23 |
|
$query->where(':unique_key', '=', $key); |
|
|
|
|
86
|
|
|
} |
87
|
24 |
|
return $query; |
88
|
|
|
} |
89
|
|
|
|
90
|
|
|
/** |
91
|
|
|
* Set the table name, even if its in an alias array (table, alias) |
92
|
|
|
* @param string|array $model |
93
|
|
|
* @param string $table |
94
|
|
|
* @return string|array |
95
|
|
|
*/ |
96
|
101 |
|
public static function set_table_name($model, $table) |
97
|
|
|
{ |
98
|
101 |
|
if (is_array($model)) |
99
|
101 |
|
{ |
100
|
9 |
|
$model[0] = $table; |
101
|
9 |
|
} |
102
|
|
|
else |
103
|
|
|
{ |
104
|
92 |
|
$model = $table; |
105
|
|
|
} |
106
|
101 |
|
return $model; |
107
|
|
|
} |
108
|
|
|
|
109
|
|
|
/** |
110
|
|
|
* Convert model name to its corresponding table, even if its in an array (model, alias) |
111
|
|
|
* @param string|array $model |
112
|
|
|
* @return string|array |
113
|
|
|
*/ |
114
|
103 |
|
public static function resolve_table_alias($model) |
115
|
|
|
{ |
116
|
103 |
|
if ($meta = Jam::meta(Jam_Query_Builder::aliased_model($model))) |
117
|
103 |
|
{ |
118
|
101 |
|
$model = Jam_Query_Builder::set_table_name($model, $meta->table()); |
|
|
|
|
119
|
101 |
|
} |
120
|
103 |
|
return $model; |
121
|
|
|
} |
122
|
|
|
|
123
|
|
|
/** |
124
|
|
|
* Generate Jam_Query_Builder_Join based on the given arguments |
125
|
|
|
* @param string $table |
126
|
|
|
* @param string $type LEFT, NATURAL... |
127
|
|
|
* @param string $context_model the model of the parent |
128
|
|
|
* @param boolean $resolve_table_model wether to resolve the name of the model to a tablename |
129
|
|
|
* @return Jam_Query_Builder_Join |
130
|
|
|
*/ |
131
|
35 |
|
public static function resolve_join($table, $type = NULL, $context_model = NULL, $resolve_table_model = TRUE) |
132
|
|
|
{ |
133
|
35 |
|
$context_model_name = Jam_Query_Builder::aliased_model($context_model); |
134
|
|
|
|
135
|
35 |
|
if ($resolve_table_model AND is_string($context_model_name) AND $meta = Jam::meta($context_model_name)) |
136
|
35 |
|
{ |
137
|
16 |
|
$table_name = Jam_Query_Builder::aliased_model($table); |
138
|
16 |
|
if (is_string($table_name) AND $association = $meta->association($table_name)) |
139
|
16 |
|
{ |
140
|
15 |
|
return $association->join(is_array($table) ? $table[1] : NULL, $type); |
|
|
|
|
141
|
|
|
} |
142
|
1 |
|
} |
143
|
|
|
|
144
|
22 |
|
$join = Jam_Query_Builder_Join::factory($table, $type); |
145
|
|
|
if ($context_model) |
|
|
|
|
146
|
22 |
|
{ |
147
|
22 |
|
$join->context_model($context_model); |
148
|
22 |
|
} |
149
|
22 |
|
return $join; |
150
|
|
|
} |
151
|
|
|
|
152
|
|
|
/** |
153
|
|
|
* Return the model if its alias array (model, alias) |
154
|
|
|
* @param string|array $model |
155
|
|
|
* @return string |
156
|
|
|
*/ |
157
|
139 |
|
public static function aliased_model($model) |
158
|
|
|
{ |
159
|
139 |
|
return is_array($model) ? $model[0] : $model; |
160
|
|
|
} |
161
|
|
|
|
162
|
|
|
/** |
163
|
|
|
* Convert :primary_key, :name_kay and :unique_key to their corresponding column names |
164
|
|
|
* @param string $attribute |
165
|
|
|
* @param Jam_Meta $meta |
166
|
|
|
* @param mixed $value |
167
|
|
|
* @return string |
168
|
|
|
*/ |
169
|
146 |
|
public static function resolve_meta_attribute($attribute, Jam_Meta $meta, $value = NULL) |
170
|
|
|
{ |
171
|
|
|
switch ($attribute) |
172
|
|
|
{ |
173
|
146 |
|
case ':primary_key': |
174
|
76 |
|
$attribute = $meta->primary_key(); |
175
|
76 |
|
break; |
176
|
|
|
|
177
|
112 |
|
case ':name_key': |
178
|
10 |
|
$attribute = $meta->name_key(); |
179
|
10 |
|
break; |
180
|
|
|
|
181
|
103 |
|
case ':unique_key': |
182
|
22 |
|
$attribute = $meta->unique_key($value); |
183
|
22 |
|
break; |
184
|
|
|
} |
185
|
|
|
|
186
|
146 |
|
return $attribute; |
187
|
|
|
} |
188
|
|
|
} |
189
|
|
|
|
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.