00001 <?php
00002
00003
00004
00005
00006
00007
00056 class views_handler_relationship_groupwise_max extends views_handler_relationship {
00057
00061 function option_definition() {
00062 $options = parent::option_definition();
00063
00064 $options['subquery_sort'] = array('default' => NULL);
00065
00066 $options['subquery_order'] = array('default' => 'DESC');
00067 $options['subquery_regenerate'] = array('default' => FALSE);
00068 $options['subquery_view'] = array('default' => FALSE);
00069 $options['subquery_namespace'] = array('default' => FALSE);
00070
00071 return $options;
00072 }
00073
00078 function options_form(&$form, &$form_state) {
00079 parent::options_form($form, $form_state);
00080
00081
00082 $sorts = views_fetch_fields($this->definition['base'], 'sort');
00083 foreach ($sorts as $sort_id => $sort) {
00084 $sort_options[$sort_id] = "$sort[group]: $sort[title]";
00085 }
00086 $base_table_data = views_fetch_data($this->definition['base']);
00087
00088 $form['subquery_sort'] = array(
00089 '#type' => 'select',
00090 '#title' => t('Representative sort criteria'),
00091
00092 '#default_value' => !empty($this->options['subquery_sort']) ? $this->options['subquery_sort'] : $this->definition['base'] . '.' . $base_table_data['table']['base']['field'],
00093 '#options' => $sort_options,
00094 '#description' => theme('advanced_help_topic', array('module' => 'views', 'topic' => 'relationship-representative')) .
00095 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'."),
00096 );
00097
00098 $form['subquery_order'] = array(
00099 '#type' => 'radios',
00100 '#title' => t('Representative sort order'),
00101 '#description' => t("The ordering to use for the sort criteria selected above."),
00102 '#options' => array('ASC' => t('Ascending'), 'DESC' => t('Descending')),
00103 '#default_value' => $this->options['subquery_order'],
00104 );
00105
00106 $form['subquery_namespace'] = array(
00107 '#type' => 'textfield',
00108 '#title' => t('Subquery namespace'),
00109 '#description' => t('Advanced. Enter a namespace for the subquery used by this relationship.'),
00110 '#default_value' => $this->options['subquery_namespace'],
00111 );
00112
00113
00114
00115
00116 $views = array('' => '<none>');
00117 $all_views = views_get_all_views();
00118 foreach ($all_views as $view) {
00119
00120
00121
00122 if ($view->base_table == $this->definition['base'] && !empty($view->display['default']->display_options['fields'])) {
00123
00124
00125 if ($view->type == 'Default') {
00126 $views[t('Default Views')][$view->name] = $view->name;
00127 }
00128 else {
00129 $views[t('Existing Views')][$view->name] = $view->name;
00130 }
00131 }
00132 }
00133
00134 $form['subquery_view'] = array(
00135 '#type' => 'select',
00136 '#title' => t('Representative view'),
00137 '#default_value' => $this->options['subquery_view'],
00138 '#options' => $views,
00139 '#description' => t('Advanced. Use another view to generate the relationship subquery. This allows you to use filtering and more than one sort. If you pick a view here, the sort options above are ignored. Your view must have the ID of its base as its only field, and should have some kind of sorting.'),
00140 );
00141
00142 $form['subquery_regenerate'] = array(
00143 '#type' => 'checkbox',
00144 '#title' => t('Generate subquery each time view is run.'),
00145 '#default_value' => $this->options['subquery_regenerate'],
00146 '#description' => t('Will re-generate the subquery for this relationship every time the view is run, instead of only when these options are saved. Use for testing if you are making changes elsewhere. WARNING: seriously impairs performance.'),
00147 );
00148 }
00149
00157 function options_submit(&$form, &$form_state) {
00158
00159 $new_options = $form_state['values']['options'];
00160 $subquery = $this->left_query($new_options);
00161
00162 $this->options['subquery_string'] = $subquery;
00163 }
00164
00170 function get_temporary_view() {
00171 views_include('view');
00172 $view = new view();
00173 $view->vid = 'new';
00174 $view->base_table = $this->definition['base'];
00175 $view->add_display('default');
00176 return $view;
00177 }
00178
00192 function left_query($options) {
00193
00194 if ($options['subquery_view']) {
00195 $temp_view = views_get_view($options['subquery_view']);
00196
00197 unset($temp_view->display['default']->display_options['fields']);
00198 }
00199 else {
00200
00201
00202 $temp_view = $this->get_temporary_view();
00203
00204
00205
00206
00207
00208 $sort = $options['subquery_sort'];
00209 list($sort_table, $sort_field) = explode('.', $sort);
00210 $sort_options = array('order' => $options['subquery_order']);
00211 $temp_view->add_item('default', 'sort', $sort_table, $sort_field, $sort_options);
00212 }
00213
00214
00215 $temp_view->namespace = (!empty($options['subquery_namespace'])) ? '_'. $options['subquery_namespace'] : '_INNER';
00216 $this->subquery_namespace = (!empty($options['subquery_namespace'])) ? '_'. $options['subquery_namespace'] : 'INNER';
00217
00218
00219
00220 $temp_view->args[] = '**CORRELATED**';
00221
00222
00223 $views_data = views_fetch_data($this->definition['base']);
00224 $base_field = $views_data['table']['base']['field'];
00225 $temp_view->add_item('default', 'field', $this->definition['base'], $this->definition['field']);
00226
00227
00228
00229
00230 $temp_view->add_item(
00231 'default',
00232 'argument',
00233 $this->definition['argument table'],
00234 $this->definition['argument field']
00235 );
00236
00237
00238
00239 $temp_view->build();
00240
00241
00242
00243 $subquery = $temp_view->build_info['query'];
00244
00245
00246
00247 $fields =& $subquery->getFields();
00248 foreach (array_keys($fields) as $field_name) {
00249
00250 if ($field_name != $this->definition['field']) {
00251 unset($fields[$field_name]);
00252 }
00253 }
00254
00255
00256
00257 $tables =& $subquery->getTables();
00258 foreach (array_keys($tables) as $table_name) {
00259 $tables[$table_name]['alias'] .= $this->subquery_namespace;
00260
00261 if (isset($tables[$table_name]['condition'])) {
00262 $tables[$table_name]['condition'] = $this->condition_namespace($tables[$table_name]['condition']);
00263 }
00264 }
00265
00266 foreach (array_keys($fields) as $field_name) {
00267 $fields[$field_name]['table'] .= $this->subquery_namespace;
00268 $fields[$field_name]['alias'] .= $this->subquery_namespace;
00269 }
00270
00271 $where =& $subquery->conditions();
00272 $this->alter_subquery_condition($subquery, $where);
00273
00274
00275
00276
00277 $orders =& $subquery->getOrderBy();
00278 foreach ($orders as $order_key => $order) {
00279
00280 if ($options['subquery_view']) {
00281 list($sort_table, $sort_field) = explode('.', $order_key);
00282 }
00283 $orders[$sort_table . $this->subquery_namespace . '.' . $sort_field] = $order;
00284 unset($orders[$order_key]);
00285 }
00286
00287
00288 $subquery->range(0, 1);
00289
00290
00291 $subquery_sql = $subquery->__toString();
00292
00293
00294
00295
00296
00297
00298 $outer_placeholder = ':' . str_replace('.', '_', $this->definition['outer field']);
00299 $subquery_sql = str_replace($outer_placeholder, $this->definition['outer field'], $subquery_sql);
00300
00301 return $subquery_sql;
00302 }
00303
00311 function alter_subquery_condition(QueryAlterableInterface $query, &$conditions) {
00312 foreach ($conditions as $condition_id => &$condition) {
00313
00314 if (is_numeric($condition_id)) {
00315 if (is_string($condition['field'])) {
00316 $condition['field'] = $this->condition_namespace($condition['field']);
00317 }
00318 elseif (is_object($condition['field'])) {
00319 $sub_conditions =& $condition['field']->conditions();
00320 $this->alter_subquery_condition($query, $sub_conditions);
00321 }
00322 }
00323 }
00324 }
00325
00331 function condition_namespace($string) {
00332 return str_replace('.', $this->subquery_namespace . '.', $string);
00333 }
00334
00340 function query() {
00341
00342 $table_data = views_fetch_data($this->definition['base']);
00343 $base_field = empty($this->definition['base field']) ? $table_data['table']['base']['field'] : $this->definition['base field'];
00344
00345 $this->ensure_my_table();
00346
00347 $def = $this->definition;
00348 $def['table'] = $this->definition['base'];
00349 $def['field'] = $base_field;
00350 $def['left_table'] = $this->table_alias;
00351 $def['left_field'] = $this->field;
00352 if (!empty($this->options['required'])) {
00353 $def['type'] = 'INNER';
00354 }
00355
00356 if ($this->options['subquery_regenerate']) {
00357
00358 $def['left_query'] = $this->left_query($this->options);
00359 }
00360 else {
00361
00362 $def['left_query'] = $this->options['subquery_string'];
00363 }
00364
00365 if (!empty($def['join_handler']) && class_exists($def['join_handler'])) {
00366 $join = new $def['join_handler'];
00367 }
00368 else {
00369 $join = new views_join_subquery();
00370 }
00371
00372 $join->definition = $def;
00373 $join->construct();
00374 $join->adjusted = TRUE;
00375
00376
00377 $alias = $def['table'] . '_' . $this->table;
00378
00379 $this->alias = $this->query->add_relationship($alias, $join, $this->definition['base'], $this->relationship);
00380 }
00381 }