Révision 5d12d676
Ajouté par Assos Assos il y a environ 6 ans
drupal7/sites/all/modules/views/handlers/views_handler_relationship_groupwise_max.inc | ||
---|---|---|
2 | 2 |
|
3 | 3 |
/** |
4 | 4 |
* @file |
5 |
* Relationship for groupwise maximum handler.
|
|
5 |
* Definition of views_handler_relationship_groupwise_max.
|
|
6 | 6 |
*/ |
7 | 7 |
|
8 | 8 |
/** |
9 | 9 |
* Relationship handler that allows a groupwise maximum of the linked in table. |
10 |
* |
|
10 | 11 |
* For a definition, see: |
11 | 12 |
* http://dev.mysql.com/doc/refman/5.0/en/example-maximum-column-group-row.html |
12 | 13 |
* In lay terms, instead of joining to get all matching records in the linked |
... | ... | |
58 | 59 |
/** |
59 | 60 |
* Defines default values for options. |
60 | 61 |
*/ |
61 |
function option_definition() { |
|
62 |
public function option_definition() {
|
|
62 | 63 |
$options = parent::option_definition(); |
63 | 64 |
|
64 | 65 |
$options['subquery_sort'] = array('default' => NULL); |
... | ... | |
72 | 73 |
} |
73 | 74 |
|
74 | 75 |
/** |
75 |
* Extends the relationship's basic options, allowing the user to pick |
|
76 |
* a sort and an order for it. |
|
76 |
* Extends the relationship's basic options. |
|
77 |
* |
|
78 |
* Allows the user to pick a sort and an order for it. |
|
77 | 79 |
*/ |
78 |
function options_form(&$form, &$form_state) { |
|
80 |
public function options_form(&$form, &$form_state) {
|
|
79 | 81 |
parent::options_form($form, $form_state); |
80 | 82 |
|
81 | 83 |
// Get the sorts that apply to our base. |
... | ... | |
92 | 94 |
'#default_value' => !empty($this->options['subquery_sort']) ? $this->options['subquery_sort'] : $this->definition['base'] . '.' . $base_table_data['table']['base']['field'], |
93 | 95 |
'#options' => $sort_options, |
94 | 96 |
'#description' => theme('advanced_help_topic', array('module' => 'views', 'topic' => 'relationship-representative')) . |
95 |
t("The sort criteria is applied to the data brought in by the relationship to determine how a representative item is obtained for each row. For example, to show the most recent node for each user, pick 'Content: Updated date'."),
|
|
97 |
t("The sort criteria is applied to the data brought in by the relationship to determine how a representative item is obtained for each row. For example, to show the most recent node for each user, pick 'Content: Updated date'."), |
|
96 | 98 |
); |
97 | 99 |
|
98 | 100 |
$form['subquery_order'] = array( |
... | ... | |
110 | 112 |
'#default_value' => $this->options['subquery_namespace'], |
111 | 113 |
); |
112 | 114 |
|
113 |
|
|
114 |
// WIP: This stuff doens't work yet: namespacing issues. |
|
115 |
// WIP: This stuff doesn't work yet: namespacing issues. |
|
115 | 116 |
// A list of suitable views to pick one as the subview. |
116 | 117 |
$views = array('' => '<none>'); |
117 | 118 |
$all_views = views_get_all_views(); |
... | ... | |
120 | 121 |
// - base must the base that our relationship joins towards |
121 | 122 |
// - must have fields. |
122 | 123 |
if ($view->base_table == $this->definition['base'] && !empty($view->display['default']->display_options['fields'])) { |
123 |
// TODO: check the field is the correct sort?
|
|
124 |
// @todo check the field is the correct sort?
|
|
124 | 125 |
// or let users hang themselves at this stage and check later? |
125 | 126 |
if ($view->type == 'Default') { |
126 | 127 |
$views[t('Default Views')][$view->name] = $view->name; |
... | ... | |
152 | 153 |
* |
153 | 154 |
* We use this to obtain our subquery SQL. |
154 | 155 |
*/ |
155 |
function get_temporary_view() { |
|
156 |
public function get_temporary_view() {
|
|
156 | 157 |
views_include('view'); |
157 | 158 |
$view = new view(); |
158 |
$view->vid = 'new'; // @todo: what's this? |
|
159 |
// @todo What's this? |
|
160 |
$view->vid = 'new'; |
|
159 | 161 |
$view->base_table = $this->definition['base']; |
160 | 162 |
$view->add_display('default'); |
161 | 163 |
return $view; |
... | ... | |
164 | 166 |
/** |
165 | 167 |
* When the form is submitted, take sure to clear the subquery string cache. |
166 | 168 |
*/ |
167 |
function options_form_submit(&$form, &$form_state) { |
|
169 |
public function options_form_submit(&$form, &$form_state) {
|
|
168 | 170 |
$cid = 'views_relationship_groupwise_max:' . $this->view->name . ':' . $this->view->current_display . ':' . $this->options['id']; |
169 | 171 |
cache_clear_all($cid, 'cache_views_data'); |
170 | 172 |
} |
... | ... | |
175 | 177 |
* generate the subquery when the options are saved, rather than when the view |
176 | 178 |
* is run. This saves considerable time. |
177 | 179 |
* |
178 |
* @param $options |
|
179 |
* An array of options: |
|
180 |
* - subquery_sort: the id of a views sort. |
|
181 |
* - subquery_order: either ASC or DESC. |
|
182 |
* @return |
|
180 |
* @param array $options |
|
181 |
* An array of options that contains the following items: |
|
182 |
* - subquery_sort: the id of a views sort. |
|
183 |
* - subquery_order: either ASC or DESC. |
|
184 |
* |
|
185 |
* @return string |
|
183 | 186 |
* The subquery SQL string, ready for use in the main query. |
184 | 187 |
*/ |
185 |
function left_query($options) { |
|
188 |
public function left_query($options) {
|
|
186 | 189 |
// Either load another view, or create one on the fly. |
187 | 190 |
if ($options['subquery_view']) { |
188 | 191 |
$temp_view = views_get_view($options['subquery_view']); |
189 |
// Remove all fields from default display |
|
192 |
// Remove all fields from default display.
|
|
190 | 193 |
unset($temp_view->display['default']->display_options['fields']); |
191 | 194 |
} |
192 | 195 |
else { |
... | ... | |
195 | 198 |
$temp_view = $this->get_temporary_view(); |
196 | 199 |
|
197 | 200 |
// Add the sort from the options to the default display. |
198 |
// This is broken, in that the sort order field also gets added as a |
|
199 |
// select field. See http://drupal.org/node/844910. |
|
200 |
// We work around this further down. |
|
201 |
$sort = $options['subquery_sort']; |
|
202 |
list($sort_table, $sort_field) = explode('.', $sort); |
|
201 |
list($sort_table, $sort_field) = explode('.', $options['subquery_sort']); |
|
203 | 202 |
$sort_options = array('order' => $options['subquery_order']); |
204 | 203 |
$temp_view->add_item('default', 'sort', $sort_table, $sort_field, $sort_options); |
205 | 204 |
} |
206 | 205 |
|
207 | 206 |
// Get the namespace string. |
208 |
$temp_view->namespace = (!empty($options['subquery_namespace'])) ? '_'. $options['subquery_namespace'] : '_INNER'; |
|
209 |
$this->subquery_namespace = (!empty($options['subquery_namespace'])) ? '_'. $options['subquery_namespace'] : 'INNER'; |
|
207 |
$temp_view->namespace = (!empty($options['subquery_namespace'])) ? '_' . $options['subquery_namespace'] : '_INNER';
|
|
208 |
$this->subquery_namespace = (!empty($options['subquery_namespace'])) ? '_' . $options['subquery_namespace'] : 'INNER';
|
|
210 | 209 |
|
211 | 210 |
// The value we add here does nothing, but doing this adds the right tables |
212 | 211 |
// and puts in a WHERE clause with a placeholder we can grab later. |
... | ... | |
217 | 216 |
$base_field = $views_data['table']['base']['field']; |
218 | 217 |
$temp_view->add_item('default', 'field', $this->definition['base'], $this->definition['field']); |
219 | 218 |
|
220 |
// Add the correct argument for our relationship's base |
|
221 |
// ie the 'how to get back to base' argument.
|
|
222 |
// The relationship definition tells us which one to use.
|
|
219 |
// Add the correct argument for our relationship's base ie the "how to get
|
|
220 |
// back to base" argument; the relationship definition defines which one to
|
|
221 |
// use. |
|
223 | 222 |
$temp_view->add_item( |
224 | 223 |
'default', |
225 | 224 |
'argument', |
226 |
$this->definition['argument table'], // eg 'term_node', |
|
227 |
$this->definition['argument field'] // eg 'tid' |
|
225 |
// For example, 'term_node', |
|
226 |
$this->definition['argument table'], |
|
227 |
// For example, 'tid'. |
|
228 |
$this->definition['argument field'] |
|
228 | 229 |
); |
229 | 230 |
|
230 | 231 |
// Build the view. The creates the query object and produces the query |
... | ... | |
235 | 236 |
// somewhat so we can get the SQL query from it. |
236 | 237 |
$subquery = $temp_view->build_info['query']; |
237 | 238 |
|
238 |
// Workaround until http://drupal.org/node/844910 is fixed:
|
|
239 |
// Workaround until http://drupal.org/node/844910 is fixed.
|
|
239 | 240 |
// Remove all fields from the SELECT except the base id. |
240 | 241 |
$fields =& $subquery->getFields(); |
241 | 242 |
foreach (array_keys($fields) as $field_name) { |
... | ... | |
245 | 246 |
} |
246 | 247 |
} |
247 | 248 |
|
248 |
// Make every alias in the subquery safe within the outer query by |
|
249 |
// appending a namespace to it, '_inner' by default.
|
|
249 |
// Make every alias in the subquery safe within the outer query by appending
|
|
250 |
// a namespace to it, '_inner' by default. |
|
250 | 251 |
$tables =& $subquery->getTables(); |
251 | 252 |
foreach (array_keys($tables) as $table_name) { |
252 | 253 |
$tables[$table_name]['alias'] .= $this->subquery_namespace; |
... | ... | |
264 | 265 |
$where =& $subquery->conditions(); |
265 | 266 |
$this->alter_subquery_condition($subquery, $where); |
266 | 267 |
// Not sure why, but our sort order clause doesn't have a table. |
267 |
// TODO: the call to add_item() above to add the sort handler is probably
|
|
268 |
// @todo The call to add_item() above to add the sort handler is probably
|
|
268 | 269 |
// wrong -- needs attention from someone who understands it. |
269 |
// In the meantime, this works, but with a leap of faith...
|
|
270 |
// In the meantime, this works, but with a leap of faith. |
|
270 | 271 |
$orders =& $subquery->getOrderBy(); |
272 |
$orders_tmp = array(); |
|
271 | 273 |
foreach ($orders as $order_key => $order) { |
272 |
// But if we're using a whole view, we don't know what we have! |
|
273 |
if ($options['subquery_view']) { |
|
274 |
list($sort_table, $sort_field) = explode('.', $order_key); |
|
275 |
} |
|
276 |
$orders[$sort_table . $this->subquery_namespace . '.' . $sort_field] = $order; |
|
277 |
unset($orders[$order_key]); |
|
274 |
// Until http://drupal.org/node/844910 is fixed, $order_key is a field |
|
275 |
// alias from SELECT. De-alias it using the View object. |
|
276 |
$sort_table = $temp_view->query->fields[$order_key]['table']; |
|
277 |
$sort_field = $temp_view->query->fields[$order_key]['field']; |
|
278 |
$orders_tmp[$sort_table . $this->subquery_namespace . '.' . $sort_field] = $order; |
|
278 | 279 |
} |
280 |
$orders = $orders_tmp; |
|
279 | 281 |
|
280 | 282 |
// The query we get doesn't include the LIMIT, so add it here. |
281 | 283 |
$subquery->range(0, 1); |
284 |
// Clone the query object to force recompilation of the underlying where and |
|
285 |
// having objects on the next step. |
|
286 |
$subquery = clone $subquery; |
|
287 |
|
|
288 |
// Add in Views Query Substitutions such as ***CURRENT_TIME***. |
|
289 |
views_query_views_alter($subquery); |
|
282 | 290 |
|
283 | 291 |
// Extract the SQL the temporary view built. |
284 | 292 |
$subquery_sql = $subquery->__toString(); |
285 | 293 |
|
286 |
// Replace the placeholder with the outer, correlated field. |
|
287 |
// Eg, change the placeholder ':users_uid' into the outer field 'users.uid'. |
|
288 |
// We have to work directly with the SQL, because putting a name of a field |
|
289 |
// into a SelectQuery that it does not recognize (because it's outer) just |
|
290 |
// makes it treat it as a string. |
|
291 |
$outer_placeholder = ':' . str_replace('.', '_', $this->definition['outer field']); |
|
292 |
$subquery_sql = str_replace($outer_placeholder, $this->definition['outer field'], $subquery_sql); |
|
294 |
// Replace subquery argument placeholders. |
|
295 |
$quoted = $subquery->getArguments(); |
|
296 |
$connection = Database::getConnection(); |
|
297 |
foreach ($quoted as $key => $val) { |
|
298 |
if (is_array($val)) { |
|
299 |
$quoted[$key] = implode(', ', array_map(array($connection, 'quote'), $val)); |
|
300 |
} |
|
301 |
// If the correlated placeholder has been located, replace it with the |
|
302 |
// outer field name. |
|
303 |
elseif ($val === '**CORRELATED**') { |
|
304 |
$quoted[$key] = $this->definition['outer field']; |
|
305 |
} |
|
306 |
else { |
|
307 |
$quoted[$key] = $connection->quote($val); |
|
308 |
} |
|
309 |
} |
|
310 |
$subquery_sql = strtr($subquery_sql, $quoted); |
|
293 | 311 |
|
294 | 312 |
return $subquery_sql; |
295 | 313 |
} |
... | ... | |
301 | 319 |
* |
302 | 320 |
* (Though why is the condition we get in a simple query 3 levels deep???) |
303 | 321 |
*/ |
304 |
function alter_subquery_condition(QueryAlterableInterface $query, &$conditions) { |
|
322 |
public function alter_subquery_condition(QueryAlterableInterface $query, &$conditions) {
|
|
305 | 323 |
foreach ($conditions as $condition_id => &$condition) { |
306 | 324 |
// Skip the #conjunction element. |
307 | 325 |
if (is_numeric($condition_id)) { |
... | ... | |
321 | 339 |
* |
322 | 340 |
* Turns 'foo.bar' into 'foo_NAMESPACE.bar'. |
323 | 341 |
*/ |
324 |
function condition_namespace($string) { |
|
342 |
public function condition_namespace($string) {
|
|
325 | 343 |
return str_replace('.', $this->subquery_namespace . '.', $string); |
326 | 344 |
} |
327 | 345 |
|
... | ... | |
330 | 348 |
* This is mostly a copy of our parent's query() except for this bit with |
331 | 349 |
* the join class. |
332 | 350 |
*/ |
333 |
function query() { |
|
351 |
public function query() {
|
|
334 | 352 |
// Figure out what base table this relationship brings to the party. |
335 | 353 |
$table_data = views_fetch_data($this->definition['base']); |
336 | 354 |
$base_field = empty($this->definition['base field']) ? $table_data['table']['base']['field'] : $this->definition['base field']; |
... | ... | |
374 | 392 |
$join->construct(); |
375 | 393 |
$join->adjusted = TRUE; |
376 | 394 |
|
377 |
// use a short alias for this:
|
|
395 |
// Use a short alias for this.
|
|
378 | 396 |
$alias = $def['table'] . '_' . $this->table; |
379 | 397 |
|
380 | 398 |
$this->alias = $this->query->add_relationship($alias, $join, $this->definition['base'], $this->relationship); |
381 | 399 |
} |
400 |
|
|
382 | 401 |
} |
Formats disponibles : Unified diff
Weekly update of contrib modules