• Main Page
  • Related Pages
  • Modules
  • Classes
  • Files
  • File List
  • File Members

includes/view.inc

Go to the documentation of this file.
00001 <?php
00018 class view extends views_db_object {
00019   var $db_table = 'views_view';
00020   var $base_table = 'node';
00021   var $base_field = 'nid';
00022 
00028   var $name = "";
00029 
00035   var $vid;
00036 
00042   var $description;
00043 
00051   var $tag;
00052 
00058   var $human_name;
00059 
00064   var $core;
00065 
00073   var $api_version;
00074 
00082   var $disabled;
00083 
00084   // State variables
00085   var $built = FALSE;
00086   var $executed = FALSE;
00087   var $editing = FALSE;
00088 
00089   var $args = array();
00090   var $build_info = array();
00091 
00092   var $use_ajax = FALSE;
00093 
00094   // Where the results of a query will go.
00095   var $result = array();
00096 
00097   // May be used to override the current pager info.
00098   var $current_page = NULL;
00099   var $items_per_page = NULL;
00100   var $offset = NULL;
00101   var $total_rows = NULL;
00102 
00103   // Places to put attached renderings:
00104   var $attachment_before = '';
00105   var $attachment_after = '';
00106 
00107   // Exposed widget input
00108   var $exposed_data = array();
00109   var $exposed_input = array();
00110   // Exposed widget input directly from the $form_state['values'].
00111   var $exposed_raw_input = array();
00112 
00113   // Used to store views that were previously running if we recurse.
00114   var $old_view = array();
00115 
00116   // To avoid recursion in views embedded into areas.
00117   var $parent_views = array();
00118 
00119   // Is the current stored view runned as an attachment to another view.
00120   var $is_attachment = NULL;
00121 
00122   // Stores the next steps of form items to handle.
00123   // It's an array of stack items, which contain the form id, the type of form,
00124   // the view, the display and some additional arguments.
00125   // @see views_ui_add_form_to_stack().
00126   // var $stack;
00127 
00133   var $current_display;
00134 
00140   var $query = NULL;
00141 
00147   var $display_handler;
00148 
00154   var $display;
00155 
00161    var $style_plugin;
00162 
00169   var $style_options;
00170 
00176   var $row_index;
00177 
00183   var $override_url = NULL;
00184 
00190   var $override_path = NULL;
00191 
00195   var $base_database = NULL;
00196 
00205   var $field;
00206 
00211   var $argument;
00212 
00217   var $sort;
00218 
00223   var $filter;
00224 
00229   var $relationship;
00230 
00235   var $header;
00236 
00241   var $footer;
00242 
00247   var $empty;
00248 
00252   function __construct() {
00253     parent::init();
00254     // Make sure all of our sub objects are arrays.
00255     foreach ($this->db_objects() as $object) {
00256       $this->$object = array();
00257     }
00258   }
00259 
00267   function update() {
00268     // When views are converted automatically the base_table should be renamed
00269     // to have a working query.
00270     $this->base_table = views_move_table($this->base_table);
00271   }
00272 
00273 
00278   function display_objects() {
00279     return array('argument', 'field', 'sort', 'filter', 'relationship', 'header', 'footer', 'empty');
00280   }
00281 
00286   static function db_objects() {
00287     return array('display');
00288   }
00289 
00294   function set_arguments($args) {
00295     $this->args = $args;
00296   }
00297 
00301   function set_current_page($page) {
00302     $this->current_page = $page;
00303   }
00304 
00308   function get_current_page() {
00309     if (!empty($this->query->pager)) {
00310       return $this->query->pager->get_current_page();
00311     }
00312   }
00313 
00317   function get_items_per_page() {
00318     if (!empty($this->query->pager)) {
00319       return $this->query->pager->get_items_per_page();
00320     }
00321   }
00322 
00326   function set_items_per_page($items_per_page) {
00327     $this->items_per_page = $items_per_page;
00328 
00329     // If the pager is already initialized, pass it through to the pager.
00330     if (!empty($this->query->pager)) {
00331       $this->query->pager->set_items_per_page($items_per_page);
00332     }
00333   }
00334 
00338   function get_offset() {
00339     if (!empty($this->query->pager)) {
00340       return $this->query->pager->get_offset();
00341     }
00342   }
00343 
00347   function set_offset($offset) {
00348     $this->offset = $offset;
00349 
00350     // If the pager is already initialized, pass it through to the pager.
00351     if (!empty($this->query->pager)) {
00352       $this->query->pager->set_offset($offset);
00353     }
00354   }
00355 
00359   function use_pager() {
00360     if (!empty($this->query->pager)) {
00361       return $this->query->pager->use_pager();
00362     }
00363   }
00364 
00370   function set_use_ajax($use_ajax) {
00371     $this->use_ajax = $use_ajax;
00372   }
00373 
00378   function set_exposed_input($filters) {
00379     $this->exposed_input = $filters;
00380   }
00381 
00385   function get_exposed_input() {
00386     // Fill our input either from $_GET or from something previously set on the
00387     // view.
00388     if (empty($this->exposed_input)) {
00389       $this->exposed_input = $_GET;
00390       // unset items that are definitely not our input:
00391       foreach (array('page', 'q') as $key) {
00392         if (isset($this->exposed_input[$key])) {
00393           unset($this->exposed_input[$key]);
00394         }
00395       }
00396 
00397       // If we have no input at all, check for remembered input via session.
00398 
00399       // If filters are not overridden, store the 'remember' settings on the
00400       // default display. If they are, store them on this display. This way,
00401       // multiple displays in the same view can share the same filters and
00402       // remember settings.
00403       $display_id = ($this->display_handler->is_defaulted('filters')) ? 'default' : $this->current_display;
00404 
00405       if (empty($this->exposed_input) && !empty($_SESSION['views'][$this->name][$display_id])) {
00406         $this->exposed_input = $_SESSION['views'][$this->name][$display_id];
00407       }
00408     }
00409 
00410     return $this->exposed_input;
00411   }
00412 
00416   function init_display($reset = FALSE) {
00417     // The default display is always the first one in the list.
00418     if (isset($this->current_display)) {
00419       return TRUE;
00420     }
00421 
00422     // Instantiate all displays
00423     foreach (array_keys($this->display) as $id) {
00424       // Correct for shallow cloning
00425       // Often we'll have a cloned view so we don't mess up each other's
00426       // displays, but the clone is pretty shallow and doesn't necessarily
00427       // clone the displays. We can tell this by looking to see if a handler
00428       // has already been set; if it has, but $this->current_display is not
00429       // set, then something is dreadfully wrong.
00430       if (!empty($this->display[$id]->handler)) {
00431         $this->display[$id] = clone $this->display[$id];
00432         unset($this->display[$id]->handler);
00433       }
00434       $this->display[$id]->handler = views_get_plugin('display', $this->display[$id]->display_plugin);
00435       if (!empty($this->display[$id]->handler)) {
00436         $this->display[$id]->handler->localization_keys = array($id);
00437         // Initialize the new display handler with data.
00438         $this->display[$id]->handler->init($this, $this->display[$id]);
00439         // If this is NOT the default display handler, let it know which is
00440         // since it may well utilize some data from the default.
00441         // This assumes that the 'default' handler is always first. It always
00442         // is. Make sure of it.
00443         if ($id != 'default') {
00444           $this->display[$id]->handler->default_display = &$this->display['default']->handler;
00445         }
00446       }
00447     }
00448 
00449     $this->current_display = 'default';
00450     $this->display_handler = &$this->display['default']->handler;
00451 
00452     return TRUE;
00453   }
00454 
00461   function choose_display($displays) {
00462     if (!is_array($displays)) {
00463       return $displays;
00464     }
00465 
00466     $this->init_display();
00467 
00468     foreach ($displays as $display_id) {
00469       if ($this->display[$display_id]->handler->access()) {
00470         return $display_id;
00471       }
00472     }
00473 
00474     return 'default';
00475   }
00476 
00483   function set_display($display_id = NULL) {
00484     // If we have not already initialized the display, do so. But be careful.
00485     if (empty($this->current_display)) {
00486       $this->init_display();
00487 
00488       // If handlers were not initialized, and no argument was sent, set up
00489       // to the default display.
00490       if (empty($display_id)) {
00491         $display_id = 'default';
00492       }
00493     }
00494 
00495     $display_id = $this->choose_display($display_id);
00496 
00497     // If no display id sent in and one wasn't chosen above, we're finished.
00498     if (empty($display_id)) {
00499       return FALSE;
00500     }
00501 
00502     // Ensure the requested display exists.
00503     if (empty($this->display[$display_id])) {
00504       $display_id = 'default';
00505       if (empty($this->display[$display_id])) {
00506         vpr('set_display() called with invalid display id @display.', array('@display' => $display_id));
00507         return FALSE;
00508       }
00509     }
00510 
00511     // Set the current display.
00512     $this->current_display = $display_id;
00513 
00514     // Ensure requested display has a working handler.
00515     if (empty($this->display[$display_id]->handler)) {
00516       return FALSE;
00517     }
00518 
00519     // Set a shortcut
00520     $this->display_handler = &$this->display[$display_id]->handler;
00521 
00522     return TRUE;
00523   }
00524 
00531   function init_style() {
00532     if (isset($this->style_plugin)) {
00533       return is_object($this->style_plugin);
00534     }
00535 
00536     if (!isset($this->plugin_name)) {
00537       $this->plugin_name = $this->display_handler->get_option('style_plugin');
00538       $this->style_options = $this->display_handler->get_option('style_options');
00539     }
00540 
00541     $this->style_plugin = views_get_plugin('style', $this->plugin_name);
00542 
00543     if (empty($this->style_plugin)) {
00544       return FALSE;
00545     }
00546 
00547     // init the new style handler with data.
00548     $this->style_plugin->init($this, $this->display[$this->current_display], $this->style_options);
00549     return TRUE;
00550   }
00551 
00558   function fix_missing_relationships() {
00559     if (isset($this->relationships_fixed)) {
00560       return;
00561     }
00562 
00563     $this->relationships_fixed = TRUE;
00564 
00565     // Go through all of our handler types and test them to see if they
00566     // are missing relationships. Missing relationships can cause fatally
00567     // broken Views.
00568     $base_tables = array(
00569       $this->base_table => TRUE,
00570       '#global' => TRUE,
00571     );
00572 
00573     // For each relationship we have, make sure we mark the base it provides as
00574     // available.
00575     foreach ($this->display_handler->get_option('relationships') as $id => $options) {
00576       $options['table'] = views_move_table($options['table']);
00577       $data = views_fetch_data($options['table'], FALSE);
00578       if (isset($data[$options['field']])) {
00579         $base_tables[$data[$options['field']]['relationship']['base']] = TRUE;
00580       }
00581     }
00582 
00583     $base_tables = array_keys($base_tables);
00584     $missing_base_tables = array();
00585 
00586     $types = views_object_types();
00587     foreach ($types as $key => $info) {
00588       foreach ($this->display_handler->get_option($info['plural']) as $id => $options) {
00589         $options['table'] = views_move_table($options['table']);
00590         $data = views_fetch_data($options['table'], FALSE);
00591 
00592         $valid_bases = array($options['table']);
00593         if (isset($data['table']['join'])) {
00594           $valid_bases = array_merge($valid_bases, array_keys($data['table']['join']));
00595         }
00596 
00597         // If the base table is missing, record it so we can try to fix it.
00598         if (!array_intersect($valid_bases, $base_tables)) {
00599           $missing_base_tables[$options['table']][] = array('type' => $key, 'id' => $id);
00600         }
00601       }
00602     }
00603 
00604     if (!empty($missing_base_tables)) {
00605       // This will change handlers, so make sure any existing handlers get
00606       // tossed.
00607       $this->display_handler->handlers = array();
00608       $this->relationships_changed = TRUE;
00609       $this->changed = TRUE;
00610 
00611       // Try to fix it.
00612       foreach ($missing_base_tables as $table => $handlers) {
00613         $data = views_fetch_data($table);
00614         $relationship = NULL;
00615 
00616         // Does the missing base table have a default relationship we can
00617         // throw in?
00618         if (isset($data['table']['default_relationship'][$this->base_table])) {
00619           // Create the relationship.
00620           $info = $data['table']['default_relationship'][$this->base_table];
00621 
00622           $relationship_options = isset($info['options']) ? $info['options'] : array();
00623           $relationship = $this->add_item($this->current_display, 'relationship', $info['table'], $info['field'], $relationship_options);
00624         }
00625         foreach ($handlers as $handler) {
00626           $options = $this->display_handler->get_option($types[$handler['type']]['plural']);
00627           if ($relationship) {
00628             $options[$handler['id']]['relationship'] = $relationship;
00629           }
00630           else {
00631             unset($options[$handler['id']]);
00632           }
00633           $this->display_handler->set_option($types[$handler['type']]['plural'], $options);
00634         }
00635       }
00636     }
00637   }
00638 
00642   function init_handlers() {
00643     if (empty($this->inited)) {
00644       $this->fix_missing_relationships();
00645       foreach (views_object_types() as $key => $info) {
00646         $this->_init_handler($key, $info);
00647       }
00648       $this->inited = TRUE;
00649     }
00650   }
00651 
00658   function init_pager() {
00659     if (empty($this->query->pager)) {
00660       $this->query->pager = $this->display_handler->get_plugin('pager');
00661 
00662       if ($this->query->pager->use_pager()) {
00663         $this->query->pager->set_current_page($this->current_page);
00664       }
00665 
00666       // These overrides may have been set earlier via $view->set_*
00667       // functions.
00668       if (isset($this->items_per_page)) {
00669         $this->query->pager->set_items_per_page($this->items_per_page);
00670       }
00671 
00672       if (isset($this->offset)) {
00673         $this->query->pager->set_offset($this->offset);
00674       }
00675     }
00676   }
00677 
00682   function get_base_tables() {
00683     $base_tables = array(
00684       $this->base_table => TRUE,
00685       '#global' => TRUE,
00686     );
00687 
00688     foreach ($this->display_handler->get_handlers('relationship') as $handler) {
00689       $base_tables[$handler->definition['base']] = TRUE;
00690     }
00691     return $base_tables;
00692   }
00693 
00697   function _pre_query() {
00698     foreach (views_object_types() as $key => $info) {
00699       $handlers = &$this->$key;
00700       $position = 0;
00701       foreach ($handlers as $id => $handler) {
00702         $handlers[$id]->position = $position;
00703         $handlers[$id]->pre_query();
00704         $position++;
00705       }
00706     }
00707   }
00708 
00712   function _post_execute() {
00713     foreach (views_object_types() as $key => $info) {
00714       $handlers = &$this->$key;
00715       foreach ($handlers as $id => $handler) {
00716         $handlers[$id]->post_execute($this->result);
00717       }
00718     }
00719   }
00720 
00729   function _init_handler($key, $info) {
00730     // Load the requested items from the display onto the object.
00731     $this->$key = $this->display_handler->get_handlers($key);
00732 
00733     // This reference deals with difficult PHP indirection.
00734     $handlers = &$this->$key;
00735 
00736     // Run through and test for accessibility.
00737     foreach ($handlers as $id => $handler) {
00738       if (!$handler->access()) {
00739         unset($handlers[$id]);
00740       }
00741     }
00742   }
00743 
00747   function _build_arguments() {
00748     // Initially, we want to build sorts and fields. This can change, though,
00749     // if we get a summary view.
00750     if (empty($this->argument)) {
00751       return TRUE;
00752     }
00753 
00754     // build arguments.
00755     $position = -1;
00756 
00757     // Create a title for use in the breadcrumb trail.
00758     $title = $this->display_handler->get_option('title');
00759 
00760     $this->build_info['breadcrumb'] = array();
00761     $breadcrumb_args = array();
00762     $substitutions = array();
00763 
00764     $status = TRUE;
00765 
00766     // Iterate through each argument and process.
00767     foreach ($this->argument as $id => $arg) {
00768       $position++;
00769       $argument = &$this->argument[$id];
00770 
00771       if ($argument->broken()) {
00772         continue;
00773       }
00774 
00775       $argument->set_relationship();
00776 
00777       $arg = isset($this->args[$position]) ? $this->args[$position] : NULL;
00778       $argument->position = $position;
00779 
00780       if (isset($arg) || $argument->has_default_argument()) {
00781         if (!isset($arg)) {
00782           $arg = $argument->get_default_argument();
00783           // make sure default args get put back.
00784           if (isset($arg)) {
00785             $this->args[$position] = $arg;
00786           }
00787           // remember that this argument was computed, not passed on the URL.
00788           $argument->is_default = TRUE;
00789         }
00790 
00791         // Set the argument, which will also validate that the argument can be set.
00792         if (!$argument->set_argument($arg)) {
00793           $status = $argument->validate_fail($arg);
00794           break;
00795         }
00796 
00797         if ($argument->is_exception()) {
00798           $arg_title = $argument->exception_title();
00799         }
00800         else {
00801           $arg_title = $argument->get_title();
00802           $argument->query($this->display_handler->use_group_by());
00803         }
00804 
00805         // Add this argument's substitution
00806         $substitutions['%' . ($position + 1)] = $arg_title;
00807         $substitutions['!' . ($position + 1)] = strip_tags(decode_entities($arg));
00808 
00809         // Since we're really generating the breadcrumb for the item above us,
00810         // check the default action of this argument.
00811         if ($this->display_handler->uses_breadcrumb() && $argument->uses_breadcrumb()) {
00812           $path = $this->get_url($breadcrumb_args);
00813           if (strpos($path, '%') === FALSE) {
00814             if (!empty($argument->options['breadcrumb_enable']) && !empty($argument->options['breadcrumb'])) {
00815               $breadcrumb = $argument->options['breadcrumb'];
00816             }
00817             else {
00818               $breadcrumb = $title;
00819             }
00820             $this->build_info['breadcrumb'][$path] = str_replace(array_keys($substitutions), $substitutions, $breadcrumb);
00821           }
00822         }
00823 
00824         // Allow the argument to muck with this breadcrumb.
00825         $argument->set_breadcrumb($this->build_info['breadcrumb']);
00826 
00827         // Test to see if we should use this argument's title
00828         if (!empty($argument->options['title_enable']) && !empty($argument->options['title'])) {
00829           $title = $argument->options['title'];
00830         }
00831 
00832         $breadcrumb_args[] = $arg;
00833       }
00834       else {
00835         // determine default condition and handle.
00836         $status = $argument->default_action();
00837         break;
00838       }
00839 
00840       // Be safe with references and loops:
00841       unset($argument);
00842     }
00843 
00844     // set the title in the build info.
00845     if (!empty($title)) {
00846       $this->build_info['title'] = $title;
00847     }
00848 
00849     // Store the arguments for later use.
00850     $this->build_info['substitutions'] = $substitutions;
00851 
00852     return $status;
00853   }
00854 
00858   function init_query() {
00859     if (!empty($this->query)) {
00860       $class = get_class($this->query);
00861       if ($class && $class != 'stdClass') {
00862         // return if query is already initialized.
00863         return TRUE;
00864       }
00865     }
00866 
00867     // Create and initialize the query object.
00868     $views_data = views_fetch_data($this->base_table);
00869     $this->base_field = !empty($views_data['table']['base']['field']) ? $views_data['table']['base']['field'] : '';
00870     if (!empty($views_data['table']['base']['database'])) {
00871       $this->base_database = $views_data['table']['base']['database'];
00872     }
00873 
00874     // Load the options.
00875     $query_options = $this->display_handler->get_option('query');
00876 
00877     // Create and initialize the query object.
00878     $plugin = !empty($views_data['table']['base']['query class']) ? $views_data['table']['base']['query class'] : 'views_query';
00879     $this->query = views_get_plugin('query', $plugin);
00880 
00881     if (empty($this->query)) {
00882       return FALSE;
00883     }
00884 
00885     $this->query->init($this->base_table, $this->base_field, $query_options['options']);
00886     return TRUE;
00887   }
00888 
00892   function build($display_id = NULL) {
00893     if (!empty($this->built)) {
00894       return;
00895     }
00896 
00897     if (empty($this->current_display) || $display_id) {
00898       if (!$this->set_display($display_id)) {
00899         return FALSE;
00900       }
00901     }
00902 
00903     // Let modules modify the view just prior to building it.
00904     foreach (module_implements('views_pre_build') as $module) {
00905       $function = $module . '_views_pre_build';
00906       $function($this);
00907     }
00908 
00909     // Attempt to load from cache.
00910     // @todo Load a build_info from cache.
00911 
00912     $start = microtime(TRUE);
00913     // If that fails, let's build!
00914     $this->build_info = array(
00915       'query' => '',
00916       'count_query' => '',
00917       'query_args' => array(),
00918     );
00919 
00920     $this->init_query();
00921 
00922     // Call a module hook and see if it wants to present us with a
00923     // pre-built query or instruct us not to build the query for
00924     // some reason.
00925     // @todo: Implement this. Use the same mechanism Panels uses.
00926 
00927     // Run through our handlers and ensure they have necessary information.
00928     $this->init_handlers();
00929 
00930     // Let the handlers interact with each other if they really want.
00931     $this->_pre_query();
00932 
00933     if ($this->display_handler->uses_exposed()) {
00934       $exposed_form = $this->display_handler->get_plugin('exposed_form');
00935       $this->exposed_widgets = $exposed_form->render_exposed_form();
00936       if (form_set_error() || !empty($this->build_info['abort'])) {
00937         $this->built = TRUE;
00938         // Don't execute the query, but rendering will still be executed to display the empty text.
00939         $this->executed = TRUE;
00940         return empty($this->build_info['fail']);
00941       }
00942     }
00943 
00944     // Build all the relationships first thing.
00945     $this->_build('relationship');
00946 
00947     // Set the filtering groups.
00948     if (!empty($this->filter)) {
00949       $filter_groups = $this->display_handler->get_option('filter_groups');
00950       if ($filter_groups) {
00951         $this->query->set_group_operator($filter_groups['operator']);
00952         foreach($filter_groups['groups'] as $id => $operator) {
00953           $this->query->set_where_group($operator, $id);
00954         }
00955       }
00956     }
00957 
00958     // Build all the filters.
00959     $this->_build('filter');
00960 
00961     $this->build_sort = TRUE;
00962 
00963     // Arguments can, in fact, cause this whole thing to abort.
00964     if (!$this->_build_arguments()) {
00965       $this->build_time = microtime(TRUE) - $start;
00966       $this->attach_displays();
00967       return $this->built;
00968     }
00969 
00970     // Initialize the style; arguments may have changed which style we use,
00971     // so waiting as long as possible is important. But we need to know
00972     // about the style when we go to build fields.
00973     if (!$this->init_style()) {
00974       $this->build_info['fail'] = TRUE;
00975       return FALSE;
00976     }
00977 
00978     if ($this->style_plugin->uses_fields()) {
00979       $this->_build('field');
00980     }
00981 
00982     // Build our sort criteria if we were instructed to do so.
00983     if (!empty($this->build_sort)) {
00984       // Allow the style handler to deal with sorting.
00985       if ($this->style_plugin->build_sort()) {
00986         $this->_build('sort');
00987       }
00988       // allow the plugin to build second sorts as well.
00989       $this->style_plugin->build_sort_post();
00990     }
00991 
00992     // Allow area handlers to affect the query.
00993     $this->_build('header');
00994     $this->_build('footer');
00995     $this->_build('empty');
00996 
00997     // Allow display handler to affect the query:
00998     $this->display_handler->query($this->display_handler->use_group_by());
00999 
01000     // Allow style handler to affect the query:
01001     $this->style_plugin->query($this->display_handler->use_group_by());
01002 
01003     // Allow exposed form to affect the query:
01004     if (isset($exposed_form)) {
01005       $exposed_form->query();
01006     }
01007 
01008     if (variable_get('views_sql_signature', FALSE)) {
01009       $this->query->add_signature($this);
01010     }
01011 
01012     // Let modules modify the query just prior to finalizing it.
01013     $this->query->alter($this);
01014 
01015     // Only build the query if we weren't interrupted.
01016     if (empty($this->built)) {
01017       // Build the necessary info to execute the query.
01018       $this->query->build($this);
01019     }
01020 
01021     $this->built = TRUE;
01022     $this->build_time = microtime(TRUE) - $start;
01023 
01024     // Attach displays
01025     $this->attach_displays();
01026 
01027     // Let modules modify the view just after building it.
01028     foreach (module_implements('views_post_build') as $module) {
01029       $function = $module . '_views_post_build';
01030       $function($this);
01031     }
01032 
01033     return TRUE;
01034   }
01035 
01039   function _build($key) {
01040     $handlers = &$this->$key;
01041     foreach ($handlers as $id => $data) {
01042       if (!empty($handlers[$id]) && is_object($handlers[$id])) {
01043         // Give this handler access to the exposed filter input.
01044         if (!empty($this->exposed_data)) {
01045           $rc = $handlers[$id]->accept_exposed_input($this->exposed_data);
01046           $handlers[$id]->store_exposed_input($this->exposed_data, $rc);
01047           if (!$rc) {
01048             continue;
01049           }
01050         }
01051         $handlers[$id]->set_relationship();
01052         $handlers[$id]->query($this->display_handler->use_group_by());
01053       }
01054     }
01055   }
01056 
01060   function execute($display_id = NULL) {
01061     if (empty($this->built)) {
01062       if (!$this->build($display_id)) {
01063         return FALSE;
01064       }
01065     }
01066 
01067     if (!empty($this->executed)) {
01068       return TRUE;
01069     }
01070 
01071     // Don't allow to use deactivated displays, but display them on the live preview.
01072     if (!$this->display[$this->current_display]->handler->get_option('enabled') && empty($this->live_preview)) {
01073       $this->build_info['fail'] = TRUE;
01074       return FALSE;
01075     }
01076 
01077     // Let modules modify the view just prior to executing it.
01078     foreach (module_implements('views_pre_execute') as $module) {
01079       $function = $module . '_views_pre_execute';
01080       $function($this);
01081     }
01082 
01083     // Check for already-cached results.
01084     if (!empty($this->live_preview)) {
01085       $cache = FALSE;
01086     }
01087     else {
01088       $cache = $this->display_handler->get_plugin('cache');
01089     }
01090     if ($cache && $cache->cache_get('results')) {
01091       if($this->query->pager->use_pager()) {
01092         $this->query->pager->total_items = $this->total_rows;
01093         $this->query->pager->update_page_info();
01094       }
01095       vpr('Used cached results');
01096     }
01097     else {
01098       $this->query->execute($this);
01099       $this->_post_execute();
01100       if ($cache) {
01101         $cache->cache_set('results');
01102       }
01103     }
01104 
01105     // Let modules modify the view just after executing it.
01106     foreach (module_implements('views_post_execute') as $module) {
01107       $function = $module . '_views_post_execute';
01108       $function($this);
01109     }
01110 
01111     $this->executed = TRUE;
01112   }
01113 
01117   function render($display_id = NULL) {
01118     $this->execute($display_id);
01119 
01120     // Check to see if the build failed.
01121     if (!empty($this->build_info['fail'])) {
01122       return;
01123     }
01124 
01125     drupal_theme_initialize();
01126 
01127     $start = microtime(TRUE);
01128     if (!empty($this->live_preview) && variable_get('views_show_additional_queries', FALSE)) {
01129       $this->start_query_capture();
01130     }
01131 
01132     $exposed_form = $this->display_handler->get_plugin('exposed_form');
01133     $exposed_form->pre_render($this->result);
01134 
01135     // Check for already-cached output.
01136     if (!empty($this->live_preview)) {
01137       $cache = FALSE;
01138     }
01139     else {
01140       $cache = $this->display_handler->get_plugin('cache');
01141     }
01142     if ($cache && $cache->cache_get('output')) {
01143     }
01144     else {
01145       if ($cache) {
01146         $cache->cache_start();
01147       }
01148 
01149       // Run pre_render for the pager as it might change the result.
01150       if (!empty($this->query->pager)) {
01151         $this->query->pager->pre_render($this->result);
01152       }
01153 
01154       // Initialize the style plugin.
01155       $this->init_style();
01156 
01157       // Give field handlers the opportunity to perform additional queries
01158       // using the entire resultset prior to rendering.
01159       if ($this->style_plugin->uses_fields()) {
01160         foreach ($this->field as $id => $handler) {
01161           if (!empty($this->field[$id])) {
01162             $this->field[$id]->pre_render($this->result);
01163           }
01164         }
01165       }
01166 
01167       $this->style_plugin->pre_render($this->result);
01168 
01169       // Let modules modify the view just prior to rendering it.
01170       foreach (module_implements('views_pre_render') as $module) {
01171         $function = $module . '_views_pre_render';
01172         $function($this);
01173       }
01174 
01175       // Let the theme play too, because pre render is a very themey thing.
01176       $function = $GLOBALS['theme'] . '_views_pre_render';
01177       if (function_exists($function)) {
01178         $function($this);
01179       }
01180 
01181       $this->display_handler->output = $this->display_handler->render();
01182       if ($cache) {
01183         $cache->cache_set('output');
01184       }
01185     }
01186 
01187     $exposed_form->post_render($this->display_handler->output);
01188 
01189     if ($cache) {
01190       $cache->post_render($this->display_handler->output);
01191     }
01192 
01193     // Let modules modify the view output after it is rendered.
01194     foreach (module_implements('views_post_render') as $module) {
01195       $function = $module . '_views_post_render';
01196       $function($this, $this->display_handler->output, $cache);
01197     }
01198 
01199     // Let the theme play too, because post render is a very themey thing.
01200     $function = $GLOBALS['theme'] . '_views_post_render';
01201     if (function_exists($function)) {
01202       $function($this, $this->display_handler->output, $cache);
01203     }
01204 
01205     if (!empty($this->live_preview) && variable_get('views_show_additional_queries', FALSE)) {
01206       $this->end_query_capture();
01207     }
01208     $this->render_time = microtime(TRUE) - $start;
01209 
01210     return $this->display_handler->output;
01211   }
01212 
01216   function render_field($field, $row) {
01217     if (isset($this->field[$field]) && isset($this->result[$row])) {
01218       return $this->field[$field]->advanced_render($this->result[$row]);
01219     }
01220   }
01221 
01234   function execute_display($display_id = NULL, $args = array()) {
01235     if (empty($this->current_display) || $this->current_display != $this->choose_display($display_id)) {
01236       if (!$this->set_display($display_id)) {
01237         return FALSE;
01238       }
01239     }
01240 
01241     $this->pre_execute($args);
01242 
01243     // Execute the view
01244     $output = $this->display_handler->execute();
01245 
01246     $this->post_execute();
01247     return $output;
01248   }
01249 
01257   function preview($display_id = NULL, $args = array()) {
01258     if (empty($this->current_display) || ((!empty($display_id)) && $this->current_display != $display_id)) {
01259       if (!$this->set_display($display_id)) {
01260         return FALSE;
01261       }
01262     }
01263 
01264     $this->preview = TRUE;
01265     $this->pre_execute($args);
01266     // Preview the view.
01267     $output = $this->display_handler->preview();
01268 
01269     $this->post_execute();
01270     return $output;
01271   }
01272 
01277   function pre_execute($args = array()) {
01278     $this->old_view[] = views_get_current_view();
01279     views_set_current_view($this);
01280     $display_id = $this->current_display;
01281 
01282     // Prepare the view with the information we have, but only if we were
01283     // passed arguments, as they may have been set previously.
01284     if ($args) {
01285       $this->set_arguments($args);
01286     }
01287 
01288     // Let modules modify the view just prior to executing it.
01289     foreach (module_implements('views_pre_view') as $module) {
01290       $function = $module . '_views_pre_view';
01291       $function($this, $display_id, $this->args);
01292     }
01293 
01294     // Allow the display handler to set up for execution
01295     $this->display_handler->pre_execute();
01296   }
01297 
01301   function post_execute() {
01302     // unset current view so we can be properly destructed later on.
01303     // Return the previous value in case we're an attachment.
01304 
01305     if ($this->old_view) {
01306       $old_view = array_pop($this->old_view);
01307     }
01308 
01309     views_set_current_view(isset($old_view) ? $old_view : FALSE);
01310   }
01311 
01315   function attach_displays() {
01316     if (!empty($this->is_attachment)) {
01317       return;
01318     }
01319 
01320     if (!$this->display_handler->accept_attachments()) {
01321       return;
01322     }
01323 
01324     $this->is_attachment = TRUE;
01325     // Give other displays an opportunity to attach to the view.
01326     foreach ($this->display as $id => $display) {
01327       if (!empty($this->display[$id]->handler)) {
01328         $this->display[$id]->handler->attach_to($this->current_display);
01329       }
01330     }
01331     $this->is_attachment = FALSE;
01332   }
01333 
01342   function execute_hook_menu($display_id = NULL, &$callbacks = array()) {
01343     // Prepare the view with the information we have.
01344 
01345     // This was probably already called, but it's good to be safe.
01346     if (!$this->set_display($display_id)) {
01347       return FALSE;
01348     }
01349 
01350     // Execute the view
01351     if (isset($this->display_handler)) {
01352       return $this->display_handler->execute_hook_menu($callbacks);
01353     }
01354   }
01355 
01360   function execute_hook_block_list($display_id = NULL) {
01361     // Prepare the view with the information we have.
01362 
01363     // This was probably already called, but it's good to be safe.
01364     if (!$this->set_display($display_id)) {
01365       return FALSE;
01366     }
01367 
01368     // Execute the view
01369     if (isset($this->display_handler)) {
01370       return $this->display_handler->execute_hook_block_list();
01371     }
01372   }
01373 
01378   function access($displays = NULL, $account = NULL) {
01379     // Noone should have access to disabled views.
01380     if (!empty($this->disabled)) {
01381       return FALSE;
01382     }
01383 
01384     if (!isset($this->current_display)) {
01385       $this->init_display();
01386     }
01387 
01388     if (!$account) {
01389       $account = $GLOBALS['user'];
01390     }
01391 
01392     // We can't use choose_display() here because that function
01393     // calls this one.
01394     $displays = (array)$displays;
01395     foreach ($displays as $display_id) {
01396       if (!empty($this->display[$display_id]->handler)) {
01397         if ($this->display[$display_id]->handler->access($account)) {
01398           return TRUE;
01399         }
01400       }
01401     }
01402 
01403     return FALSE;
01404   }
01405 
01410   function get_title() {
01411     if (empty($this->display_handler)) {
01412       if (!$this->set_display('default')) {
01413         return FALSE;
01414       }
01415     }
01416 
01417     // During building, we might find a title override. If so, use it.
01418     if (!empty($this->build_info['title'])) {
01419       $title = $this->build_info['title'];
01420     }
01421     else {
01422       $title = $this->display_handler->get_option('title');
01423     }
01424 
01425     // Allow substitutions from the first row.
01426     if ($this->init_style()) {
01427       $title = $this->style_plugin->tokenize_value($title, 0);
01428     }
01429     return $title;
01430   }
01431 
01437   function set_title($title) {
01438      $this->build_info['title'] = $title;
01439      return TRUE;
01440    }
01441 
01447   function get_human_name() {
01448     if (!empty($this->human_name)) {
01449       $human_name = $this->human_name;
01450     }
01451     else {
01452       $human_name = $this->name;
01453     }
01454     return $human_name;
01455   }
01456 
01460   function build_title() {
01461     $this->init_display();
01462 
01463     if (empty($this->built)) {
01464       $this->init_query();
01465     }
01466 
01467     $this->init_handlers();
01468 
01469     $this->_build_arguments();
01470   }
01471 
01477   function get_url($args = NULL, $path = NULL) {
01478     if (!empty($this->override_url)) {
01479       return $this->override_url;
01480     }
01481 
01482     if (!isset($path)) {
01483       $path = $this->get_path();
01484     }
01485     if (!isset($args)) {
01486       $args = $this->args;
01487 
01488       // Exclude arguments that were computed, not passed on the URL.
01489       $position = 0;
01490       if (!empty($this->argument)) {
01491         foreach ($this->argument as $argument_id => $argument) {
01492           if (!empty($argument->is_default) && !empty($argument->options['default_argument_skip_url'])) {
01493             unset($args[$position]);
01494           }
01495           $position++;
01496         }
01497       }
01498     }
01499     // Don't bother working if there's nothing to do:
01500     if (empty($path) || (empty($args) && strpos($path, '%') === FALSE)) {
01501       return $path;
01502     }
01503 
01504     $pieces = array();
01505     $argument_keys = isset($this->argument) ? array_keys($this->argument) : array();
01506     $id = current($argument_keys);
01507     foreach (explode('/', $path) as $piece) {
01508       if ($piece != '%') {
01509         $pieces[] = $piece;
01510       }
01511       else {
01512         if (empty($args)) {
01513           // Try to never put % in a url; use the wildcard instead.
01514           if ($id && !empty($this->argument[$id]->options['exception']['value'])) {
01515             $pieces[] = $this->argument[$id]->options['exception']['value'];
01516           }
01517           else {
01518             $pieces[] = '*'; // gotta put something if there just isn't one.
01519           }
01520 
01521         }
01522         else {
01523           $pieces[] = array_shift($args);
01524         }
01525 
01526         if ($id) {
01527           $id = next($argument_keys);
01528         }
01529       }
01530     }
01531 
01532     if (!empty($args)) {
01533       $pieces = array_merge($pieces, $args);
01534     }
01535     return implode('/', $pieces);
01536   }
01537 
01541   function get_path() {
01542     if (!empty($this->override_path)) {
01543       return $this->override_path;
01544     }
01545 
01546     if (empty($this->display_handler)) {
01547       if (!$this->set_display('default')) {
01548         return FALSE;
01549       }
01550     }
01551     return $this->display_handler->get_path();
01552   }
01553 
01560   function get_breadcrumb($set = FALSE) {
01561     // Now that we've built the view, extract the breadcrumb.
01562     $base = TRUE;
01563     $breadcrumb = array();
01564 
01565     if (!empty($this->build_info['breadcrumb'])) {
01566       foreach ($this->build_info['breadcrumb'] as $path => $title) {
01567         // Check to see if the frontpage is in the breadcrumb trail; if it
01568         // is, we'll remove that from the actual breadcrumb later.
01569         if ($path == variable_get('site_frontpage', 'node')) {
01570           $base = FALSE;
01571           $title = t('Home');
01572         }
01573         if ($title) {
01574           $breadcrumb[] = l($title, $path, array('html' => true));
01575         }
01576       }
01577 
01578       if ($set) {
01579         if ($base) {
01580           $breadcrumb = array_merge(drupal_get_breadcrumb(), $breadcrumb);
01581         }
01582         drupal_set_breadcrumb($breadcrumb);
01583       }
01584     }
01585     return $breadcrumb;
01586   }
01587 
01591   function is_cacheable() {
01592     return $this->is_cacheable;
01593   }
01594 
01604   function start_query_capture() {
01605     global $conf, $queries;
01606     if (empty($conf['dev_query'])) {
01607       $this->fix_dev_query = TRUE;
01608       $conf['dev_query'] = TRUE;
01609     }
01610 
01611     // Record the last query key used; anything already run isn't
01612     // a query that we are interested in.
01613     $this->last_query_key = NULL;
01614 
01615     if (!empty($queries)) {
01616       $keys = array_keys($queries);
01617       $this->last_query_key = array_pop($keys);
01618     }
01619   }
01620 
01626   function end_query_capture() {
01627     global $conf, $queries;
01628     if (!empty($this->fix_dev_query)) {
01629       $conf['dev_query'] = FALSE;
01630     }
01631 
01632     // make a copy of the array so we can manipulate it with array_splice.
01633     $temp = $queries;
01634 
01635     // Scroll through the queries until we get to our last query key.
01636     // Unset anything in our temp array.
01637     if (isset($this->last_query_key)) {
01638       while (list($id, $query) = each($queries)) {
01639         if ($id == $this->last_query_key) {
01640           break;
01641         }
01642 
01643         unset($temp[$id]);
01644       }
01645     }
01646 
01647     $this->additional_queries = $temp;
01648   }
01649 
01657   static function load_views() {
01658     $result = db_query("SELECT DISTINCT v.* FROM {views_view} v");
01659     $views = array();
01660 
01661     // Load all the views.
01662     foreach ($result as $data) {
01663       $view = new view;
01664       $view->load_row($data);
01665       $view->loaded = TRUE;
01666       $view->type = t('Normal');
01667       $views[$view->name] = $view;
01668       $names[$view->vid] = $view->name;
01669     }
01670 
01671     // Stop if we didn't get any views.
01672     if (!$views) {
01673       return array();
01674     }
01675 
01676     // Now load all the subtables:
01677     foreach (view::db_objects() as $key) {
01678       $object_name = "views_$key";
01679       $result = db_query("SELECT * FROM {{$object_name}} WHERE vid IN (:vids) ORDER BY vid, position",
01680         array(':vids' => array_keys($names)));
01681 
01682       foreach ($result as $data) {
01683         $object = new $object_name(FALSE);
01684         $object->load_row($data);
01685 
01686         // Because it can get complicated with this much indirection,
01687         // make a shortcut reference.
01688         $location = &$views[$names[$object->vid]]->$key;
01689 
01690         // If we have a basic id field, load the item onto the view based on
01691         // this ID, otherwise push it on.
01692         if (!empty($object->id)) {
01693           $location[$object->id] = $object;
01694         }
01695         else {
01696           $location[] = $object;
01697         }
01698       }
01699     }
01700     return $views;
01701   }
01702 
01707   function save() {
01708     if ($this->vid == 'new') {
01709       $this->vid = NULL;
01710     }
01711 
01712     // If we have no vid or our vid is a string, this is a new view.
01713     if (!empty($this->vid)) {
01714       // remove existing table entries
01715       foreach ($this->db_objects() as $key) {
01716         db_delete('views_' . $key)
01717           ->condition('vid', $this->vid)
01718           ->execute();
01719       }
01720     }
01721 
01722     $this->save_row(!empty($this->vid) ? 'vid' : FALSE);
01723 
01724     // Save all of our subtables.
01725     foreach ($this->db_objects() as $key) {
01726       $this->_save_rows($key);
01727     }
01728 
01729     $this->save_locale_strings();
01730 
01731     cache_clear_all('views_urls', 'cache_views');
01732     cache_clear_all(); // clear the page cache as well.
01733   }
01734 
01739   function _save_rows($key) {
01740     $count = 0;
01741     foreach ($this->$key as $position => $object) {
01742       $object->position = ++$count;
01743       $object->vid = $this->vid;
01744       $object->save_row();
01745     }
01746   }
01747 
01751   function delete($clear = TRUE) {
01752     if (empty($this->vid)) {
01753       return;
01754     }
01755 
01756     db_delete('views_view')
01757       ->condition('vid', $this->vid)
01758       ->execute();
01759     // Delete from all of our subtables as well.
01760     foreach ($this->db_objects() as $key) {
01761       db_delete('views_'. $key)
01762         ->condition('vid', $this->vid)
01763         ->execute();
01764     }
01765 
01766     cache_clear_all('views_query:' . $this->name, 'cache_views');
01767 
01768     if ($clear) {
01769       cache_clear_all(); // this clears the block and page caches only.
01770       menu_rebuild(); // force a menu rebuild when a view is deleted.
01771     }
01772   }
01773 
01777   function export($indent = '') {
01778     $this->init_display();
01779     $this->init_query();
01780     $output = '';
01781     $output .= $this->export_row('view', $indent);
01782     // Set the API version
01783     $output .= $indent . '$view->api_version = \'' . views_api_version() . "';\n";
01784     $output .= $indent . '$view->disabled = FALSE; /* Edit this to true to make a default view disabled initially */' . "\n";
01785 
01786     foreach ($this->display as $id => $display) {
01787       $output .= "\n" . $indent . "/* Display: $display->display_title */\n";
01788       $output .= $indent . '$handler = $view->new_display(' . ctools_var_export($display->display_plugin, $indent) . ', ' . ctools_var_export($display->display_title, $indent) . ', \'' . $id . "');\n";
01789       if (empty($display->handler)) {
01790         // @todo -- probably need a method of exporting broken displays as
01791         // they may simply be broken because a module is not installed. That
01792         // does not invalidate the display.
01793         continue;
01794       }
01795 
01796       $output .= $display->handler->export_options($indent, '$handler->options');
01797     }
01798 
01799     // Give the localization system a chance to export translatables to code.
01800     if ($this->init_localization()) {
01801       $this->export_locale_strings('export');
01802       $translatables = $this->localization_plugin->export_render($indent);
01803       if (!empty($translatables)) {
01804         $output .= $translatables;
01805       }
01806     }
01807 
01808     return $output;
01809   }
01810 
01817   function copy() {
01818     $code = $this->export();
01819     eval($code);
01820     return $view;
01821   }
01822 
01837   function clone_view() {
01838     $clone = version_compare(phpversion(), '5.0') < 0 ? $this : clone($this);
01839 
01840     $keys = array('current_display', 'display_handler', 'build_info', 'built', 'executed', 'attachment_before', 'attachment_after', 'field', 'argument', 'filter', 'sort', 'relationship', 'header', 'footer', 'empty', 'query', 'inited', 'style_plugin', 'plugin_name', 'exposed_data', 'exposed_input', 'exposed_widgets', 'many_to_one_tables', 'feed_icon');
01841     foreach ($keys as $key) {
01842       if (isset($clone->$key)) {
01843         unset($clone->$key);
01844       }
01845     }
01846     $clone->built = $clone->executed = FALSE;
01847     $clone->build_info = array();
01848     $clone->attachment_before = '';
01849     $clone->attachment_after = '';
01850     $clone->result = array();
01851 
01852     // shallow cloning means that all the display objects
01853     // *were not cloned*. We must clone them ourselves.
01854     $displays = array();
01855     foreach ($clone->display as $id => $display) {
01856       $displays[$id] = clone $display;
01857       if (isset($displays[$id]->handler)) {
01858         unset($displays[$id]->handler);
01859       }
01860     }
01861     $clone->display = $displays;
01862 
01863     return $clone;
01864   }
01865 
01870   function destroy() {
01871     foreach (array_keys($this->display) as $display_id) {
01872       if (isset($this->display[$display_id]->handler)) {
01873         $this->display[$display_id]->handler->destroy();
01874         unset($this->display[$display_id]->handler);
01875       }
01876     }
01877 
01878     foreach (views_object_types() as $type => $info) {
01879       if (isset($this->$type)) {
01880         $handlers = &$this->$type;
01881         foreach ($handlers as $id => $item) {
01882           $handlers[$id]->destroy();
01883         }
01884         unset($handlers);
01885       }
01886     }
01887 
01888     if (isset($this->style_plugin)) {
01889       $this->style_plugin->destroy();
01890       unset($this->style_plugin);
01891     }
01892 
01893     // Clear these to make sure the view can be processed/used again.
01894     if (isset($this->display_handler)) {
01895       unset($this->display_handler);
01896     }
01897 
01898     if (isset($this->current_display)) {
01899       unset($this->current_display);
01900     }
01901 
01902     if (isset($this->query)) {
01903       unset($this->query);
01904     }
01905 
01906     $keys = array('current_display', 'display_handler', 'build_info', 'built', 'executed', 'attachment_before', 'attachment_after', 'field', 'argument', 'filter', 'sort', 'relationship', 'header', 'footer', 'empty', 'query', 'result', 'inited', 'style_plugin', 'plugin_name', 'exposed_data', 'exposed_input', 'many_to_one_tables');
01907     foreach ($keys as $key) {
01908       if (isset($this->$key)) {
01909         unset($this->$key);
01910       }
01911     }
01912     $this->built = $this->executed = FALSE;
01913     $this->build_info = array();
01914     $this->attachment_before = '';
01915     $this->attachment_after = '';
01916   }
01917 
01924   function validate() {
01925     $this->init_display();
01926 
01927     $errors = array();
01928 
01929     $current_display = $this->current_display;
01930     foreach ($this->display as $id => $display) {
01931       if ($display->handler) {
01932         if (!empty($display->deleted)) {
01933           continue;
01934         }
01935 
01936         $result = $this->display[$id]->handler->validate();
01937         if (!empty($result) && is_array($result)) {
01938           $errors = array_merge($errors, $result);
01939         }
01940       }
01941     }
01942 
01943     $this->set_display($current_display);
01944     return $errors ? $errors : TRUE;
01945   }
01946 
01950   function init_localization() {
01951     if (isset($this->localization_plugin) && is_object($this->localization_plugin)) {
01952       return TRUE;
01953     }
01954 
01955     $this->localization_plugin = views_get_plugin('localization', views_get_localization_plugin());
01956 
01957     if (empty($this->localization_plugin)) {
01958       return FALSE;
01959     }
01960 
01964     $this->localization_plugin->init($this);
01965 
01966     return $this->localization_plugin->translate;
01967   }
01968 
01972   function is_translatable() {
01973     // If the view is normal or overridden, use admin string translation.
01974     // A newly created view won't have a type. Accept this.
01975     return (!isset($this->type) || in_array($this->type, array(t('Normal'), t('Overridden')))) ? TRUE : FALSE;
01976   }
01977 
01981   function save_locale_strings() {
01982     $this->process_locale_strings('save');
01983   }
01984 
01988   function delete_locale_strings() {
01989     $this->process_locale_strings('delete');
01990   }
01991 
01995   function export_locale_strings() {
01996     $this->process_locale_strings('export');
01997   }
01998 
02002   function process_locale_strings($op) {
02003     // Ensure this view supports translation, we have a display, and we
02004     // have a localization plugin.
02005     // @fixme Export does not init every handler.
02006     if (($this->is_translatable() || $op == 'export') && $this->init_display() && $this->init_localization()) {
02007       $this->localization_plugin->process_locale_strings($op);
02008     }
02009   }
02010 
02011 }
02012 
02016 class views_db_object {
02017   public $db_table;
02018 
02027   function init($init = TRUE) {
02028     if (is_array($init)) {
02029       return $this->load_row($init);
02030     }
02031 
02032     if (!$init) {
02033       return;
02034     }
02035 
02036     $schema = drupal_get_schema($this->db_table);
02037 
02038     if (!$schema) {
02039       return;
02040     }
02041 
02042     // Go through our schema and build correlations.
02043     foreach ($schema['fields'] as $field => $info) {
02044       if ($info['type'] == 'serial') {
02045         $this->$field = NULL;
02046       }
02047       if (!isset($this->$field)) {
02048         if (!empty($info['serialize']) && isset($info['serialized default'])) {
02049           $this->$field = unserialize($info['serialized default']);
02050         }
02051         elseif (isset($info['default'])) {
02052           $this->$field = $info['default'];
02053         }
02054         else {
02055           $this->$field = '';
02056         }
02057       }
02058     }
02059   }
02060 
02067   function save_row($update = NULL) {
02068     $fields = $defs = $values = $serials = array();
02069     $schema = drupal_get_schema($this->db_table);
02070 
02071     // Go through our schema and build correlations.
02072     foreach ($schema['fields'] as $field => $info) {
02073       // special case -- skip serial types if we are updating.
02074       if ($info['type'] == 'serial') {
02075         $serials[] = $field;
02076         continue;
02077       }
02078       elseif ($info['type'] == 'int') {
02079         $this->$field = (int) $this->$field;
02080       }
02081       $fields[$field] = empty($info['serialize']) ? $this->$field : serialize($this->$field);
02082     }
02083     if (!$update) {
02084       $query = db_insert($this->db_table);
02085     }
02086     else {
02087       $query = db_update($this->db_table)
02088         ->condition($update, $this->$update);
02089     }
02090     $return = $query
02091       ->fields($fields)
02092       ->execute();
02093 
02094     if ($serials && !$update) {
02095       // get last insert ids and fill them in.
02096       // Well, one ID.
02097       foreach ($serials as $field) {
02098         $this->$field = $return;
02099       }
02100     }
02101   }
02102 
02114   function load_row($data) {
02115     $schema = drupal_get_schema($this->db_table);
02116 
02117     // Go through our schema and build correlations.
02118     foreach ($schema['fields'] as $field => $info) {
02119       $this->$field = empty($info['serialize']) ? $data->$field : unserialize($data->$field);
02120     }
02121   }
02122 
02131   function export_row($identifier = NULL, $indent = '') {
02132     ctools_include('export');
02133 
02134     if (!$identifier) {
02135       $identifier = $this->db_table;
02136     }
02137     $schema = drupal_get_schema($this->db_table);
02138 
02139     $output = $indent . '$' . $identifier . ' = new ' . get_class($this) . ";\n";
02140     // Go through our schema and build correlations.
02141     foreach ($schema['fields'] as $field => $info) {
02142       if (!empty($info['no export'])) {
02143         continue;
02144       }
02145       if (!isset($this->$field)) {
02146         if (isset($info['default'])) {
02147           $this->$field = $info['default'];
02148         }
02149         else {
02150           $this->$field = '';
02151         }
02152 
02153         // serialized defaults must be set as serialized.
02154         if (isset($info['serialize'])) {
02155           $this->$field = unserialize(db_decode_blob($this->$field));
02156         }
02157       }
02158       $value = $this->$field;
02159       if ($info['type'] == 'int') {
02160         if (isset($info['size']) && $info['size'] == 'tiny') {
02161           $value = (bool) $value;
02162         }
02163         else {
02164           $value = (int) $value;
02165         }
02166       }
02167 
02168       $output .= $indent . '$' . $identifier . '->' . $field . ' = ' . ctools_var_export($value, $indent) . ";\n";
02169     }
02170     return $output;
02171   }
02172 
02186   function add_display($type = 'page', $title = NULL, $id = NULL) {
02187     if (empty($type)) {
02188       return FALSE;
02189     }
02190 
02191     $plugin = views_fetch_plugin_data('display', $type);
02192     if (empty($plugin)) {
02193       $plugin['title'] = t('Broken');
02194     }
02195 
02196 
02197     if (empty($id)) {
02198       $id = $this->generate_display_id($type);
02199       if ($id !== 'default') {
02200         preg_match("/[0-9]+/", $id, $count);
02201         $count = $count[0];
02202       }
02203       else {
02204         $count = '';
02205       }
02206 
02207       if (empty($title)) {
02208         if ($count > 1) {
02209           $title = $plugin['title'] . ' ' . $count;
02210         }
02211         else {
02212           $title = $plugin['title'];
02213         }
02214       }
02215     }
02216 
02217     // Create the new display object
02218     $display = new views_display;
02219     $display->options($type, $id, $title);
02220 
02221     // Add the new display object to the view.
02222     $this->display[$id] = $display;
02223     return $id;
02224   }
02225 
02232   function generate_display_id($type) {
02233     // 'default' is singular and is unique, so just go with 'default'
02234     // for it. For all others, start counting.
02235     if ($type == 'default') {
02236       return 'default';
02237     }
02238     // Initial id.
02239     $id = $type . '_1';
02240     $count = 1;
02241 
02242     // Loop through IDs based upon our style plugin name until
02243     // we find one that is unused.
02244     while (!empty($this->display[$id])) {
02245       $id = $type . '_' . ++$count;
02246     }
02247 
02248     return $id;
02249   }
02250 
02266   public static function generate_item_id($requested_id, $existing_items) {
02267     $count = 0;
02268     $id = $requested_id;
02269     while (!empty($existing_items[$id])) {
02270       $id = $requested_id . '_' . ++$count;
02271     }
02272     return $id;
02273   }
02274 
02286   function &new_display($type = 'page', $title = NULL, $id = NULL) {
02287     $id = $this->add_display($type, $title, $id);
02288 
02289     // Create a handler
02290     $this->display[$id]->handler = views_get_plugin('display', $this->display[$id]->display_plugin);
02291     if (empty($this->display[$id]->handler)) {
02292       // provide a 'default' handler as an emergency. This won't work well but
02293       // it will keep things from crashing.
02294       $this->display[$id]->handler = views_get_plugin('display', 'default');
02295     }
02296 
02297     if (!empty($this->display[$id]->handler)) {
02298       // Initialize the new display handler with data.
02299       $this->display[$id]->handler->init($this, $this->display[$id]);
02300       // If this is NOT the default display handler, let it know which is
02301       if ($id != 'default') {
02302         $this->display[$id]->handler->default_display = &$this->display['default']->handler;
02303       }
02304     }
02305 
02306     return $this->display[$id]->handler;
02307   }
02308 
02314   function add_item($display_id, $type, $table, $field, $options = array(), $id = NULL) {
02315     $types = views_object_types();
02316     $this->set_display($display_id);
02317 
02318     $fields = $this->display[$display_id]->handler->get_option($types[$type]['plural']);
02319 
02320     if (empty($id)) {
02321       $id = $this->generate_item_id($field, $fields);
02322     }
02323 
02324     $new_item = array(
02325       'id' => $id,
02326       'table' => $table,
02327       'field' => $field,
02328     ) + $options;
02329 
02330     if (!empty($types[$type]['type'])) {
02331       $handler_type = $types[$type]['type'];
02332     }
02333     else {
02334       $handler_type = $type;
02335     }
02336 
02337     $handler = views_get_handler($table, $field, $handler_type);
02338 
02339     $fields[$id] = $new_item;
02340     $this->display[$display_id]->handler->set_option($types[$type]['plural'], $fields);
02341 
02342     return $id;
02343   }
02344 
02348   function get_items($type, $display_id = NULL) {
02349     $this->set_display($display_id);
02350 
02351     if (!isset($display_id)) {
02352       $display_id = $this->current_display;
02353     }
02354 
02355     // Get info about the types so we can get the right data.
02356     $types = views_object_types();
02357     return $this->display[$display_id]->handler->get_option($types[$type]['plural']);
02358   }
02359 
02364   function get_item($display_id, $type, $id) {
02365     // Get info about the types so we can get the right data.
02366     $types = views_object_types();
02367     // Initialize the display
02368     $this->set_display($display_id);
02369 
02370     // Get the existing configuration
02371     $fields = $this->display[$display_id]->handler->get_option($types[$type]['plural']);
02372 
02373     return isset($fields[$id]) ? $fields[$id] : NULL;
02374   }
02375 
02382   function set_item($display_id, $type, $id, $item) {
02383     // Get info about the types so we can get the right data.
02384     $types = views_object_types();
02385     // Initialize the display
02386     $this->set_display($display_id);
02387 
02388     // Get the existing configuration
02389     $fields = $this->display[$display_id]->handler->get_option($types[$type]['plural']);
02390     if (isset($item)) {
02391       $fields[$id] = $item;
02392     }
02393     else {
02394       unset($fields[$id]);
02395     }
02396 
02397     // Store.
02398     $this->display[$display_id]->handler->set_option($types[$type]['plural'], $fields);
02399   }
02400 
02408   function set_item_option($display_id, $type, $id, $option, $value) {
02409     $item = $this->get_item($display_id, $type, $id);
02410     $item[$option] = $value;
02411     $this->set_item($display_id, $type, $id, $item);
02412   }
02413 }
02414 
02421 class views_display extends views_db_object {
02427   var $handler;
02428 
02434   var $display_options;
02435 
02436   var $db_table = 'views_display';
02437   function views_display($init = TRUE) {
02438     parent::init($init);
02439   }
02440 
02441   function options($type, $id, $title) {
02442     $this->display_plugin = $type;
02443     $this->id = $id;
02444     $this->display_title = $title;
02445   }
02446 }
02447 
02452 function views_object_types() {
02453   static $retval = NULL;
02454 
02455   // statically cache this so t() doesn't run a bajillion times.
02456   if (!isset($retval)) {
02457     $retval = array(
02458       'field' => array(
02459         'title' => t('Fields'), // title
02460         'ltitle' => t('fields'), // lowercase title for mid-sentence
02461         'stitle' => t('Field'), // singular title
02462         'lstitle' => t('field'), // singular lowercase title for mid sentence
02463         'plural' => 'fields',
02464       ),
02465       'argument' => array(
02466         'title' => t('Contextual filters'),
02467         'ltitle' => t('contextual filters'),
02468         'stitle' => t('Contextual filter'),
02469         'lstitle' => t('contextual filter'),
02470         'plural' => 'arguments',
02471       ),
02472       'sort' => array(
02473         'title' => t('Sort criteria'),
02474         'ltitle' => t('sort criteria'),
02475         'stitle' => t('Sort criterion'),
02476         'lstitle' => t('sort criterion'),
02477         'plural' => 'sorts',
02478       ),
02479       'filter' => array(
02480         'title' => t('Filter criteria'),
02481         'ltitle' => t('filter criteria'),
02482         'stitle' => t('Filter criterion'),
02483         'lstitle' => t('filter criterion'),
02484         'plural' => 'filters',
02485       ),
02486       'relationship' => array(
02487         'title' => t('Relationships'),
02488         'ltitle' => t('relationships'),
02489         'stitle' => t('Relationship'),
02490         'lstitle' => t('Relationship'),
02491         'plural' => 'relationships',
02492       ),
02493       'header' => array(
02494         'title' => t('Header'),
02495         'ltitle' => t('header'),
02496         'stitle' => t('Header'),
02497         'lstitle' => t('Header'),
02498         'plural' => 'header',
02499         'type' => 'area',
02500       ),
02501       'footer' => array(
02502         'title' => t('Footer'),
02503         'ltitle' => t('footer'),
02504         'stitle' => t('Footer'),
02505         'lstitle' => t('Footer'),
02506         'plural' => 'footer',
02507         'type' => 'area',
02508       ),
02509       'empty' => array(
02510         'title' => t('No results behavior'),
02511         'ltitle' => t('no results behavior'),
02512         'stitle' => t('No results behavior'),
02513         'lstitle' => t('No results behavior'),
02514         'plural' => 'empty',
02515         'type' => 'area',
02516       ),
02517     );
02518   }
02519 
02520   return $retval;
02521 }
02522 

Generated on Sun Feb 26 2012 12:52:51 for Views by  doxygen 1.7.1