1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
use Pixie\QueryBuilder\QueryBuilderHandler; |
4
|
|
|
|
5
|
|
|
/** |
6
|
|
|
* @since 0.10.3 |
7
|
|
|
*/ |
8
|
|
|
class QueryBuilderFlex extends QueryBuilderHandler |
9
|
|
|
{ |
10
|
|
|
/** @var Model|string The FQN of the model object this QueryBuilder instance is for */ |
11
|
|
|
private $modelType = null; |
12
|
|
|
|
13
|
|
|
/** @var int The amount of results per page with regards to result pagination */ |
14
|
|
|
private $resultsPerPage; |
15
|
|
|
|
16
|
|
|
// |
17
|
|
|
// Factories |
18
|
|
|
// |
19
|
|
|
|
20
|
|
|
/** |
21
|
|
|
* Create a QueryBuilder instance for a specific table. |
22
|
|
|
* |
23
|
|
|
* @param string $tableName |
24
|
|
|
* |
25
|
|
|
* @throws Exception If there is no database connection configured. |
26
|
|
|
* |
27
|
|
|
* @return QueryBuilderFlex |
28
|
|
|
*/ |
29
|
|
View Code Duplication |
public static function createForTable($tableName) |
|
|
|
|
30
|
|
|
{ |
31
|
|
|
Database::getInstance(); |
32
|
|
|
|
33
|
|
|
$connection = Service::getQueryBuilderConnection(); |
34
|
|
|
$qbBase = new QueryBuilderFlex($connection); |
35
|
|
|
|
36
|
|
|
$queryBuilder = $qbBase->table($tableName); |
37
|
|
|
|
38
|
|
|
return $queryBuilder; |
39
|
|
|
} |
40
|
|
|
|
41
|
|
|
/** |
42
|
|
|
* Creeate a QueryBuilder instance to work with a Model. |
43
|
|
|
* |
44
|
|
|
* @param string $modelType The FQN for the model that |
45
|
|
|
* |
46
|
|
|
* @throws Exception If there is no database connection configured. |
47
|
|
|
* |
48
|
|
|
* @return QueryBuilderFlex |
49
|
|
|
*/ |
50
|
|
View Code Duplication |
public static function createForModel($modelType) |
|
|
|
|
51
|
|
|
{ |
52
|
|
|
Database::getInstance(); |
53
|
|
|
|
54
|
|
|
$connection = Service::getQueryBuilderConnection(); |
55
|
|
|
$qbBase = new QueryBuilderFlex($connection); |
56
|
|
|
|
57
|
|
|
$queryBuilder = $qbBase->table(constant("$modelType::TABLE")); |
58
|
|
|
$queryBuilder->setModelType($modelType); |
59
|
|
|
|
60
|
|
|
return $queryBuilder; |
61
|
|
|
} |
62
|
|
|
|
63
|
|
|
// |
64
|
|
|
// Overridden QueryBuilder Functions |
65
|
|
|
// |
66
|
|
|
|
67
|
|
|
/** |
68
|
|
|
* {@inheritdoc} |
69
|
|
|
*/ |
70
|
|
|
public function limit($limit) |
71
|
|
|
{ |
72
|
|
|
$this->resultsPerPage = $limit; |
73
|
|
|
|
74
|
|
|
return parent::limit($limit); |
75
|
|
|
} |
76
|
|
|
|
77
|
|
|
// |
78
|
|
|
// QueryBuilderFlex unique functions |
79
|
|
|
// |
80
|
|
|
|
81
|
|
|
/** |
82
|
|
|
* Request that only non-deleted Models should be returned. |
83
|
|
|
* |
84
|
|
|
* @return static |
85
|
|
|
*/ |
86
|
|
|
public function active() |
87
|
|
|
{ |
88
|
|
|
$type = $this->modelType; |
89
|
|
|
$column = $type::DELETED_COLUMN; |
90
|
|
|
|
91
|
|
|
if ($column === null) { |
92
|
|
|
@trigger_error( |
|
|
|
|
93
|
|
|
'The use of the status column is deprecated. Update this model to use the DELETED_* constants.', |
94
|
|
|
E_USER_DEPRECATED |
95
|
|
|
); |
96
|
|
|
|
97
|
|
|
return $this->whereIn('status', $type::getActiveStatuses()); |
98
|
|
|
} |
99
|
|
|
|
100
|
|
|
return $this->whereNot($column, '=', $type::DELETED_VALUE); |
101
|
|
|
} |
102
|
|
|
|
103
|
|
|
/** |
104
|
|
|
* Get the amount of pages this query would have. |
105
|
|
|
* |
106
|
|
|
* @return int |
107
|
|
|
*/ |
108
|
|
|
public function countPages() |
109
|
|
|
{ |
110
|
|
|
return (int)ceil($this->count() / $this->resultsPerPage); |
111
|
|
|
} |
112
|
|
|
|
113
|
|
|
/** |
114
|
|
|
* Request that a specific model is not returned. |
115
|
|
|
* |
116
|
|
|
* @param Model|int $model The ID or model you don't want to get |
117
|
|
|
* |
118
|
|
|
* @return static |
119
|
|
|
*/ |
120
|
|
|
public function except($model) |
121
|
|
|
{ |
122
|
|
|
if ($model instanceof Model) { |
123
|
|
|
$model = $model->getId(); |
124
|
|
|
} |
125
|
|
|
|
126
|
|
|
$this->whereNot('id', '=', $model); |
127
|
|
|
|
128
|
|
|
return $this; |
129
|
|
|
} |
130
|
|
|
|
131
|
|
|
/** |
132
|
|
|
* Only show results from a specific page. |
133
|
|
|
* |
134
|
|
|
* This method will automatically take care of the calculations for a correct OFFSET. |
135
|
|
|
* |
136
|
|
|
* @param int|null $page The page number (or null to show all pages - counting starts from 0) |
137
|
|
|
* |
138
|
|
|
* @return static |
139
|
|
|
*/ |
140
|
|
|
public function fromPage($page) |
141
|
|
|
{ |
142
|
|
|
if ($page === null) { |
143
|
|
|
$this->offset($page); |
144
|
|
|
|
145
|
|
|
return $this; |
146
|
|
|
} |
147
|
|
|
|
148
|
|
|
$page = intval($page); |
149
|
|
|
$page = ($page <= 0) ? 1 : $page; |
150
|
|
|
|
151
|
|
|
$this->offset((min($page, $this->countPages()) - 1) * $this->resultsPerPage); |
152
|
|
|
|
153
|
|
|
return $this; |
154
|
|
|
} |
155
|
|
|
|
156
|
|
|
/** |
157
|
|
|
* Perform the query and get the results as Models. |
158
|
|
|
* |
159
|
|
|
* @param bool $fastFetch Whether to perform one query to load all the model data instead of fetching them one by |
160
|
|
|
* one (ignores cache) |
161
|
|
|
* |
162
|
|
|
* @return array |
163
|
|
|
*/ |
164
|
|
|
public function getModels($fastFetch = false) |
165
|
|
|
{ |
166
|
|
|
/** @var Model $type */ |
167
|
|
|
$type = $this->modelType; |
168
|
|
|
$columns = ($fastFetch) ? $type::getEagerColumns() : ['*']; |
169
|
|
|
|
170
|
|
|
$this->select($columns); |
171
|
|
|
$this->setFetchMode(PDO::FETCH_ASSOC); |
172
|
|
|
|
173
|
|
|
/** @var array $results */ |
174
|
|
|
$results = $this->get(); |
175
|
|
|
|
176
|
|
|
if ($fastFetch) { |
177
|
|
|
return $type::createFromDatabaseResults($results); |
178
|
|
|
} |
179
|
|
|
|
180
|
|
|
return $type::arrayIdToModel(array_column($results, 'id')); |
181
|
|
|
} |
182
|
|
|
|
183
|
|
|
/** |
184
|
|
|
* Set the model this QueryBuilder will be working this. |
185
|
|
|
* |
186
|
|
|
* This information is used for automatically retrieving table names, eager columns, and lazy columns for these |
187
|
|
|
* models. |
188
|
|
|
* |
189
|
|
|
* @param string $modelType The FQN of the model this QueryBuilder will be working with |
190
|
|
|
* |
191
|
|
|
* @return $this |
192
|
|
|
*/ |
193
|
|
|
public function setModelType($modelType) |
194
|
|
|
{ |
195
|
|
|
$this->modelType = $modelType; |
196
|
|
|
|
197
|
|
|
return $this; |
198
|
|
|
} |
199
|
|
|
|
200
|
|
|
/** |
201
|
|
|
* Make sure that Models invisible to a player are not returned. |
202
|
|
|
* |
203
|
|
|
* Note that this method does not take PermissionModel::canBeSeenBy() into |
204
|
|
|
* consideration for performance purposes, so you will have to override this |
205
|
|
|
* in your query builder if necessary. |
206
|
|
|
* |
207
|
|
|
* @param Player $player The player in question |
208
|
|
|
* @param bool $showDeleted Use false to hide deleted models even from admins |
209
|
|
|
* |
210
|
|
|
* @return static |
211
|
|
|
*/ |
212
|
|
|
public function visibleTo(Player $player, $showDeleted = false) |
213
|
|
|
{ |
214
|
|
|
$type = $this->modelType; |
215
|
|
|
|
216
|
|
|
if (is_subclass_of($this->modelType, PermissionModel::class) && |
|
|
|
|
217
|
|
|
$player->hasPermission(constant("$type::EDIT_PERMISSION")) |
218
|
|
|
) { |
219
|
|
|
// The player is an admin who can see the hidden models |
220
|
|
|
if (!$showDeleted) { |
221
|
|
|
$col = constant("$type::DELETED_COLUMN"); |
222
|
|
|
|
223
|
|
|
if ($col !== null) { |
224
|
|
|
$this->whereNot($col, '=', constant("$type::DELETED_VALUE")); |
225
|
|
|
} |
226
|
|
|
} |
227
|
|
|
} else { |
228
|
|
|
return $this->active(); |
229
|
|
|
} |
230
|
|
|
|
231
|
|
|
return $this; |
232
|
|
|
} |
233
|
|
|
} |
234
|
|
|
|
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.