| [ Index ] |
PHP Cross Reference of Drupal 6 (gatewave) |
[Summary view] [Print] [Text view]
1 <?php 2 // $Id: views_handler_argument.inc,v 1.9.2.2 2010/03/12 21:25:33 merlinofchaos Exp $ 3 4 /** 5 * @defgroup views_argument_handlers Handlers for arguments 6 * @{ 7 */ 8 9 /** 10 * Base class for arguments. 11 * 12 * The basic argument works for very simple arguments such as nid and uid 13 * 14 * Definition terms for this handler: 15 * - name field: The field to use for the name to use in the summary, which is 16 * the displayed output. For example, for the node: nid argument, 17 * the argument itself is the nid, but node.title is displayed. 18 * - name table: The table to use for the name, should it not be in the same 19 * table as the argument. 20 * - empty field name: For arguments that can have no value, such as taxonomy 21 * which can have "no term", this is the string which 22 * will be displayed for this lack of value. Be sure to use 23 * t(). 24 * - validate type: A little used string to allow an argument to restrict 25 * which validator is available to just one. Use the 26 * validator ID. This probably should not be used at all, 27 * and may disappear or change. 28 * - numeric: If set to TRUE this field is numeric and will use %d instead of 29 * %s in queries. 30 * 31 * @ingroup views_argument_handlers 32 */ 33 class views_handler_argument extends views_handler { 34 var $name_field = NULL; 35 /** 36 * Constructor 37 */ 38 function construct() { 39 parent::construct(); 40 41 if (!empty($this->definition['name field'])) { 42 $this->name_field = $this->definition['name field']; 43 } 44 if (!empty($this->definition['name table'])) { 45 $this->name_table = $this->definition['name table']; 46 } 47 } 48 49 function init(&$view, &$options) { 50 parent::init($view, $options); 51 } 52 53 /** 54 * Give an argument the opportunity to modify the breadcrumb, if it wants. 55 * This only gets called on displays where a breadcrumb is actually used. 56 * 57 * The breadcrumb will be in the form of an array, with the keys being 58 * the path and the value being the already sanitized title of the path. 59 */ 60 function set_breadcrumb(&$breadcrumb) { } 61 62 /** 63 * Determine if the argument can generate a breadcrumb 64 * 65 * @return TRUE/FALSE 66 */ 67 function uses_breadcrumb() { 68 $info = $this->default_actions($this->options['default_action']); 69 return !empty($info['breadcrumb']); 70 } 71 72 function is_wildcard($arg = NULL) { 73 if (!isset($arg)) { 74 $arg = $this->argument; 75 } 76 77 return !empty($this->options['wildcard']) && $this->options['wildcard'] === $arg; 78 } 79 80 function wildcard_title() { 81 return $this->options['wildcard_substitution']; 82 } 83 84 /** 85 * Determine if the argument needs a style plugin. 86 * 87 * @return TRUE/FALSE 88 */ 89 function needs_style_plugin() { 90 $info = $this->default_actions($this->options['default_action']); 91 $validate_info = $this->default_actions($this->options['validate_fail']); 92 return !empty($info['style plugin']) || !empty($validate_info['style plugin']); 93 } 94 95 function option_definition() { 96 $options = parent::option_definition(); 97 98 $options['default_action'] = array('default' => 'ignore'); 99 $options['style_plugin'] = array('default' => 'default_summary'); 100 $options['style_options'] = array('default' => array()); 101 $options['wildcard'] = array('default' => 'all'); 102 $options['wildcard_substitution'] = array('default' => t('All'), 'translatable' => TRUE); 103 $options['title'] = array('default' => '', 'translatable' => TRUE); 104 $options['breadcrumb'] = array('default' => '', 'translatable' => TRUE); 105 $options['default_argument_type'] = array('default' => 'fixed'); 106 $options['default_argument'] = array('default' => ''); 107 $options['validate_type'] = array('default' => 'none'); 108 $options['validate_fail'] = array('default' => 'not found'); 109 110 return $options; 111 } 112 113 function options_form(&$form, &$form_state) { 114 $defaults = $this->default_actions(); 115 116 $form['title'] = array( 117 '#prefix' => '<div class="clear-block">', 118 '#suffix' => '</div>', 119 '#type' => 'textfield', 120 '#title' => t('Title'), 121 '#default_value' => $this->options['title'], 122 '#description' => t('The title to use when this argument is present. It will override the title of the view and titles from previous arguments. You can use percent substitution here to replace with argument titles. Use "%1" for the first argument, "%2" for the second, etc.'), 123 ); 124 125 $form['breadcrumb'] = array( 126 '#prefix' => '<div class="clear-block">', 127 '#suffix' => '</div>', 128 '#type' => 'textfield', 129 '#title' => t('Breadcrumb'), 130 '#default_value' => $this->options['breadcrumb'], 131 '#description' => t('The Breadcrumb title to use when this argument is present. If no breadcrumb is set here, default Title values will be used, see "Title" for percent substitutions.'), 132 ); 133 134 $form['clear_start'] = array( 135 '#value' => '<div class="clear-block">', 136 ); 137 138 $form['defaults_start'] = array( 139 '#value' => '<div class="views-left-50">', 140 ); 141 142 $form['default_action'] = array( 143 '#type' => 'radios', 144 '#title' => t('Action to take if argument is not present'), 145 '#default_value' => $this->options['default_action'], 146 ); 147 148 $form['defaults_stop'] = array( 149 '#value' => '</div>', 150 ); 151 152 $form['wildcard'] = array( 153 '#prefix' => '<div class="views-right-50">', 154 // prefix and no suffix means these two items will be grouped together. 155 '#type' => 'textfield', 156 '#title' => t('Wildcard'), 157 '#size' => 20, 158 '#default_value' => $this->options['wildcard'], 159 '#description' => t('If this value is received as an argument, the argument will be ignored; i.e, "all values"'), 160 ); 161 162 $form['wildcard_substitution'] = array( 163 '#suffix' => '</div>', 164 '#type' => 'textfield', 165 '#title' => t('Wildcard title'), 166 '#size' => 20, 167 '#default_value' => $this->options['wildcard_substitution'], 168 '#description' => t('The title to use for the wildcard in substitutions elsewhere.'), 169 ); 170 171 $form['clear_stop'] = array( 172 '#value' => '</div>', 173 ); 174 175 $options = array(); 176 $validate_options = array(); 177 foreach ($defaults as $id => $info) { 178 $options[$id] = $info['title']; 179 if (empty($info['default only'])) { 180 $validate_options[$id] = $info['title']; 181 } 182 if (!empty($info['form method'])) { 183 $this->{$info['form method']}($form, $form_state); 184 } 185 } 186 187 $form['default_action']['#options'] = $options; 188 189 $form['validate_options_div_prefix'] = array( 190 '#id' => 'views-validator-options', 191 '#value' => '<fieldset id="views-validator-options"><legend>' . t('Validator options') . '</legend>', 192 ); 193 194 $form['validate_type'] = array( 195 '#type' => 'select', 196 '#title' => t('Validator'), 197 '#default_value' => $this->options['validate_type'], 198 ); 199 200 $validate_types = array('none' => t('<Basic validation>')); 201 $plugins = views_fetch_plugin_data('argument validator'); 202 foreach ($plugins as $id => $info) { 203 if (!empty($info['no ui'])) { 204 continue; 205 } 206 207 $valid = TRUE; 208 if (!empty($info['type'])) { 209 $valid = FALSE; 210 if (empty($this->definition['validate type'])) { 211 continue; 212 } 213 foreach ((array) $info['type'] as $type) { 214 if ($type == $this->definition['validate type']) { 215 $valid = TRUE; 216 break; 217 } 218 } 219 } 220 221 // If we decide this validator is ok, add it to the list. 222 if ($valid) { 223 $plugin = views_get_plugin('argument validator', $id); 224 if ($plugin) { 225 $plugin->init($this->view, $this, $id); 226 if ($plugin->access() || $this->options['validate_type'] == $id) { 227 $plugin->validate_form($form, $form_state, $id); 228 $validate_types[$id] = $info['title']; 229 } 230 } 231 } 232 } 233 234 asort($validate_types); 235 $form['validate_type']['#options'] = $validate_types; 236 237 $form['validate_fail'] = array( 238 '#type' => 'select', 239 '#title' => t('Action to take if argument does not validate'), 240 '#default_value' => $this->options['validate_fail'], 241 '#options' => $validate_options, 242 ); 243 244 $form['validate_options_div_suffix'] = array( 245 '#value' => '</fieldset>', 246 ); 247 } 248 249 /** 250 * Provide a list of default behaviors for this argument if the argument 251 * is not present. 252 * 253 * Override this method to provide additional (or fewer) default behaviors. 254 */ 255 function default_actions($which = NULL) { 256 $defaults = array( 257 'ignore' => array( 258 'title' => t('Display all values'), 259 'method' => 'default_ignore', 260 'breadcrumb' => TRUE, // generate a breadcrumb to here 261 ), 262 'not found' => array( 263 'title' => t('Hide view / Page not found (404)'), 264 'method' => 'default_not_found', 265 'hard fail' => TRUE, // This is a hard fail condition 266 ), 267 'empty' => array( 268 'title' => t('Display empty text'), 269 'method' => 'default_empty', 270 'breadcrumb' => TRUE, // generate a breadcrumb to here 271 ), 272 'summary asc' => array( 273 'title' => t('Summary, sorted ascending'), 274 'method' => 'default_summary', 275 'method args' => array('asc'), 276 'style plugin' => TRUE, 277 'breadcrumb' => TRUE, // generate a breadcrumb to here 278 ), 279 'summary desc' => array( 280 'title' => t('Summary, sorted descending'), 281 'method' => 'default_summary', 282 'method args' => array('desc'), 283 'style plugin' => TRUE, 284 'breadcrumb' => TRUE, // generate a breadcrumb to here 285 ), 286 'default' => array( 287 'title' => t('Provide default argument'), 288 'method' => 'default_default', 289 'form method' => 'default_argument_form', 290 'has default argument' => TRUE, 291 'default only' => TRUE, // this can only be used for missing argument, not validation failure 292 ), 293 ); 294 295 if ($which) { 296 if (!empty($defaults[$which])) { 297 return $defaults[$which]; 298 } 299 } 300 else { 301 return $defaults; 302 } 303 } 304 305 /** 306 * Provide a form for selecting the default argument when the 307 * default action is set to provide default argument. 308 */ 309 function default_argument_form(&$form, &$form_state) { 310 $plugins = views_fetch_plugin_data('argument default'); 311 $options = array(); 312 313 // This construct uses 'hidden' and not markup because process doesn't 314 // run. It also has an extra div because the dependency wants to hide 315 // the parent in situations like this, so we need a second div to 316 // make this work. 317 $form['default_options_div_prefix'] = array( 318 '#type' => 'hidden', 319 '#id' => 'views-default-options', 320 '#prefix' => '<div><fieldset id="views-default-options"><legend>' . t('Provide default argument options') . '</legend>', 321 '#process' => array('views_process_dependency'), 322 '#dependency' => array('radio:options[default_action]' => array('default')), 323 ); 324 325 $form['default_argument_type'] = array( 326 '#prefix' => '<div id="edit-options-default-argument-type-wrapper">', 327 '#suffix' => '</div>', 328 '#type' => 'radios', 329 '#id' => 'edit-options-default-argument-type', 330 '#title' => t('Default argument type'), 331 '#default_value' => $this->options['default_argument_type'], 332 '#process' => array('expand_radios', 'views_process_dependency'), 333 '#dependency' => array('radio:options[default_action]' => array('default')), 334 ); 335 336 foreach ($plugins as $id => $info) { 337 $plugin = views_get_plugin('argument default', $id); 338 if ($plugin) { 339 $plugin->init($this->view, $this, $id); 340 341 if ($plugin->access() || $this->options['default_argument_type'] == $id) { 342 $options[$id] = $info['title']; 343 $plugin->argument_form($form, $form_state); 344 } 345 } 346 } 347 348 $form['default_options_div_suffix'] = array( 349 '#value' => '</fieldset></div>', 350 ); 351 352 asort($options); 353 $form['default_argument_type']['#options'] = $options; 354 } 355 356 /** 357 * Handle the default action, which means our argument wasn't present. 358 * 359 * Override this method only with extreme care. 360 * 361 * @return 362 * A boolean value; if TRUE, continue building this view. If FALSE, 363 * building the view will be aborted here. 364 */ 365 function default_action($info = NULL) { 366 if (!isset($info)) { 367 $info = $this->default_actions($this->options['default_action']); 368 } 369 370 if (!$info) { 371 return FALSE; 372 } 373 374 if (!empty($info['method args'])) { 375 return call_user_func_array(array(&$this, $info['method']), $info['method args']); 376 } 377 else { 378 return $this->{$info['method']}(); 379 } 380 } 381 382 /** 383 * How to act if validation failes 384 */ 385 function validate_fail() { 386 $info = $this->default_actions($this->options['validate_fail']); 387 return $this->default_action($info); 388 } 389 /** 390 * Default action: ignore. 391 * 392 * If an argument was expected and was not given, in this case, simply 393 * ignore the argument entirely. 394 */ 395 function default_ignore() { 396 return TRUE; 397 } 398 399 /** 400 * Default action: not found. 401 * 402 * If an argument was expected and was not given, in this case, report 403 * the view as 'not found' or hide it. 404 */ 405 function default_not_found() { 406 // Set a failure condition and let the display manager handle it. 407 $this->view->build_info['fail'] = TRUE; 408 return FALSE; 409 } 410 411 /** 412 * Default action: empty 413 * 414 * If an argument was expected and was not given, in this case, display 415 * the view's empty text 416 */ 417 function default_empty() { 418 // We return with no query; this will force the empty text. 419 $this->view->built = TRUE; 420 $this->view->executed = TRUE; 421 $this->view->result = array(); 422 return FALSE; 423 } 424 425 /** 426 * This just returns true. The view argument builder will know where 427 * to find the argument from. 428 */ 429 function default_default() { 430 return TRUE; 431 } 432 433 /** 434 * Determine if the argument is set to provide a default argument. 435 */ 436 function has_default_argument() { 437 $info = $this->default_actions($this->options['default_action']); 438 return !empty($info['has default argument']); 439 } 440 441 /** 442 * Get a default argument, if available. 443 */ 444 function get_default_argument() { 445 $plugin = views_get_plugin('argument default', $this->options['default_argument_type']); 446 if ($plugin) { 447 $plugin->init($this->view, $this); 448 return $plugin->get_argument(); 449 } 450 } 451 452 /** 453 * Default action: summary. 454 * 455 * If an argument was expected and was not given, in this case, display 456 * a summary query. 457 */ 458 function default_summary($order) { 459 $this->view->build_info['summary'] = TRUE; 460 $this->view->build_info['summary_level'] = $this->options['id']; 461 462 // Change the display style to the summary style for this 463 // argument. 464 $this->view->plugin_name = $this->options['style_plugin']; 465 $this->view->style_options = $this->options['style_options']; 466 467 // Clear out the normal primary field and whatever else may have 468 // been added and let the summary do the work. 469 $this->query->clear_fields(); 470 $this->summary_query(); 471 472 $this->summary_sort($order); 473 474 // Summaries have their own sorting and fields, so tell the View not 475 // to build these. 476 $this->view->build_sort = $this->view->build_fields = FALSE; 477 return TRUE; 478 } 479 480 /** 481 * Build the info for the summary query. 482 * 483 * This must: 484 * - add_groupby: group on this field in order to create summaries. 485 * - add_field: add a 'num_nodes' field for the count. Usually it will 486 * be a count on $view->base_field 487 * - set_count_field: Reset the count field so we get the right paging. 488 * 489 * @return 490 * The alias used to get the number of records (count) for this entry. 491 */ 492 function summary_query() { 493 $this->ensure_my_table(); 494 // Add the field. 495 $this->base_alias = $this->query->add_field($this->table_alias, $this->real_field); 496 497 $this->summary_name_field(); 498 return $this->summary_basics(); 499 } 500 501 /** 502 * Add the name field, which is the field displayed in summary queries. 503 * This is often used when the argument is numeric. 504 */ 505 function summary_name_field() { 506 // Add the 'name' field. For example, if this is a uid argument, the 507 // name field would be 'name' (i.e, the username). 508 509 if (isset($this->name_table)) { 510 // if the alias is different then we're probably added, not ensured, 511 // so look up the join and add it instead. 512 if ($this->table_alias != $this->table) { 513 $j = views_get_table_join($this->name_table, $this->table); 514 if ($j) { 515 $join = drupal_clone($j); 516 $join->left_table = $this->table_alias; 517 $this->name_table_alias = $this->query->add_table($this->name_table, $this->relationship, $join); 518 } 519 } 520 else { 521 $this->name_table_alias = $this->query->ensure_table($this->name_table, $this->relationship); 522 } 523 } 524 else { 525 $this->name_table_alias = $this->table_alias; 526 } 527 528 if (isset($this->name_field)) { 529 $this->name_alias = $this->query->add_field($this->name_table_alias, $this->name_field); 530 } 531 else { 532 $this->name_alias = $this->base_alias; 533 } 534 } 535 536 /** 537 * Some basic summary behavior that doesn't need to be repeated as much as 538 * code that goes into summary_query() 539 */ 540 function summary_basics($count_field = TRUE) { 541 // Add the number of nodes counter 542 $field = $this->query->base_table . '.' . $this->query->base_field; 543 $distinct = ($this->view->display_handler->get_option('distinct') && empty($this->query->no_distinct)); 544 545 $count_alias = $this->query->add_field(NULL, $field, 'num_records', 546 array('count' => TRUE, 'distinct' => $distinct)); 547 $this->query->add_groupby($this->name_alias); 548 549 if ($count_field) { 550 $this->query->set_count_field($this->table_alias, $this->real_field); 551 } 552 553 $this->count_alias = $count_alias; 554 } 555 556 /** 557 * Sorts the summary based upon the user's selection. The base variant of 558 * this is usually adequte. 559 * 560 * @param $order 561 * The order selected in the UI. 562 */ 563 function summary_sort($order) { 564 $this->query->add_orderby(NULL, NULL, $order, $this->name_alias); 565 } 566 567 /** 568 * Provide the argument to use to link from the summary to the next level; 569 * this will be called once per row of a summary, and used as part of 570 * $view->get_url(). 571 * 572 * @param $data 573 * The query results for the row. 574 */ 575 function summary_argument($data) { 576 return $data->{$this->base_alias}; 577 } 578 579 /** 580 * Provides the name to use for the summary. By default this is just 581 * the name field. 582 * 583 * @param $data 584 * The query results for the row. 585 */ 586 function summary_name($data) { 587 $value = $data->{$this->name_alias}; 588 if (empty($value) && !empty($this->definition['empty field name'])) { 589 $value = $this->definition['empty field name']; 590 } 591 return check_plain($value); 592 } 593 594 /** 595 * Set up the query for this argument. 596 * 597 * The argument sent may be found at $this->argument. 598 */ 599 function query() { 600 $this->ensure_my_table(); 601 $placeholder = empty($this->definition['numeric']) ? "'%s'" : '%d'; 602 $this->query->add_where(0, "$this->table_alias.$this->real_field = $placeholder", $this->argument); 603 } 604 605 /** 606 * Get the title this argument will assign the view, given the argument. 607 * 608 * This usually needs to be overridden to provide a proper title. 609 */ 610 function title() { 611 return check_plain($this->argument); 612 } 613 614 /** 615 * Called by the view object to get the title. This may be set by a 616 * validator so we don't necessarily call through to title(). 617 */ 618 function get_title() { 619 if (isset($this->validated_title)) { 620 return $this->validated_title; 621 } 622 else { 623 return $this->title(); 624 } 625 } 626 627 /** 628 * Validate that this argument works. By default, all arguments are valid. 629 */ 630 function validate_arg($arg) { 631 // By using % in URLs, arguments could be validated twice; this eases 632 // that pain. 633 if (isset($this->argument_validated)) { 634 return $this->argument_validated; 635 } 636 637 if ($this->is_wildcard($arg)) { 638 return $this->argument_validated = TRUE; 639 } 640 641 if ($this->options['validate_type'] == 'none') { 642 return $this->argument_validated = $this->validate_argument_basic($arg); 643 } 644 645 $plugin = views_get_plugin('argument validator', $this->options['validate_type']); 646 if ($plugin) { 647 $plugin->init($this->view, $this, $this->options['validate_type']); 648 return $this->argument_validated = $plugin->validate_argument($arg); 649 } 650 651 // If the plugin isn't found, fall back to the basic validation path: 652 return $this->argument_validated = $this->validate_argument_basic($arg); 653 } 654 655 /** 656 * Called by the menu system to validate an argument. 657 * 658 * This checks to see if this is a 'soft fail', which means that if the 659 * argument fails to validate, but there is an action to take anyway, 660 * then validation cannot actually fail. 661 */ 662 function validate_argument($arg) { 663 $validate_info = $this->default_actions($this->options['validate_fail']); 664 if (empty($validate_info['hard fail'])) { 665 return TRUE; 666 } 667 668 $rc = $this->validate_arg($arg); 669 670 // If the validator has changed the validate fail condition to a 671 // soft fail, deal with that: 672 $validate_info = $this->default_actions($this->options['validate_fail']); 673 if (empty($validate_info['hard fail'])) { 674 return TRUE; 675 } 676 677 return $rc; 678 } 679 680 /** 681 * Provide a basic argument validation. 682 * 683 * This can be overridden for more complex types; the basic 684 * validator only checks to see if the argument is not NULL 685 * or is numeric if the definition says it's numeric. 686 */ 687 function validate_argument_basic($arg) { 688 if (!isset($arg) || $arg === '') { 689 return FALSE; 690 } 691 692 if (!empty($this->definition['numeric']) && !isset($this->options['break_phrase']) && !is_numeric($arg)) { 693 return FALSE; 694 } 695 696 return TRUE; 697 } 698 699 /** 700 * Set the input for this argument 701 * 702 * @return TRUE if it successfully validates; FALSE if it does not. 703 */ 704 function set_argument($arg) { 705 $this->argument = $arg; 706 return $this->validate_arg($arg); 707 } 708 709 /** 710 * Get the value of this argument. 711 */ 712 function get_value() { 713 // If we already processed this argument, we're done. 714 if (isset($this->argument)) { 715 return $this->argument; 716 } 717 718 // Otherwise, we have to pretend to process ourself to find the value. 719 $value = NULL; 720 // Find the position of this argument within the view. 721 $position = 0; 722 foreach ($this->view->argument as $id => $argument) { 723 if ($id == $this->options['id']) { 724 break; 725 } 726 $position++; 727 } 728 729 $arg = isset($this->view->args[$position]) ? $this->view->args[$position] : NULL; 730 $this->position = $position; 731 732 // Clone ourselves so that we don't break things when we're really 733 // processing the arguments. 734 $argument = drupal_clone($this); 735 if (!isset($arg) && $argument->has_default_argument()) { 736 $arg = $argument->get_default_argument(); 737 } 738 // Set the argument, which will also validate that the argument can be set. 739 if ($argument->set_argument($arg)) { 740 $value = $argument->argument; 741 } 742 unset($argument); 743 return $value; 744 } 745 } 746 747 /** 748 * A special handler to take the place of missing or broken handlers. 749 * 750 * @ingroup views_argument_handlers 751 */ 752 class views_handler_argument_broken extends views_handler_argument { 753 function ui_name($short = FALSE) { 754 return t('Broken/missing handler'); 755 } 756 757 function ensure_my_table() { /* No table to ensure! */ } 758 function query() { /* No query to run */ } 759 function options_form(&$form, &$form_state) { 760 $form['markup'] = array( 761 '#prefix' => '<div class="form-item description">', 762 '#value' => t('The handler for this item is broken or missing and cannot be used. If a module provided the handler and was disabled, re-enabling the module may restore it. Otherwise, you should probably delete this item.'), 763 ); 764 } 765 766 /** 767 * Determine if the handler is considered 'broken' 768 */ 769 function broken() { return TRUE; } 770 } 771 772 /** 773 * @} 774 */
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated: Thu Mar 24 11:18:33 2011 | Cross-referenced by PHPXref 0.7 |