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