[ Index ]

PHP Cross Reference of Drupal 6 (yi-drupal)

title

Body

[close]

/sites/all/modules/views/includes/ -> handlers.inc (source)

   1  <?php
   2  /**
   3   * @file handlers.inc
   4   * Defines the various handler objects to help build and display views.
   5   */
   6  
   7  /**
   8   * Instantiate and construct a new handler
   9   */
  10  function _views_create_handler($definition, $type = 'handler') {
  11  //  vpr('Instantiating handler ' . $definition['handler']);
  12    if (empty($definition['handler'])) {
  13      return;
  14    }
  15  
  16    if (!class_exists($definition['handler']) && !views_include_handler($definition, $type)) {
  17      return;
  18    }
  19  
  20    $handler = new $definition['handler'];
  21    $handler->set_definition($definition);
  22    // let the handler have something like a constructor.
  23    $handler->construct();
  24  
  25    return $handler;
  26  }
  27  
  28  /**
  29   * Attempt to find the include file for a given handler from its definition.
  30   *
  31   * This will also attempt to include all parents, though we're maxing the
  32   * parent chain to 10 to prevent infinite loops.
  33   */
  34  function views_include_handler($definition, $type, $count = 0) {
  35    // Do not proceed if the class already exists.
  36    if (isset($definition['handler']) && class_exists($definition['handler'])) {
  37      return TRUE;
  38    }
  39  
  40    // simple infinite loop prevention.
  41    if ($count > 10) {
  42      vpr(t('Handler @handler include tried to loop infinitely!', array('@handler' => $definition['handler'])));
  43      return FALSE;
  44    }
  45  
  46    if (!isset($definition['path'])) {
  47      if ($type == 'handler') {
  48        $definition += views_fetch_handler_data($definition['handler']);
  49      }
  50      else {
  51        $definition += views_fetch_plugin_data($type, $definition['handler']);
  52      }
  53    }
  54  
  55    if (!empty($definition['parent'])) {
  56      if ($type == 'handler') {
  57        $parent = views_fetch_handler_data($definition['parent']);
  58      }
  59      else {
  60        $parent = views_fetch_plugin_data($type, $definition['parent']);
  61      }
  62  
  63      if ($parent) {
  64        $rc = views_include_handler($parent, $type, $count + 1);
  65        // If the parent chain cannot be included, don't try; this will
  66        // help alleviate problems with modules with cross dependencies.
  67        if (!$rc) {
  68          return FALSE;
  69        }
  70      }
  71    }
  72  
  73    if (isset($definition['path']) && $definition['file']) {
  74      $filename = './' . $definition['path'] . '/' . $definition['file'];
  75      if (file_exists($filename)) {
  76        require_once $filename;
  77      }
  78    }
  79  
  80    return class_exists($definition['handler']);
  81  }
  82  
  83  /**
  84   * Prepare a handler's data by checking defaults and such.
  85   */
  86  function _views_prepare_handler($definition, $data, $field) {
  87    foreach (array('group', 'title', 'title short', 'help', 'real field') as $key) {
  88      if (!isset($definition[$key])) {
  89        // First check the field level
  90        if (!empty($data[$field][$key])) {
  91          $definition[$key] = $data[$field][$key];
  92        }
  93        // Then if that doesn't work, check the table level
  94        else if (!empty($data['table'][$key])) {
  95          $definition[$key] = $data['table'][$key];
  96        }
  97      }
  98    }
  99  
 100    return _views_create_handler($definition);
 101  }
 102  
 103  /**
 104   * Fetch the handler data from cache.
 105   */
 106  function views_fetch_handler_data($handler = NULL) {
 107    static $cache = NULL;
 108    if (!isset($cache)) {
 109      $start = views_microtime();
 110  
 111      $cache = views_discover_handlers();
 112  
 113      vpr('Views handlers build time: ' . (views_microtime() - $start) * 1000 . ' ms');
 114    }
 115  
 116    if (!$handler) {
 117      return $cache;
 118    }
 119    else if (isset($cache[$handler])) {
 120      return $cache[$handler];
 121    }
 122  
 123    // Return an empty array if there is no match.
 124    return array();
 125  }
 126  
 127  /**
 128   * Builds and return a list of all handlers available in the system.
 129   *
 130   * @return Nested array of handlers
 131   */
 132  function views_discover_handlers() {
 133    $cache = array();
 134    // Get handlers from all modules.
 135    foreach (module_implements('views_handlers') as $module) {
 136      $function = $module . '_views_handlers';
 137      $result = $function();
 138      if (!is_array($result)) {
 139        continue;
 140      }
 141  
 142      $module_dir = isset($result['info']['module']) ? $result['info']['module'] : $module;
 143      $path = isset($result['info']['path']) ? $result['info']['path'] : drupal_get_path('module', $module_dir);
 144  
 145      foreach ($result['handlers'] as $handler => $def) {
 146        if (!isset($def['module'])) {
 147          $def['module'] = $module_dir;
 148        }
 149        if (!isset($def['path'])) {
 150          $def['path'] = $path;
 151        }
 152        if (!isset($def['file'])) {
 153          $def['file'] = "$handler.inc";
 154        }
 155        if (!isset($def['handler'])) {
 156          $def['handler'] = $handler;
 157        }
 158        // merge the new data in
 159        $cache[$handler] = $def;
 160      }
 161    }
 162    return $cache;
 163  }
 164  
 165  /**
 166   * Fetch a handler to join one table to a primary table from the data cache
 167   */
 168  function views_get_table_join($table, $base_table) {
 169    $data = views_fetch_data($table);
 170    if (isset($data['table']['join'][$base_table])) {
 171      $h = $data['table']['join'][$base_table];
 172      if (!empty($h['handler']) && class_exists($h['handler'])) {
 173        $handler = new $h['handler'];
 174      }
 175      else {
 176        $handler = new views_join();
 177      }
 178  
 179      // Fill in some easy defaults
 180      $handler->definition = $h;
 181      if (empty($handler->definition['table'])) {
 182        $handler->definition['table'] = $table;
 183      }
 184      // If this is empty, it's a direct link.
 185      if (empty($handler->definition['left_table'])) {
 186        $handler->definition['left_table'] = $base_table;
 187      }
 188  
 189      if (isset($h['arguments'])) {
 190        call_user_func_array(array(&$handler, 'construct'), $h['arguments']);
 191      }
 192      else {
 193        $handler->construct();
 194      }
 195  
 196      return $handler;
 197    }
 198    // DEBUG -- identify missing handlers
 199    vpr("Missing join: $table $base_table");
 200  }
 201  
 202  /**
 203   * Base handler, from which all the other handlers are derived.
 204   * It creates a common interface to create consistency amongst
 205   * handlers and data.
 206   *
 207   * This class would be abstract in PHP5, but PHP4 doesn't understand that.
 208   *
 209   * Definition terms:
 210   * - table: The actual table this uses; only specify if different from
 211   *          the table this is attached to.
 212   * - real field: The actual field this uses; only specify if different from
 213   *               the field this item is attached to.
 214   * - group: A text string representing the 'group' this item is attached to,
 215   *          for display in the UI. Examples: "Node", "Taxonomy", "Comment",
 216   *          "User", etc. This may be inherited from the parent definition or
 217   *          the 'table' definition.
 218   * - title: The title for this handler in the UI. This may be inherited from
 219   *          the parent definition or the 'table' definition.
 220   * - help: A more informative string to give to the user to explain what this
 221   *         field/handler is or does.
 222   * - access callback: If this field should have access control, this could
 223   *                    be a function to use. 'user_access' is a common
 224   *                    function to use here. If not specified, no access
 225   *                    control is provided.
 226   * - access arguments: An array of arguments for the access callback.
 227   */
 228  class views_handler extends views_object {
 229    /**
 230     * init the handler with necessary data.
 231     * @param $view
 232     *   The $view object this handler is attached to.
 233     * @param $options
 234     *   The item from the database; the actual contents of this will vary
 235     *   based upon the type of handler.
 236     */
 237    function init(&$view, $options) {
 238      $this->view = &$view;
 239      $this->unpack_options($this->options, $options);
 240  
 241      // This exist on most handlers, but not all. So they are still optional.
 242      if (isset($options['table'])) {
 243        $this->table = $options['table'];
 244      }
 245  
 246      if (isset($this->definition['real field'])) {
 247        $this->real_field = $this->definition['real field'];
 248      }
 249  
 250      if (isset($this->definition['field'])) {
 251        $this->real_field = $this->definition['field'];
 252      }
 253  
 254      if (isset($options['field'])) {
 255        $this->field = $options['field'];
 256        if (!isset($this->real_field)) {
 257          $this->real_field = $options['field'];
 258        }
 259      }
 260  
 261      $this->query = &$view->query;
 262    }
 263  
 264    /**
 265     * Return a string representing this handler's name in the UI.
 266     */
 267    function ui_name($short = FALSE) {
 268      $title = ($short && isset($this->definition['title short'])) ? $this->definition['title short'] : $this->definition['title'];
 269      return t('!group: !title', array('!group' => $this->definition['group'], '!title' => $title));
 270    }
 271  
 272    /**
 273     * Provide a form for setting options.
 274     */
 275    function options_form(&$form, &$form_state) { }
 276  
 277    /**
 278     * Validate the options form.
 279     */
 280    function options_validate($form, &$form_state) { }
 281  
 282    /**
 283     * Perform any necessary changes to the form values prior to storage.
 284     * There is no need for this function to actually store the data.
 285     */
 286    function options_submit($form, &$form_state) { }
 287  
 288    /**
 289     * If a handler has 'extra options' it will get a little settings widget and
 290     * another form called extra_options.
 291     */
 292    function has_extra_options() { return FALSE; }
 293  
 294    /**
 295     * Provide defaults for the handler.
 296     */
 297    function extra_options(&$option) { }
 298  
 299    /**
 300     * Provide a form for setting options.
 301     */
 302    function extra_options_form(&$form, &$form_state) { }
 303  
 304    /**
 305     * Validate the options form.
 306     */
 307    function extra_options_validate($form, &$form_state) { }
 308  
 309    /**
 310     * Perform any necessary changes to the form values prior to storage.
 311     * There is no need for this function to actually store the data.
 312     */
 313    function extra_options_submit($form, &$form_state) { }
 314  
 315    /**
 316     * Set new exposed option defaults when exposed setting is flipped
 317     * on.
 318     */
 319    function expose_options() { }
 320    /**
 321     * Render our chunk of the exposed filter form when selecting
 322     */
 323    function exposed_form(&$form, &$form_state) { }
 324  
 325    /**
 326     * Validate the exposed filter form
 327     */
 328    function exposed_validate(&$form, &$form_state) { }
 329  
 330    /**
 331     * Submit the exposed filter form
 332     */
 333    function exposed_submit(&$form, &$form_state) { }
 334  
 335    /**
 336     * Get information about the exposed form for the form renderer.
 337     *
 338     * @return
 339     *   An array with the following keys:
 340     *   - operator: The $form key of the operator. Set to NULL if no operator.
 341     *   - value: The $form key of the value. Set to NULL if no value.
 342     *   - label: The label to use for this piece.
 343     */
 344    function exposed_info() { }
 345  
 346    /**
 347     * Determine if a handler can be exposed.
 348     */
 349    function can_expose() { return FALSE; }
 350  
 351   /**
 352    * Check whether current user has access to this handler.
 353    *
 354    * @return boolean
 355    */
 356    function access() {
 357      if (isset($this->definition['access callback']) && function_exists($this->definition['access callback'])) {
 358        if (isset($this->definition['access arguments']) && is_array($this->definition['access arguments'])) {
 359          return call_user_func_array($this->definition['access callback'], $this->definition['access arguments']);
 360        }
 361        return $this->definition['access callback']();
 362      }
 363  
 364      return TRUE;
 365    }
 366  
 367    /**
 368     * Run before the view is built.
 369     *
 370     * This gives all the handlers some time to set up before any handler has
 371     * been fully run.
 372     */
 373    function pre_query() { }
 374  
 375    /**
 376     * Called just prior to query(), this lets a handler set up any relationship
 377     * it needs.
 378     */
 379    function set_relationship() {
 380      // Ensure this gets set to something.
 381      $this->relationship = NULL;
 382  
 383      // Don't process non-existant relationships.
 384      if (empty($this->options['relationship']) || $this->options['relationship'] == 'none') {
 385        return;
 386      }
 387  
 388      $relationship = $this->options['relationship'];
 389  
 390      // Ignore missing/broken relationships.
 391      if (empty($this->view->relationship[$relationship])) {
 392        return;
 393      }
 394  
 395      // Check to see if the relationship has already processed. If not, then we
 396      // cannot process it.
 397      if (empty($this->view->relationship[$relationship]->alias)) {
 398        return;
 399      }
 400  
 401      // Finally!
 402      $this->relationship = $this->view->relationship[$relationship]->alias;
 403    }
 404  
 405    /**
 406     * Add this handler into the query.
 407     *
 408     * If we were using PHP5, this would be abstract.
 409     */
 410    function query() { }
 411  
 412    /**
 413     * Ensure the main table for this handler is in the query. This is used
 414     * a lot.
 415     */
 416    function ensure_my_table() {
 417      if (!isset($this->table_alias)) {
 418        $this->table_alias = $this->query->ensure_table($this->table, $this->relationship);
 419      }
 420      return $this->table_alias;
 421    }
 422  
 423    /**
 424     * Provide text for the administrative summary
 425     */
 426    function admin_summary() { }
 427  
 428    /**
 429     * Determine if the argument needs a style plugin.
 430     *
 431     * @return TRUE/FALSE
 432     */
 433    function needs_style_plugin() { return FALSE; }
 434  
 435    /**
 436     * Determine if this item is 'exposed', meaning it provides form elements
 437     * to let users modify the view.
 438     *
 439     * @return TRUE/FALSE
 440     */
 441    function is_exposed() {
 442      return !empty($this->options['exposed']);
 443    }
 444  
 445    /**
 446     * Take input from exposed filters and assign to this handler, if necessary.
 447     */
 448    function accept_exposed_input($input) { return TRUE; }
 449  
 450    /**
 451     * If set to remember exposed input in the session, store it there.
 452     */
 453    function store_exposed_input($input, $status) { return TRUE; }
 454  
 455    /**
 456     * Get the join object that should be used for this handler.
 457     *
 458     * This method isn't used a great deal, but it's very handy for easily
 459     * getting the join if it is necessary to make some changes to it, such
 460     * as adding an 'extra'.
 461     */
 462    function get_join() {
 463      // get the join from this table that links back to the base table.
 464      // Determine the primary table to seek
 465      if (empty($this->query->relationships[$this->relationship])) {
 466        $base_table = $this->query->base_table;
 467      }
 468      else {
 469        $base_table = $this->query->relationships[$this->relationship]['base'];
 470      }
 471  
 472      $join = views_get_table_join($this->table, $base_table);
 473      if ($join) {
 474        return drupal_clone($join);
 475      }
 476    }
 477  
 478    /**
 479     * Validates the handler against the complete View.
 480     *
 481     * This is called when the complete View is being validated. For validating
 482     * the handler options form use options_validate().
 483     *
 484     * @see views_handler::options_validate()
 485     *
 486     * @return
 487     *   Empty array if the handler is valid; an array of error strings if it is not.
 488     */
 489    function validate() { return array(); }
 490  
 491    /**
 492     * Determine if the handler is considered 'broken', meaning it's a
 493     * a placeholder used when a handler can't be found.
 494     */
 495    function broken() { }
 496  }
 497  
 498  /**
 499   * This many to one helper object is used on both arguments and filters.
 500   *
 501   * @todo This requires extensive documentation on how this class is to
 502   * be used. For now, look at the arguments and filters that use it. Lots
 503   * of stuff is just pass-through but there are definitely some interesting
 504   * areas where they interact.
 505   *
 506   * Any handler that uses this can have the following possibly additional
 507   * definition terms:
 508   * - numeric: If true, treat this field as numeric, using %d instead of %s in
 509   *            queries.
 510   *
 511   */
 512  class views_many_to_one_helper {
 513    function views_many_to_one_helper(&$handler) {
 514      $this->handler = &$handler;
 515    }
 516  
 517    function option_definition(&$options) {
 518      $options['reduce_duplicates'] = array('default' => FALSE);
 519    }
 520  
 521    function options_form(&$form, &$form_state) {
 522      $form['reduce_duplicates'] = array(
 523        '#type' => 'checkbox',
 524        '#title' => t('Reduce duplicates'),
 525        '#description' => t('This filter can cause items that have more than one of the selected options to appear as duplicate results. If this filter causes duplicate results to occur, this checkbox can reduce those duplicates; however, the more terms it has to search for, the less performant the query will be, so use this with caution. Shouldn\'t be set on single-value fields, as it may cause values to disappear from display, if used on an incompatible field.'),
 526        '#default_value' => !empty($this->handler->options['reduce_duplicates']),
 527      );
 528    }
 529  
 530    /**
 531     * Sometimes the handler might want us to use some kind of formula, so give
 532     * it that option. If it wants us to do this, it must set $helper->formula = TRUE
 533     * and implement handler->get_formula();
 534     */
 535    function get_field() {
 536      if (!empty($this->formula)) {
 537        return $this->handler->get_formula();
 538      }
 539      else {
 540        return $this->handler->table_alias . '.' . $this->handler->real_field;
 541      }
 542    }
 543  
 544    /**
 545     * Add a table to the query.
 546     *
 547     * This is an advanced concept; not only does it add a new instance of the table,
 548     * but it follows the relationship path all the way down to the relationship
 549     * link point and adds *that* as a new relationship and then adds the table to
 550     * the relationship, if necessary.
 551     */
 552    function add_table($join = NULL, $alias = NULL) {
 553      // This is used for lookups in the many_to_one table.
 554      $field = $this->handler->table . '.' . $this->handler->field;
 555  
 556      if (empty($join)) {
 557        $join = $this->get_join();
 558      }
 559  
 560      // See if there's a chain between us and the base relationship. If so, we need
 561      // to create a new relationship to use.
 562      $relationship = $this->handler->relationship;
 563  
 564      // Determine the primary table to seek
 565      if (empty($this->handler->query->relationships[$relationship])) {
 566        $base_table = $this->handler->query->base_table;
 567      }
 568      else {
 569        $base_table = $this->handler->query->relationships[$relationship]['base'];
 570      }
 571  
 572      // Cycle through the joins. This isn't as error-safe as the normal
 573      // ensure_path logic. Perhaps it should be.
 574      $r_join = drupal_clone($join);
 575      while ($r_join->left_table != $base_table) {
 576        $r_join = views_get_table_join($r_join->left_table, $base_table);
 577      }
 578      // If we found that there are tables in between, add the relationship.
 579      if ($r_join->table != $join->table) {
 580        $relationship = $this->handler->query->add_relationship($this->handler->table . '_' . $r_join->table, $r_join, $r_join->table, $this->handler->relationship);
 581      }
 582  
 583      // And now add our table, using the new relationship if one was used.
 584      $alias = $this->handler->query->add_table($this->handler->table, $relationship, $join, $alias);
 585  
 586      // Store what values are used by this table chain so that other chains can
 587      // automatically discard those values.
 588      if (empty($this->handler->view->many_to_one_tables[$field])) {
 589        $this->handler->view->many_to_one_tables[$field] = $this->handler->value;
 590      }
 591      else {
 592        $this->handler->view->many_to_one_tables[$field] = array_merge($this->handler->view->many_to_one_tables[$field], $this->handler->value);
 593      }
 594  
 595      return $alias;
 596    }
 597  
 598    function get_join() {
 599      return $this->handler->get_join();
 600    }
 601  
 602    /**
 603     * Provide the proper join for summary queries. This is important in part because
 604     * it will cooperate with other arguments if possible.
 605     */
 606    function summary_join() {
 607      $field = $this->handler->table . '.' . $this->handler->field;
 608      $join = $this->get_join();
 609  
 610      // shortcuts
 611      $options = $this->handler->options;
 612      $view = &$this->handler->view;
 613      $query = &$this->handler->query;
 614  
 615      if (!empty($options['require_value'])) {
 616        $join->type = 'INNER';
 617      }
 618  
 619      if (empty($options['add_table']) || empty($view->many_to_one_tables[$field])) {
 620        return $query->ensure_table($this->handler->table, $this->handler->relationship, $join);
 621      }
 622      else {
 623        if (!empty($view->many_to_one_tables[$field])) {
 624          foreach ($view->many_to_one_tables[$field] as $value) {
 625            $join->extra = array(
 626              array(
 627                'field' => $this->handler->real_field,
 628                'operator' => '!=',
 629                'value' => $value,
 630                'numeric' => !empty($this->definition['numeric']),
 631              ),
 632            );
 633          }
 634        }
 635        return $this->add_table($join);
 636      }
 637    }
 638  
 639    /**
 640     * Override ensure_my_table so we can control how this joins in.
 641     * The operator actually has influence over joining.
 642     */
 643    function ensure_my_table() {
 644      if (!isset($this->handler->table_alias)) {
 645        // For 'or' if we're not reducing duplicates, we get the absolute simplest:
 646        $field = $this->handler->table . '.' . $this->handler->field;
 647        if ($this->handler->operator == 'or' && empty($this->handler->options['reduce_duplicates'])) {
 648          if (empty($this->handler->options['add_table']) && empty($this->handler->view->many_to_one_tables[$field])) {
 649            // query optimization, INNER joins are slightly faster, so use them
 650            // when we know we can.
 651            $join = $this->get_join();
 652            $join->type = 'INNER';
 653            $this->handler->table_alias = $this->handler->query->ensure_table($this->handler->table, $this->handler->relationship, $join);
 654            $this->handler->view->many_to_one_tables[$field] = $this->handler->value;
 655          }
 656          else {
 657            $join = $this->get_join();
 658            $join->type = 'LEFT';
 659            if (!empty($this->handler->view->many_to_one_tables[$field])) {
 660              foreach ($this->handler->view->many_to_one_tables[$field] as $value) {
 661                $join->extra = array(
 662                  array(
 663                    'field' => $this->handler->real_field,
 664                    'operator' => '!=',
 665                    'value' => $value,
 666                    'numeric' => !empty($this->handler->definition['numeric']),
 667                  ),
 668                );
 669              }
 670            }
 671  
 672            $this->handler->table_alias = $this->add_table($join);
 673          }
 674  
 675          return $this->handler->table_alias;
 676        }
 677  
 678        if ($this->handler->operator != 'not') {
 679          // If it's an and or an or, we do one join per selected value.
 680          // Clone the join for each table:
 681          $this->handler->table_aliases = array();
 682          foreach ($this->handler->value as $value) {
 683            $join = $this->get_join();
 684            if ($this->handler->operator == 'and') {
 685              $join->type = 'INNER';
 686            }
 687            $join->extra = array(
 688              array(
 689                'field' => $this->handler->real_field,
 690                'value' => $value,
 691                'numeric' => !empty($this->handler->definition['numeric']),
 692              ),
 693            );
 694  
 695            // The table alias needs to be unique to this value across the
 696            // multiple times the filter or argument is called by the view.
 697            if (!isset($this->handler->view->many_to_one_aliases[$field][$value])) {
 698              if (!isset($this->handler->view->many_to_one_count[$this->handler->table])) {
 699                $this->handler->view->many_to_one_count[$this->handler->table] = 0;
 700              }
 701              $this->handler->view->many_to_one_aliases[$field][$value] = $this->handler->table . '_value_' . ($this->handler->view->many_to_one_count[$this->handler->table]++);
 702            }
 703            $alias = $this->handler->table_aliases[$value] = $this->add_table($join, $this->handler->view->many_to_one_aliases[$field][$value]);
 704  
 705            // and set table_alias to the first of these.
 706            if (empty($this->handler->table_alias)) {
 707              $this->handler->table_alias = $alias;
 708            }
 709          }
 710        }
 711        else {
 712          // For not, we just do one join. We'll add a where clause during
 713          // the query phase to ensure that $table.$field IS NULL.
 714          $join = $this->get_join();
 715          $join->type = 'LEFT';
 716          $join->extra = array();
 717          $join->extra_type = 'OR';
 718          foreach ($this->handler->value as $value) {
 719            $join->extra[] = array(
 720              'field' => $this->handler->real_field,
 721              'value' => $value,
 722              'numeric' => !empty($this->handler->definition['numeric']),
 723            );
 724          }
 725  
 726          $this->handler->table_alias = $this->add_table($join);
 727        }
 728      }
 729      return $this->handler->table_alias;
 730    }
 731  
 732    function add_filter() {
 733      if (empty($this->handler->value)) {
 734        return;
 735      }
 736      $this->handler->ensure_my_table();
 737  
 738      // Shorten some variables:
 739      $field = $this->get_field();
 740      $options = $this->handler->options;
 741      $operator = $this->handler->operator;
 742      if (empty($options['group'])) {
 743        $options['group'] = 0;
 744      }
 745  
 746      $placeholder = !empty($this->handler->definition['numeric']) ? '%d' : "'%s'";
 747  
 748      if ($operator == 'not') {
 749        $this->handler->query->add_where($options['group'], "$field IS NULL");
 750      }
 751      else if ($operator == 'or' && empty($options['reduce_duplicates'])) {
 752        if (count($this->handler->value) > 1) {
 753          $replace = array_fill(0, sizeof($this->handler->value), $placeholder);
 754          $in = '(' . implode(", ", $replace) . ')';
 755          $this->handler->query->add_where($options['group'], "$field IN $in", $this->handler->value);
 756        }
 757        else {
 758          $this->handler->query->add_where($options['group'], "$field = $placeholder", $this->handler->value);
 759        }
 760      }
 761      else {
 762        $field = $this->handler->real_field;
 763        $clauses = array();
 764        foreach ($this->handler->table_aliases as $value => $alias) {
 765          $clauses[] = "$alias.$field = $placeholder";
 766        }
 767  
 768        $group = empty($options['group']) ? 0 : $options['group'];
 769  
 770        // implode on either AND or OR.
 771        $this->handler->query->add_where($group, implode(' ' . strtoupper($operator) . ' ', $clauses), $this->handler->value);
 772      }
 773    }
 774  }
 775  
 776  /*
 777   * Break x,y,z and x+y+z into an array. Numeric only.
 778   *
 779   * @param $str
 780   *   The string to parse.
 781   * @param $filter
 782   *   The filter object to use as a base.
 783   *
 784   * @return $filter
 785   *   The new filter object.
 786   */
 787  function views_break_phrase($str, &$filter) {
 788    if (!$filter) {
 789      $filter = new stdClass();
 790    }
 791  
 792    // Set up defaults:
 793    if (!isset($filter->value)) {
 794      $filter->value = array();
 795    }
 796  
 797    if (!isset($filter->operator)) {
 798      $filter->operator = 'or';
 799    }
 800  
 801    if ($str == '') {
 802      return $filter;
 803    }
 804  
 805    if (preg_match('/^([0-9]+[+ ])+[0-9]+$/', $str)) {
 806      // The '+' character in a query string may be parsed as ' '.
 807      $filter->operator = 'or';
 808      $filter->value = preg_split('/[+ ]/', $str);
 809    }
 810    else if (preg_match('/^([0-9]+,)*[0-9]+$/', $str)) {
 811      $filter->operator = 'and';
 812      $filter->value = explode(',', $str);
 813    }
 814  
 815    // Keep an 'error' value if invalid strings were given.
 816    if (!empty($str) && (empty($filter->value) || !is_array($filter->value))) {
 817      $filter->value = array(-1);
 818      return $filter;
 819    }
 820  
 821    // Doubly ensure that all values are numeric only.
 822    foreach ($filter->value as $id => $value) {
 823      $filter->value[$id] = intval($value);
 824    }
 825  
 826    return $filter;
 827  }
 828  
 829  // --------------------------------------------------------------------------
 830  // Date helper functions
 831  
 832  /**
 833   * Figure out what timezone we're in; needed for some date manipulations.
 834   */
 835  function views_get_timezone() {
 836    global $user;
 837    if (variable_get('configurable_timezones', 1) && $user->uid && strlen($user->timezone)) {
 838      $timezone = $user->timezone;
 839    }
 840    else {
 841      $timezone = variable_get('date_default_timezone', 0);
 842    }
 843  
 844    // set up the database timezone
 845    if (in_array($GLOBALS['db_type'], array('mysql', 'mysqli', 'pgsql'))) {
 846      $offset = '+00:00';
 847      static $already_set = false;
 848      if (!$already_set) {
 849        if ($GLOBALS['db_type'] == 'pgsql') {
 850          db_query("SET TIME ZONE INTERVAL '$offset' HOUR TO MINUTE");
 851        }
 852        elseif ($GLOBALS['db_type'] == 'mysqli') {
 853          db_query("SET @@session.time_zone = '$offset'");
 854        }
 855        elseif ($GLOBALS['db_type'] == 'mysql' && version_compare(db_version(), '4.1.3', '>=')) {
 856          db_query("SET @@session.time_zone = '$offset'");
 857        }
 858  
 859        $already_set = true;
 860      }
 861    }
 862  
 863    return $timezone;
 864  }
 865  
 866  /**
 867   * Helper function to create cross-database SQL dates.
 868   *
 869   * @param $field
 870   *   The real table and field name, like 'tablename.fieldname'.
 871   * @param $field_type
 872   *  The type of date field, 'int' or 'datetime'.
 873   * @param $set_offset
 874   *   The name of a field that holds the timezone offset or a fixed timezone
 875   *   offset value. If not provided, the normal Drupal timezone handling
 876   *   will be used, i.e. $set_offset = 0 will make no timezone adjustment.
 877   * @return
 878   *   An appropriate SQL string for the db type and field type.
 879   */
 880  function views_date_sql_field($field, $field_type = 'int', $set_offset = NULL) {
 881    $db_type = $GLOBALS['db_type'];
 882    $offset = $set_offset !== NULL ? $set_offset : views_get_timezone();
 883    switch ($db_type) {
 884      case 'mysql':
 885      case 'mysqli':
 886        switch ($field_type) {
 887          case 'int':
 888            $field = "FROM_UNIXTIME($field)";
 889            break;
 890          case 'datetime':
 891            break;
 892        }
 893        if (!empty($offset)) {
 894          $field = "($field + INTERVAL $offset SECOND)";
 895        }
 896        return $field;
 897      case 'pgsql':
 898        switch ($field_type) {
 899          case 'int':
 900            $field = "$field::ABSTIME";
 901            break;
 902          case 'datetime':
 903            break;
 904        }
 905        if (!empty($offset)) {
 906          $field = "($field + INTERVAL '$offset SECONDS')";
 907        }
 908        return $field;
 909    }
 910  }
 911  
 912  /**
 913   * Helper function to create cross-database SQL date formatting.
 914   *
 915   * @param $format
 916   *   A format string for the result, like 'Y-m-d H:i:s'.
 917   * @param $field
 918   *   The real table and field name, like 'tablename.fieldname'.
 919   * @param $field_type
 920   *   The type of date field, 'int' or 'datetime'.
 921   * @param $set_offset
 922   *   The name of a field that holds the timezone offset or a fixed timezone
 923   *   offset value. If not provided, the normal Drupal timezone handling
 924   *   will be used, i.e. $set_offset = 0 will make no timezone adjustment.
 925   * @return
 926   *   An appropriate SQL string for the db type and field type.
 927   */
 928  function views_date_sql_format($format, $field, $field_type = 'int', $set_offset = NULL) {
 929    $db_type = $GLOBALS['db_type'];
 930    $field = views_date_sql_field($field, $field_type, $set_offset);
 931    switch ($db_type) {
 932      case 'mysql':
 933      case 'mysqli':
 934        $replace = array(
 935          'Y' => '%Y',
 936          'y' => '%y',
 937          'M' => '%%b',
 938          'm' => '%m',
 939          'n' => '%c',
 940          'F' => '%M',
 941          'D' => '%a',
 942          'd' => '%%d',
 943          'l' => '%W',
 944          'j' => '%e',
 945          'W' => '%v',
 946          'H' => '%H',
 947          'h' => '%h',
 948          'i' => '%i',
 949          's' => '%%s',
 950          'A' => '%p',
 951          );
 952        $format = strtr($format, $replace);
 953        return "DATE_FORMAT($field, '$format')";
 954      case 'pgsql':
 955        $replace = array(
 956          'Y' => 'YYYY',
 957          'y' => 'YY',
 958          'M' => 'Mon',
 959          'm' => 'MM',
 960          'n' => 'MM', // no format for Numeric representation of a month, without leading zeros
 961          'F' => 'Month',
 962          'D' => 'Dy',
 963          'd' => 'DD',
 964          'l' => 'Day',
 965          'j' => 'DD', // no format for Day of the month without leading zeros
 966          'W' => 'WW',
 967          'H' => 'HH24',
 968          'h' => 'HH12',
 969          'i' => 'MI',
 970          's' => 'SS',
 971          'A' => 'AM',
 972          );
 973        $format = strtr($format, $replace);
 974        return "TO_CHAR($field, '$format')";
 975    }
 976  }
 977  
 978  /**
 979   * Helper function to create cross-database SQL date extraction.
 980   *
 981   * @param $extract_type
 982   *   The type of value to extract from the date, like 'MONTH'.
 983   * @param $field
 984   *   The real table and field name, like 'tablename.fieldname'.
 985   * @param $field_type
 986   *   The type of date field, 'int' or 'datetime'.
 987   * @param $set_offset
 988   *   The name of a field that holds the timezone offset or a fixed timezone
 989   *   offset value. If not provided, the normal Drupal timezone handling
 990   *   will be used, i.e. $set_offset = 0 will make no timezone adjustment.
 991   * @return
 992   *   An appropriate SQL string for the db type and field type.
 993   */
 994  function views_date_sql_extract($extract_type, $field, $field_type = 'int', $set_offset = NULL) {
 995    $db_type = $GLOBALS['db_type'];
 996    $field = views_date_sql_field($field, $field_type, $set_offset);
 997  
 998    // Note there is no space after FROM to avoid db_rewrite problems
 999    // see http://drupal.org/node/79904.
1000    switch ($extract_type) {
1001    case('DATE'):
1002      return $field;
1003    case('YEAR'):
1004      return "EXTRACT(YEAR FROM($field))";
1005    case('MONTH'):
1006      return "EXTRACT(MONTH FROM($field))";
1007    case('DAY'):
1008      return "EXTRACT(DAY FROM($field))";
1009    case('HOUR'):
1010      return "EXTRACT(HOUR FROM($field))";
1011    case('MINUTE'):
1012      return "EXTRACT(MINUTE FROM($field))";
1013    case('SECOND'):
1014      return "EXTRACT(SECOND FROM($field))";
1015    case('WEEK'):  // ISO week number for date
1016      switch ($db_type) {
1017        case('mysql'):
1018        case('mysqli'):
1019          // WEEK using arg 3 in mysql should return the same value as postgres EXTRACT
1020          return "WEEK($field, 3)";
1021        case('pgsql'):
1022          return "EXTRACT(WEEK FROM($field))";
1023      }
1024    case('DOW'):
1025      switch ($db_type) {
1026        case('mysql'):
1027        case('mysqli'):
1028          // mysql returns 1 for Sunday through 7 for Saturday
1029          // php date functions and postgres use 0 for Sunday and 6 for Saturday
1030          return "INTEGER(DAYOFWEEK($field) - 1)";
1031        case('pgsql'):
1032          return "EXTRACT(DOW FROM($field))";
1033      }
1034    case('DOY'):
1035      switch ($db_type) {
1036        case('mysql'):
1037        case('mysqli'):
1038          return "DAYOFYEAR($field)";
1039        case('pgsql'):
1040          return "EXTRACT(DOY FROM($field))";
1041      }
1042    }
1043  }
1044  
1045  /**
1046   * Implementation of hook_views_handlers() to register all of the basic handlers
1047   * views uses.
1048   */
1049  function views_views_handlers() {
1050    return array(
1051      'info' => array(
1052        'path' => drupal_get_path('module', 'views') . '/handlers',
1053      ),
1054      'handlers' => array(
1055        // argument handlers
1056        'views_handler_argument' => array(
1057          'parent' => 'views_handler',
1058        ),
1059        'views_handler_argument_numeric' => array(
1060          'parent' => 'views_handler_argument',
1061        ),
1062        'views_handler_argument_formula' => array(
1063          'parent' => 'views_handler_argument',
1064        ),
1065        'views_handler_argument_date' => array(
1066          'parent' => 'views_handler_argument_formula',
1067        ),
1068        'views_handler_argument_string' => array(
1069          'parent' => 'views_handler_argument',
1070        ),
1071        'views_handler_argument_many_to_one' => array(
1072          'parent' => 'views_handler_argument',
1073        ),
1074        'views_handler_argument_null' => array(
1075          'parent' => 'views_handler_argument',
1076        ),
1077        'views_handler_argument_broken' => array(
1078          'parent' => 'views_handler_argument',
1079        ),
1080  
1081        // field handlers
1082        'views_handler_field' => array(
1083          'parent' => 'views_handler',
1084        ),
1085        'views_handler_field_date' => array(
1086          'parent' => 'views_handler_field',
1087        ),
1088        'views_handler_field_boolean' => array(
1089          'parent' => 'views_handler_field',
1090        ),
1091        'views_handler_field_markup' => array(
1092          'parent' => 'views_handler_field',
1093        ),
1094        'views_handler_field_xss' => array(
1095          'parent' => 'views_handler_field',
1096          'file' => 'views_handler_field.inc',
1097        ),
1098        'views_handler_field_url' => array(
1099          'parent' => 'views_handler_field',
1100        ),
1101        'views_handler_field_file_size' => array(
1102          'parent' => 'views_handler_field',
1103          'file' => 'views_handler_field.inc',
1104        ),
1105        'views_handler_field_prerender_list' => array(
1106          'parent' => 'views_handler_field',
1107        ),
1108        'views_handler_field_numeric' => array(
1109          'parent' => 'views_handler_field',
1110        ),
1111        'views_handler_field_custom' => array(
1112          'parent' => 'views_handler_field',
1113        ),
1114        'views_handler_field_counter' => array(
1115          'parent' => 'views_handler_field',
1116        ),
1117        'views_handler_field_math' => array(
1118          'parent' => 'views_handler_field_numeric',
1119        ),
1120        'views_handler_field_broken' => array(
1121          'parent' => 'views_handler_field',
1122        ),
1123  
1124        // filter handlers
1125        'views_handler_filter' => array(
1126          'parent' => 'views_handler',
1127        ),
1128        'views_handler_filter_equality' => array(
1129          'parent' => 'views_handler_filter',
1130        ),
1131        'views_handler_filter_string' => array(
1132          'parent' => 'views_handler_filter',
1133        ),
1134        'views_handler_filter_boolean_operator' => array(
1135          'parent' => 'views_handler_filter',
1136        ),
1137        'views_handler_filter_boolean_operator_string' => array(
1138          'parent' => 'views_handler_filter_boolean_operator',
1139        ),
1140        'views_handler_filter_in_operator' => array(
1141          'parent' => 'views_handler_filter',
1142        ),
1143        'views_handler_filter_numeric' => array(
1144          'parent' => 'views_handler_filter',
1145        ),
1146        'views_handler_filter_float' => array(
1147          'parent' => 'views_handler_filter_numeric',
1148        ),
1149        'views_handler_filter_date' => array(
1150          'parent' => 'views_handler_filter_numeric',
1151        ),
1152        'views_handler_filter_many_to_one' => array(
1153          'parent' => 'views_handler_filter_in_operator',
1154        ),
1155        'views_handler_filter_broken' => array(
1156          'parent' => 'views_handler_filter',
1157        ),
1158  
1159        // relationship handlers
1160        'views_handler_relationship' => array(
1161          'parent' => 'views_handler',
1162        ),
1163        'views_handler_relationship_broken' => array(
1164          'parent' => 'views_handler_relationship',
1165        ),
1166  
1167  
1168        // sort handlers
1169        'views_handler_sort' => array(
1170          'parent' => 'views_handler',
1171        ),
1172        'views_handler_sort_formula' => array(
1173          'parent' => 'views_handler_sort',
1174        ),
1175        'views_handler_sort_date' => array(
1176          'parent' => 'views_handler_sort',
1177        ),
1178        'views_handler_sort_menu_hierarchy' => array(
1179          'parent' => 'views_handler_sort',
1180        ),
1181        'views_handler_sort_random' => array(
1182          'parent' => 'views_handler_sort',
1183        ),
1184        'views_handler_sort_broken' => array(
1185          'parent' => 'views_handler_sort',
1186        ),
1187      ),
1188    );
1189  }
1190  
1191  
1192  /**
1193   * @}
1194   */
1195  
1196  /**
1197   * @defgroup views_join_handlers Views' join handlers
1198   * @{
1199   * Handlers to tell Views how to join tables together.
1200  
1201   * Here is how you do complex joins:
1202   *
1203   * @code
1204   * class views_join_complex extends views_join {
1205   *   // PHP 4 doesn't call constructors of the base class automatically from a
1206   *   // constructor of a derived class. It is your responsibility to propagate
1207   *   // the call to constructors upstream where appropriate.
1208   *   function construct($table = NULL, $left_table = NULL, $left_field = NULL, $field = NULL, $extra = array(), $type = 'LEFT') {
1209   *     parent::construct($table, $left_table, $left_field, $field, $extra, $type);
1210   *   }
1211   *
1212   *   function join($table, &$query) {
1213   *     $output = parent::join($table, $query);
1214   *     $output .= "AND foo.bar = baz.boing";
1215   *     return $output;
1216   *   }
1217   * }
1218   * @endcode
1219   */
1220  /**
1221   * A function class to represent a join and create the SQL necessary
1222   * to implement the join.
1223   *
1224   * This is the Delegation pattern. If we had PHP5 exclusively, we would
1225   * declare this an interface.
1226   *
1227   * Extensions of this class can be used to create more interesting joins.
1228   *
1229   * join definition
1230   *   - table: table to join (right table)
1231   *   - field: field to join on (right field)
1232   *   - left_table: The table we join to
1233   *   - left_field: The field we join to
1234   *   - type: either LEFT (default) or INNER
1235   *   - extra: Either a string that's directly added, or an array of items:
1236   *   - - table: if not set, current table; if NULL, no table. This field can't
1237   *       be set in the cached definition because it can't know aliases; this field
1238   *       can only be used by realtime joins.
1239   *   - - field: Field or formula
1240   *   - - operator: defaults to =
1241   *   - - value: Must be set. If an array, operator will be defaulted to IN.
1242   *   - - numeric: If true, the value will not be surrounded in quotes.
1243   *   - extra type: How all the extras will be combined. Either AND or OR. Defaults to AND.
1244   */
1245  class views_join {
1246    /**
1247     * Construct the views_join object.
1248     */
1249    function construct($table = NULL, $left_table = NULL, $left_field = NULL, $field = NULL, $extra = array(), $type = 'LEFT') {
1250      $this->extra_type = 'AND';
1251      if (!empty($table)) {
1252        $this->table = $table;
1253        $this->left_table = $left_table;
1254        $this->left_field = $left_field;
1255        $this->field = $field;
1256        $this->extra = $extra;
1257        $this->type = strtoupper($type);
1258      }
1259      else if (!empty($this->definition)) {
1260        // if no arguments, construct from definition.
1261        // These four must exist or it will throw notices.
1262        $this->table = $this->definition['table'];
1263        $this->left_table = $this->definition['left_table'];
1264        $this->left_field = $this->definition['left_field'];
1265        $this->field = $this->definition['field'];
1266        if (!empty($this->definition['extra'])) {
1267          $this->extra = $this->definition['extra'];
1268        }
1269        if (!empty($this->definition['extra type'])) {
1270          $this->extra_type = strtoupper($this->definition['extra type']);
1271        }
1272  
1273        $this->type = !empty($this->definition['type']) ? strtoupper($this->definition['type']) : 'LEFT';
1274      }
1275    }
1276  
1277    /**
1278     * Build the SQL for the join this object represents.
1279     */
1280    function join($table, &$query) {
1281      if (empty($this->definition['table formula'])) {
1282        $right_table = "{" . $this->table . "}";
1283      }
1284      else {
1285        $right_table = $this->definition['table formula'];
1286      }
1287  
1288      if ($this->left_table) {
1289        $left = $query->get_table_info($this->left_table);
1290        $left_field = "$left[alias].$this->left_field";
1291      }
1292      else {
1293        // This can be used if left_field is a formula or something. It should be used only *very* rarely.
1294        $left_field = $this->left_field;
1295      }
1296  
1297      $output = " $this->type JOIN $right_table $table[alias] ON $left_field = $table[alias].$this->field";
1298  
1299      // Load query tokens replacements.
1300      $view = views_get_current_view();
1301      $replacements = array();
1302      if (!empty($view)) {
1303        $replacements = $view->substitutions();
1304      }
1305      else {
1306        vpr('The current view is not set, maybe some code missed to execute $view->pre_execute()');
1307      }
1308  
1309      // Tack on the extra.
1310      if (isset($this->extra)) {
1311        if (is_array($this->extra)) {
1312          $extras = array();
1313          foreach ($this->extra as $info) {
1314            $extra = '';
1315            // Figure out the table name. Remember, only use aliases provided
1316            // if at all possible.
1317            $join_table = '';
1318            if (!array_key_exists('table', $info)) {
1319              $join_table = $table['alias'] . '.';
1320            }
1321            elseif (isset($info['table'])) {
1322              $join_table = $info['table'] . '.';
1323            }
1324  
1325            // Apply query token replacements.
1326            $info['value'] = str_replace(array_keys($replacements), $replacements, $info['value']);
1327  
1328            // And now deal with the value and the operator.  Set $q to
1329            // a single-quote for non-numeric values and the
1330            // empty-string for numeric values, then wrap all values in $q.
1331            $raw_value = $this->db_safe($info['value'], $info);
1332            $q = (empty($info['numeric']) ? "'" : '');
1333  
1334            if (is_array($raw_value)) {
1335              $operator = !empty($info['operator']) ? $info['operator'] : 'IN';
1336              // Transform from IN() notation to = notation if just one value.
1337              if (count($raw_value) == 1) {
1338                $value = $q . array_shift($raw_value) . $q;
1339                $operator = $operator == 'NOT IN' ? '!=' : '=';
1340              }
1341              else {
1342                $value = "($q" . implode("$q, $q", $raw_value) . "$q)";
1343              }
1344            }
1345            else {
1346              $operator = !empty($info['operator']) ? $info['operator'] : '=';
1347              $value = "$q$raw_value$q";
1348            }
1349            $extras[] = "$join_table$info[field] $operator $value";
1350          }
1351  
1352          if ($extras) {
1353            if (count($extras) == 1) {
1354              $output .= ' AND ' . array_shift($extras);
1355            }
1356            else {
1357              $output .= ' AND (' . implode(' ' . $this->extra_type . ' ', $extras) . ')';
1358            }
1359          }
1360        }
1361        else if ($this->extra && is_string($this->extra)) {
1362          $output .= " AND ($this->extra)";
1363        }
1364      }
1365      return $output;
1366    }
1367  
1368    /**
1369     * Ensure that input is db safe. We only check strings and ints tho
1370     * so something that needs floats in their joins needs to do their
1371     * own type checking.
1372     */
1373    function db_safe($input, $info) {
1374      if (is_array($input)) {
1375        $output = array();
1376        foreach ($input as $value) {
1377          if (empty($info['numeric'])) {
1378            $output[] = db_escape_string($value);
1379          }
1380          else {
1381            $output[] = intval($value);
1382          }
1383        }
1384      }
1385      else if (empty($info['numeric'])) {
1386        $output = db_escape_string($input);
1387      }
1388      else {
1389        $output = intval($input);
1390      }
1391  
1392      return $output;
1393    }
1394  }
1395  
1396  /**
1397   * @}
1398   */
1399  
1400  // Declare API compatibility on behalf of core modules:
1401  
1402  /**
1403   * Implementation of hook_views_api().
1404   *
1405   * This one is used as the base to reduce errors when updating.
1406   */
1407  function views_views_api() {
1408    return array(
1409      'api' => 2,
1410      'path' => drupal_get_path('module', 'views') . '/modules',
1411    );
1412  }
1413  
1414  if (!function_exists('aggregator_views_api')) {
1415    function aggregator_views_api() { return views_views_api(); }
1416  }
1417  
1418  if (!function_exists('book_views_api')) {
1419    function book_views_api() { return views_views_api(); }
1420  }
1421  
1422  if (!function_exists('comment_views_api')) {
1423    function comment_views_api() { return views_views_api(); }
1424  }
1425  
1426  if (!function_exists('locale_views_api')) {
1427    function locale_views_api() { return views_views_api(); }
1428  }
1429  
1430  if (!function_exists('filter_views_api')) {
1431    function filter_views_api() { return views_views_api(); }
1432  }
1433  
1434  if (!function_exists('node_views_api')) {
1435    function node_views_api() { return views_views_api(); }
1436  }
1437  
1438  if (!function_exists('poll_views_api')) {
1439    function poll_views_api() { return views_views_api(); }
1440  }
1441  
1442  if (!function_exists('profile_views_api')) {
1443    function profile_views_api() { return views_views_api(); }
1444  }
1445  
1446  if (!function_exists('search_views_api')) {
1447    function search_views_api() { return views_views_api(); }
1448  }
1449  
1450  if (!function_exists('statistics_views_api')) {
1451    function statistics_views_api() { return views_views_api(); }
1452  }
1453  
1454  if (!function_exists('system_views_api')) {
1455    function system_views_api() { return views_views_api(); }
1456  }
1457  
1458  if (!function_exists('taxonomy_views_api')) {
1459    function taxonomy_views_api() { return views_views_api(); }
1460  }
1461  
1462  if (!function_exists('translation_views_api')) {
1463    function translation_views_api() { return views_views_api(); }
1464  }
1465  
1466  if (!function_exists('upload_views_api')) {
1467    function upload_views_api() { return views_views_api(); }
1468  }
1469  
1470  if (!function_exists('user_views_api')) {
1471    function user_views_api() { return views_views_api(); }
1472  }
1473  
1474  if (!function_exists('contact_views_api')) {
1475    function contact_views_api() { return views_views_api(); }
1476  }


Generated: Mon Jul 9 18:01:44 2012 Cross-referenced by PHPXref 0.7