00001 <?php
00002
00011 class views_query {
00012
00016 var $table_queue = array();
00017
00021 var $tables = array();
00022
00027 var $relationships = array();
00028
00034 var $where = array();
00040 var $having = array();
00045 var $group_operator = 'AND';
00046
00050 var $orderby = array();
00051
00055 var $groupby = array();
00056
00061 var $header = array();
00062
00066 var $distinct = FALSE;
00067
00071 function views_query($base_table = 'node', $base_field = 'nid') {
00072 $this->base_table = $base_table;
00073 $this->base_field = $base_field;
00074 $this->relationships[$base_table] = array(
00075 'link' => NULL,
00076 'table' => $base_table,
00077 'alias' => $base_table,
00078 'base' => $base_table
00079 );
00080
00081
00082 $this->table_queue[$base_table] = array(
00083 'alias' => $base_table,
00084 'table' => $base_table,
00085 'relationship' => $base_table,
00086 'join' => NULL,
00087 );
00088
00089
00090 $this->tables[$base_table][$base_table] = array(
00091 'count' => 1,
00092 'alias' => $base_table,
00093 );
00094
00095 if ($base_field) {
00096 $this->fields[$base_field] = array(
00097 'table' => $base_table,
00098 'field' => $base_field,
00099 'alias' => $base_field,
00100 );
00101 }
00102
00103 $this->count_field = array(
00104 'table' => $base_table,
00105 'field' => $base_field,
00106 'alias' => $base_field,
00107 'count' => TRUE,
00108 );
00109 }
00110
00111
00112
00113
00117 function set_distinct($value = TRUE) {
00118 if (!(isset($this->no_distinct) && $value)) {
00119 $this->distinct = $value;
00120 }
00121 }
00122
00126 function set_count_field($table, $field, $alias = NULL) {
00127 if (empty($alias)) {
00128 $alias = $table . '_' . $field;
00129 }
00130 $this->count_field = array(
00131 'table' => $table,
00132 'field' => $field,
00133 'alias' => $alias,
00134 'count' => TRUE,
00135 );
00136 }
00137
00142 function set_header($header) {
00143 $this->header = $header;
00144 }
00145
00146
00147
00148
00177 function add_relationship($alias, $join, $base, $link_point = NULL) {
00178 if (empty($link_point)) {
00179 $link_point = $this->base_table;
00180 }
00181 else if (!array_key_exists($link_point, $this->relationships)) {
00182 return FALSE;
00183 }
00184
00185
00186 $alias_base = $alias;
00187 $count = 1;
00188 while (!empty($this->relationships[$alias])) {
00189 $alias = $alias_base . '_' . $count++;
00190 }
00191
00192
00193 if ($link_point && isset($this->relationships[$link_point])) {
00194 $join = $this->adjust_join($join, $link_point);
00195 }
00196
00197
00198
00199 $this->table_queue[$alias] = array(
00200 'table' => $join->table,
00201 'num' => 1,
00202 'alias' => $alias,
00203 'join' => $join,
00204 'relationship' => $link_point,
00205 );
00206
00207 $this->relationships[$alias] = array(
00208 'link' => $link_point,
00209 'table' => $join->table,
00210 'base' => $base,
00211 );
00212 return $alias;
00213 }
00214
00245 function add_table($table, $relationship = NULL, $join = NULL, $alias = NULL) {
00246 if (!$this->ensure_path($table, $relationship, $join)) {
00247 return FALSE;
00248 }
00249
00250 if (!$join) {
00251 $join = $this->get_join_data($table, $this->relationships[$relationship]['base']);
00252 }
00253
00254 $join = $this->adjust_join($join, $relationship);
00255
00256 return $this->queue_table($table, $relationship, $join, $alias);
00257 }
00258
00286 function queue_table($table, $relationship = NULL, $join = NULL, $alias = NULL) {
00287
00288 if (isset($this->table_queue[$alias])) {
00289 return $alias;
00290 }
00291
00292 if (empty($relationship)) {
00293 $relationship = $this->base_table;
00294 }
00295
00296 if (!array_key_exists($relationship, $this->relationships)) {
00297 return FALSE;
00298 }
00299
00300 if (!$alias && $join && $relationship && !empty($join->adjusted) && $table != $join->table) {
00301 if ($relationship == $this->base_table) {
00302 $alias = $table;
00303 }
00304 else {
00305 $alias = $relationship . '_' . $table;
00306 }
00307 }
00308
00309
00310
00311 if (isset($this->table_queue[$alias])) {
00312 return $alias;
00313 }
00314
00315 $alias = $this->mark_table($table, $relationship, $alias);
00316
00317
00318 if (!isset($alias)) {
00319 $alias = $this->tables[$relationship][$table]['alias'] . $this->tables[$relationship][$table]['count'];
00320 }
00321
00322
00323
00324 if ($table != $alias) {
00325 $this->mark_table($alias, $this->base_table, $alias);
00326 }
00327
00328
00329 if (!isset($join)) {
00330 $join = $this->get_join_data($table, $this->relationships[$relationship]['base']);
00331 if (empty($join)) {
00332 return FALSE;
00333 }
00334
00335 $join = $this->adjust_join($join, $relationship);
00336 }
00337
00338 $this->table_queue[$alias] = array(
00339 'table' => $table,
00340 'num' => $this->tables[$relationship][$table]['count'],
00341 'alias' => $alias,
00342 'join' => $join,
00343 'relationship' => $relationship,
00344 );
00345
00346 return $alias;
00347 }
00348
00349 function mark_table($table, $relationship, $alias) {
00350
00351 if (empty($this->tables[$relationship][$table])) {
00352 if (!isset($alias)) {
00353 $alias = '';
00354 if ($relationship != $this->base_table) {
00355
00356
00357 $alias = $relationship . '__';
00358 }
00359 $alias .= $table;
00360 }
00361 $this->tables[$relationship][$table] = array(
00362 'count' => 1,
00363 'alias' => $alias,
00364 );
00365 }
00366 else {
00367 $this->tables[$relationship][$table]['count']++;
00368 }
00369
00370 return $alias;
00371 }
00372
00391 function ensure_table($table, $relationship = NULL, $join = NULL) {
00392
00393 if (empty($relationship)) {
00394 $relationship = $this->base_table;
00395 }
00396
00397
00398
00399
00400
00401 if ($relationship == $this->base_table && !empty($this->tables[$relationship][$table])) {
00402 return $this->tables[$relationship][$table]['alias'];
00403 }
00404
00405 if (!array_key_exists($relationship, $this->relationships)) {
00406 return FALSE;
00407 }
00408
00409 if ($table == $this->relationships[$relationship]['base']) {
00410 return $relationship;
00411 }
00412
00413
00414 if (!isset($join)) {
00415 $join = $this->get_join_data($table, $this->relationships[$relationship]['base']);
00416 }
00417
00418
00419 if (empty($join)) {
00420 return;
00421 }
00422
00423
00424
00425
00426 $join = $this->adjust_join($join, $relationship);
00427
00428 if ($this->ensure_path($table, $relationship, $join)) {
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450 foreach ($this->table_queue as $queued_table) {
00451
00452
00453
00454 if ($queued_table['relationship'] == $relationship && $queued_table['join'] == $join) {
00455 return $queued_table['alias'];
00456 }
00457 }
00458
00459 return $this->queue_table($table, $relationship, $join);
00460 }
00461 }
00462
00470 function ensure_path($table, $relationship = NULL, $join = NULL, $traced = array(), $add = array()) {
00471 if (!isset($relationship)) {
00472 $relationship = $this->base_table;
00473 }
00474
00475 if (!array_key_exists($relationship, $this->relationships)) {
00476 return FALSE;
00477 }
00478
00479
00480 if (!isset($join)) {
00481 $join = $this->get_join_data($table, $this->relationships[$relationship]['base']);
00482 }
00483
00484
00485 if (empty($join)) {
00486 return FALSE;
00487 }
00488
00489
00490 if (isset($this->tables[$relationship][$table]) ||
00491 ($join && $join->left_table == $relationship) ||
00492 ($join && $join->left_table == $this->relationships[$relationship]['table'])) {
00493
00494
00495 foreach (array_reverse($add) as $table => $path_join) {
00496 $this->queue_table($table, $relationship, $this->adjust_join($path_join, $relationship));
00497 }
00498 return TRUE;
00499 }
00500
00501
00502 if (isset($traced[$join->left_table])) {
00503
00504 return FALSE;
00505 }
00506
00507
00508 $left_join = $this->get_join_data($join->left_table, $this->relationships[$relationship]['base']);
00509 if (!isset($this->tables[$relationship][$join->left_table])) {
00510 $add[$join->left_table] = $left_join;
00511 }
00512
00513
00514 $traced[$join->left_table] = TRUE;
00515 return $this->ensure_path($join->left_table, $relationship, $left_join, $traced, $add);
00516 }
00517
00522 function adjust_join($join, $relationship) {
00523 if (!empty($join->adjusted)) {
00524 return $join;
00525 }
00526
00527 if (empty($relationship) || empty($this->relationships[$relationship])) {
00528 return $join;
00529 }
00530
00531
00532 if ($relationship != $this->base_table) {
00533
00534
00535
00536
00537 $join = drupal_clone($join);
00538
00539
00540 if ($join->left_table != $this->relationships[$relationship]['table'] &&
00541 $join->left_table != $this->relationships[$relationship]['base'] &&
00542 !isset($this->tables[$relationship][$join->left_table]['alias'])) {
00543 $this->ensure_table($join->left_table, $relationship);
00544 }
00545
00546
00547 if ($join->left_table == $this->relationships[$relationship]['table']) {
00548 $join->left_table = $relationship;
00549 }
00550
00551 else if (isset($this->tables[$relationship][$join->left_table]['alias'])) {
00552 $join->left_table = $this->tables[$relationship][$join->left_table]['alias'];
00553 }
00554
00555 else if (isset($this->table_queue[$relationship]['alias'])) {
00556 $join->left_table = $this->table_queue[$relationship]['alias'];
00557 }
00558 }
00559
00560 $join->adjusted = TRUE;
00561 return $join;
00562 }
00563
00575 function get_join_data($table, $base_table) {
00576
00577
00578 if (!empty($this->table_queue[$table])) {
00579 $table = $this->table_queue[$table]['table'];
00580 }
00581 return views_get_table_join($table, $base_table);
00582
00583 }
00584
00591 function get_table_info($table) {
00592 if (!empty($this->table_queue[$table])) {
00593 return $this->table_queue[$table];
00594 }
00595
00596
00597 if (!empty($this->tables[$this->base_table][$table])) {
00598 $alias = $this->tables[$this->base_table][$table]['alias'];
00599 if (!empty($this->table_queue[$alias])) {
00600 return $this->table_queue[$alias];
00601 }
00602 }
00603 }
00604
00624 function add_field($table, $field, $alias = '', $params = NULL) {
00625
00626 if ($table == $this->base_table && $field == $this->base_field && empty($alias)) {
00627 $alias = $this->base_field;
00628 }
00629
00630 if ($table && empty($this->table_queue[$table])) {
00631 $this->ensure_table($table);
00632 }
00633
00634 if (!$alias && $table) {
00635 $alias = $table . '_' . $field;
00636 }
00637
00638 $name = $alias ? $alias : $field;
00639
00640
00641 if (empty($this->fields[$alias])) {
00642 $this->fields[$name] = array(
00643 'field' => $field,
00644 'table' => $table,
00645 'alias' => $alias,
00646 );
00647 }
00648
00649 foreach ((array)$params as $key => $value) {
00650 $this->fields[$name][$key] = $value;
00651 }
00652
00653 return $name;
00654 }
00655
00660 function clear_fields() {
00661 $this->fields = array();
00662 }
00663
00678 function set_where_group($type = 'AND', $group = NULL, $where = 'where') {
00679
00680 $groups = &$this->$where;
00681
00682 if (!isset($group)) {
00683 $group = empty($groups) ? 1 : max(array_keys($groups)) + 1;
00684 }
00685
00686
00687 if (empty($groups[$group])) {
00688 $groups[$group] = array('clauses' => array(), 'args' => array());
00689 }
00690
00691 $groups[$group]['type'] = strtoupper($type);
00692 return $group;
00693 }
00694
00701 function set_group_operator($type = 'AND') {
00702 $this->group_operator = strtoupper($type);
00703 }
00704
00723 function add_where($group, $clause) {
00724 $args = func_get_args();
00725 array_shift($args);
00726 array_shift($args);
00727
00728
00729 if (count($args) == 1 && is_array(reset($args))) {
00730 $args = current($args);
00731 }
00732
00733
00734
00735 if (empty($group)) {
00736 $group = 0;
00737 }
00738
00739
00740 if (!isset($this->where[$group])) {
00741 $this->set_where_group('AND', $group);
00742 }
00743
00744
00745 if (is_array($args)) {
00746 $this->where[$group]['clauses'][] = $clause;
00747
00748
00749 $this->where[$group]['args'] = array_merge($this->where[$group]['args'], array_values($args));
00750 }
00751 }
00752
00771 function add_having($group, $clause) {
00772 $args = func_get_args();
00773 array_shift($args);
00774 array_shift($args);
00775
00776
00777 if (count($args) == 1 && is_array(reset($args))) {
00778 $args = current($args);
00779 }
00780
00781
00782
00783 if (empty($group)) {
00784 $group = 0;
00785 }
00786
00787
00788 if (!isset($this->having[$group])) {
00789 $this->set_where_group('AND', $group, 'having');
00790 }
00791
00792
00793 if (is_array($args)) {
00794 $this->having[$group]['clauses'][] = $clause;
00795 $this->having[$group]['args'] = array_merge($this->having[$group]['args'], array_values($args));
00796 }
00797 }
00798
00815 function add_orderby($table, $field, $order, $alias = '') {
00816 if ($table) {
00817 $this->ensure_table($table);
00818 }
00819
00820
00821
00822 if (!$alias && $table) {
00823 $as = $table . '_' . $field;
00824 }
00825 else {
00826 $as = $alias;
00827 }
00828
00829 if ($field) {
00830 $this->add_field($table, $field, $as);
00831 }
00832
00833 $this->orderby[] = "$as " . strtoupper($order);
00834
00835
00836
00837
00838 if ($this->groupby && $table) {
00839 $this->add_groupby($as);
00840 }
00841 }
00842
00848 function add_groupby($clause) {
00849
00850 if (!in_array($clause, $this->groupby)) {
00851 $this->groupby[] = $clause;
00852 }
00853 }
00854
00861 function condition_sql($where = 'where') {
00862 $clauses = array();
00863 foreach ($this->$where as $group => $info) {
00864 $clause = implode(") " . $info['type'] . " (", $info['clauses']);
00865 if (count($info['clauses']) > 1) {
00866 $clause = '(' . $clause . ')';
00867 }
00868 $clauses[] = $clause;
00869 }
00870
00871 if ($clauses) {
00872 $keyword = drupal_strtoupper($where);
00873 if (count($clauses) > 1) {
00874 return "$keyword (" . implode(")\n " . $this->group_operator . ' (', $clauses) . ")\n";
00875 }
00876 else {
00877 return "$keyword " . array_shift($clauses) . "\n";
00878 }
00879 }
00880 return "";
00881 }
00882
00890 function query($get_count = FALSE) {
00891
00892 if (empty($this->no_distinct) && $this->distinct && !empty($this->fields)) {
00893 if (!empty($this->fields[$this->base_field])) {
00894 $this->fields[$this->base_field]['distinct'] = TRUE;
00895 $this->add_groupby($this->base_field);
00896 }
00897 }
00898
00903 $fields_array = $this->fields;
00904 if ($get_count && !$this->groupby) {
00905 foreach ($fields_array as $field) {
00906 if (!empty($field['distinct'])) {
00907 $get_count_optimized = FALSE;
00908 break;
00909 }
00910 }
00911 }
00912 else {
00913 $get_count_optimized = FALSE;
00914 }
00915 if (!isset($get_count_optimized)) {
00916 $get_count_optimized = TRUE;
00917 }
00918
00919 $joins = $fields = $where = $having = $orderby = $groupby = '';
00920
00921 foreach ($this->table_queue as $table) {
00922 if (is_object($table['join'])) {
00923 $joins .= $table['join']->join($table, $this) . "\n";
00924 }
00925 }
00926
00927 $has_aggregate = FALSE;
00928 $non_aggregates = array();
00929
00930 foreach ($fields_array as $field) {
00931 if ($fields) {
00932 $fields .= ",\n ";
00933 }
00934 $string = '';
00935 if (!empty($field['table'])) {
00936 $string .= $field['table'] . '.';
00937 }
00938 $string .= $field['field'];
00939
00940
00941 $fieldname = (!empty($field['alias']) ? $field['alias'] : $string);
00942
00943 if (!empty($field['distinct'])) {
00944 $string = "DISTINCT($string)";
00945 }
00946 if (!empty($field['count'])) {
00947 $string = "COUNT($string)";
00948 $has_aggregate = TRUE;
00949 }
00950 else if (!empty($field['aggregate'])) {
00951 $has_aggregate = TRUE;
00952 }
00953 elseif ($this->distinct && !in_array($fieldname, $this->groupby)) {
00954 $string = $GLOBALS['db_type'] == 'pgsql' ? "FIRST($string)" : $string;
00955 }
00956 else {
00957 $non_aggregates[] = $fieldname;
00958 }
00959 if ($field['alias']) {
00960 $string .= " AS $field[alias]";
00961 }
00962 $fields .= $string;
00963
00964 if ($get_count_optimized) {
00965
00966 break;
00967 }
00968 }
00969
00970 if ($has_aggregate || $this->groupby) {
00971 $groupby = "GROUP BY " . implode(', ', array_unique(array_merge($this->groupby, $non_aggregates))) . "\n";
00972 if ($this->having) {
00973 $having = $this->condition_sql('having');
00974 }
00975 }
00976
00977 if (!$get_count_optimized) {
00978
00979 if ($this->orderby) {
00980 $orderby = "ORDER BY " . implode(', ', $this->orderby) . "\n";
00981 }
00982 }
00983
00984 $where = $this->condition_sql();
00985
00986 $query = "SELECT $fields\n FROM {" . $this->base_table . "} $this->base_table \n$joins $where $groupby $having $orderby";
00987
00988 $replace = array('>' => '>', '<' => '<');
00989 $query = strtr($query, $replace);
00990
00991 return $query;
00992 }
00993
00997 function get_where_args() {
00998 $args = array();
00999 foreach ($this->where as $group => $where) {
01000 $args = array_merge($args, $where['args']);
01001 }
01002 foreach ($this->having as $group => $having) {
01003 $args = array_merge($args, $having['args']);
01004 }
01005 return $args;
01006 }
01007 }
01008