Now all modules are in core modules folder
This commit is contained in:
parent
5ba1cdfa0b
commit
05b6a91b0c
1907 changed files with 0 additions and 0 deletions
773
modules/views/handlers/views_handler_argument.inc
Normal file
773
modules/views/handlers/views_handler_argument.inc
Normal file
|
@ -0,0 +1,773 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @defgroup views_argument_handlers Handlers for arguments
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Base class for arguments.
|
||||
*
|
||||
* The basic argument works for very simple arguments such as nid and uid
|
||||
*
|
||||
* Definition terms for this handler:
|
||||
* - name field: The field to use for the name to use in the summary, which is
|
||||
* the displayed output. For example, for the node: nid argument,
|
||||
* the argument itself is the nid, but node.title is displayed.
|
||||
* - name table: The table to use for the name, should it not be in the same
|
||||
* table as the argument.
|
||||
* - empty field name: For arguments that can have no value, such as taxonomy
|
||||
* which can have "no term", this is the string which
|
||||
* will be displayed for this lack of value. Be sure to use
|
||||
* t().
|
||||
* - validate type: A little used string to allow an argument to restrict
|
||||
* which validator is available to just one. Use the
|
||||
* validator ID. This probably should not be used at all,
|
||||
* and may disappear or change.
|
||||
* - numeric: If set to TRUE this field is numeric and will use %d instead of
|
||||
* %s in queries.
|
||||
*
|
||||
* @ingroup views_argument_handlers
|
||||
*/
|
||||
class views_handler_argument extends views_handler {
|
||||
var $name_field = NULL;
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
function construct() {
|
||||
parent::construct();
|
||||
|
||||
if (!empty($this->definition['name field'])) {
|
||||
$this->name_field = $this->definition['name field'];
|
||||
}
|
||||
if (!empty($this->definition['name table'])) {
|
||||
$this->name_table = $this->definition['name table'];
|
||||
}
|
||||
}
|
||||
|
||||
function init(&$view, $options) {
|
||||
parent::init($view, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Give an argument the opportunity to modify the breadcrumb, if it wants.
|
||||
* This only gets called on displays where a breadcrumb is actually used.
|
||||
*
|
||||
* The breadcrumb will be in the form of an array, with the keys being
|
||||
* the path and the value being the already sanitized title of the path.
|
||||
*/
|
||||
function set_breadcrumb(&$breadcrumb) { }
|
||||
|
||||
/**
|
||||
* Determine if the argument can generate a breadcrumb
|
||||
*
|
||||
* @return TRUE/FALSE
|
||||
*/
|
||||
function uses_breadcrumb() {
|
||||
$info = $this->default_actions($this->options['default_action']);
|
||||
return !empty($info['breadcrumb']);
|
||||
}
|
||||
|
||||
function is_wildcard($arg = NULL) {
|
||||
if (!isset($arg)) {
|
||||
$arg = $this->argument;
|
||||
}
|
||||
|
||||
return !empty($this->options['wildcard']) && $this->options['wildcard'] === $arg;
|
||||
}
|
||||
|
||||
function wildcard_title() {
|
||||
return $this->options['wildcard_substitution'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the argument needs a style plugin.
|
||||
*
|
||||
* @return TRUE/FALSE
|
||||
*/
|
||||
function needs_style_plugin() {
|
||||
$info = $this->default_actions($this->options['default_action']);
|
||||
$validate_info = $this->default_actions($this->options['validate_fail']);
|
||||
return !empty($info['style plugin']) || !empty($validate_info['style plugin']);
|
||||
}
|
||||
|
||||
function option_definition() {
|
||||
$options = parent::option_definition();
|
||||
|
||||
$options['default_action'] = array('default' => 'ignore');
|
||||
$options['style_plugin'] = array('default' => 'default_summary');
|
||||
$options['style_options'] = array('default' => array());
|
||||
$options['wildcard'] = array('default' => 'all');
|
||||
$options['wildcard_substitution'] = array('default' => t('All'), 'translatable' => TRUE);
|
||||
$options['title'] = array('default' => '', 'translatable' => TRUE);
|
||||
$options['breadcrumb'] = array('default' => '', 'translatable' => TRUE);
|
||||
$options['default_argument_type'] = array('default' => 'fixed');
|
||||
$options['default_argument'] = array('default' => '');
|
||||
$options['validate_type'] = array('default' => 'none');
|
||||
$options['validate_fail'] = array('default' => 'not found');
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
function options_form(&$form, &$form_state) {
|
||||
$defaults = $this->default_actions();
|
||||
|
||||
$form['title'] = array(
|
||||
'#prefix' => '<div class="clear-block">',
|
||||
'#suffix' => '</div>',
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Title'),
|
||||
'#default_value' => $this->options['title'],
|
||||
'#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.'),
|
||||
);
|
||||
|
||||
$form['breadcrumb'] = array(
|
||||
'#prefix' => '<div class="clear-block">',
|
||||
'#suffix' => '</div>',
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Breadcrumb'),
|
||||
'#default_value' => $this->options['breadcrumb'],
|
||||
'#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.'),
|
||||
);
|
||||
|
||||
$form['clear_start'] = array(
|
||||
'#value' => '<div class="clear-block">',
|
||||
);
|
||||
|
||||
$form['defaults_start'] = array(
|
||||
'#value' => '<div class="views-left-50">',
|
||||
);
|
||||
|
||||
$form['default_action'] = array(
|
||||
'#type' => 'radios',
|
||||
'#title' => t('Action to take if argument is not present'),
|
||||
'#default_value' => $this->options['default_action'],
|
||||
);
|
||||
|
||||
$form['defaults_stop'] = array(
|
||||
'#value' => '</div>',
|
||||
);
|
||||
|
||||
$form['wildcard'] = array(
|
||||
'#prefix' => '<div class="views-right-50">',
|
||||
// prefix and no suffix means these two items will be grouped together.
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Wildcard'),
|
||||
'#size' => 20,
|
||||
'#default_value' => $this->options['wildcard'],
|
||||
'#description' => t('If this value is received as an argument, the argument will be ignored; i.e, "all values"'),
|
||||
);
|
||||
|
||||
$form['wildcard_substitution'] = array(
|
||||
'#suffix' => '</div>',
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Wildcard title'),
|
||||
'#size' => 20,
|
||||
'#default_value' => $this->options['wildcard_substitution'],
|
||||
'#description' => t('The title to use for the wildcard in substitutions elsewhere.'),
|
||||
);
|
||||
|
||||
$form['clear_stop'] = array(
|
||||
'#value' => '</div>',
|
||||
);
|
||||
|
||||
$options = array();
|
||||
$validate_options = array();
|
||||
foreach ($defaults as $id => $info) {
|
||||
$options[$id] = $info['title'];
|
||||
if (empty($info['default only'])) {
|
||||
$validate_options[$id] = $info['title'];
|
||||
}
|
||||
if (!empty($info['form method'])) {
|
||||
$this->{$info['form method']}($form, $form_state);
|
||||
}
|
||||
}
|
||||
|
||||
$form['default_action']['#options'] = $options;
|
||||
|
||||
$form['validate_options_div_prefix'] = array(
|
||||
'#id' => 'views-validator-options',
|
||||
'#value' => '<fieldset id="views-validator-options"><legend>' . t('Validator options') . '</legend>',
|
||||
);
|
||||
|
||||
$form['validate_type'] = array(
|
||||
'#type' => 'select',
|
||||
'#title' => t('Validator'),
|
||||
'#default_value' => $this->options['validate_type'],
|
||||
);
|
||||
|
||||
$validate_types = array('none' => t('- Basic validation -'));
|
||||
$plugins = views_fetch_plugin_data('argument validator');
|
||||
foreach ($plugins as $id => $info) {
|
||||
if (!empty($info['no ui'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$valid = TRUE;
|
||||
if (!empty($info['type'])) {
|
||||
$valid = FALSE;
|
||||
if (empty($this->definition['validate type'])) {
|
||||
continue;
|
||||
}
|
||||
foreach ((array) $info['type'] as $type) {
|
||||
if ($type == $this->definition['validate type']) {
|
||||
$valid = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we decide this validator is ok, add it to the list.
|
||||
if ($valid) {
|
||||
$plugin = views_get_plugin('argument validator', $id);
|
||||
if ($plugin) {
|
||||
$plugin->init($this->view, $this, $id);
|
||||
if ($plugin->access() || $this->options['validate_type'] == $id) {
|
||||
$plugin->validate_form($form, $form_state, $id);
|
||||
$validate_types[$id] = $info['title'];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
asort($validate_types);
|
||||
$form['validate_type']['#options'] = $validate_types;
|
||||
|
||||
$form['validate_fail'] = array(
|
||||
'#type' => 'select',
|
||||
'#title' => t('Action to take if argument does not validate'),
|
||||
'#default_value' => $this->options['validate_fail'],
|
||||
'#options' => $validate_options,
|
||||
);
|
||||
|
||||
$form['validate_options_div_suffix'] = array(
|
||||
'#value' => '</fieldset>',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide a list of default behaviors for this argument if the argument
|
||||
* is not present.
|
||||
*
|
||||
* Override this method to provide additional (or fewer) default behaviors.
|
||||
*/
|
||||
function default_actions($which = NULL) {
|
||||
$defaults = array(
|
||||
'ignore' => array(
|
||||
'title' => t('Display all values'),
|
||||
'method' => 'default_ignore',
|
||||
'breadcrumb' => TRUE, // generate a breadcrumb to here
|
||||
),
|
||||
'not found' => array(
|
||||
'title' => t('Hide view / Page not found (404)'),
|
||||
'method' => 'default_not_found',
|
||||
'hard fail' => TRUE, // This is a hard fail condition
|
||||
),
|
||||
'empty' => array(
|
||||
'title' => t('Display empty text'),
|
||||
'method' => 'default_empty',
|
||||
'breadcrumb' => TRUE, // generate a breadcrumb to here
|
||||
),
|
||||
'summary asc' => array(
|
||||
'title' => t('Summary, sorted ascending'),
|
||||
'method' => 'default_summary',
|
||||
'method args' => array('asc'),
|
||||
'style plugin' => TRUE,
|
||||
'breadcrumb' => TRUE, // generate a breadcrumb to here
|
||||
),
|
||||
'summary desc' => array(
|
||||
'title' => t('Summary, sorted descending'),
|
||||
'method' => 'default_summary',
|
||||
'method args' => array('desc'),
|
||||
'style plugin' => TRUE,
|
||||
'breadcrumb' => TRUE, // generate a breadcrumb to here
|
||||
),
|
||||
'default' => array(
|
||||
'title' => t('Provide default argument'),
|
||||
'method' => 'default_default',
|
||||
'form method' => 'default_argument_form',
|
||||
'has default argument' => TRUE,
|
||||
'default only' => TRUE, // this can only be used for missing argument, not validation failure
|
||||
),
|
||||
);
|
||||
|
||||
if ($which) {
|
||||
if (!empty($defaults[$which])) {
|
||||
return $defaults[$which];
|
||||
}
|
||||
}
|
||||
else {
|
||||
return $defaults;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide a form for selecting the default argument when the
|
||||
* default action is set to provide default argument.
|
||||
*/
|
||||
function default_argument_form(&$form, &$form_state) {
|
||||
$plugins = views_fetch_plugin_data('argument default');
|
||||
$options = array();
|
||||
|
||||
// This construct uses 'hidden' and not markup because process doesn't
|
||||
// run. It also has an extra div because the dependency wants to hide
|
||||
// the parent in situations like this, so we need a second div to
|
||||
// make this work.
|
||||
$form['default_options_div_prefix'] = array(
|
||||
'#type' => 'hidden',
|
||||
'#id' => 'views-default-options',
|
||||
'#prefix' => '<div><fieldset id="views-default-options"><legend>' . t('Provide default argument options') . '</legend>',
|
||||
'#process' => array('views_process_dependency'),
|
||||
'#dependency' => array('radio:options[default_action]' => array('default')),
|
||||
);
|
||||
|
||||
$form['default_argument_type'] = array(
|
||||
'#prefix' => '<div id="edit-options-default-argument-type-wrapper">',
|
||||
'#suffix' => '</div>',
|
||||
'#type' => 'radios',
|
||||
'#id' => 'edit-options-default-argument-type',
|
||||
'#title' => t('Default argument type'),
|
||||
'#default_value' => $this->options['default_argument_type'],
|
||||
'#process' => array('expand_radios', 'views_process_dependency'),
|
||||
'#dependency' => array('radio:options[default_action]' => array('default')),
|
||||
);
|
||||
|
||||
foreach ($plugins as $id => $info) {
|
||||
$plugin = views_get_plugin('argument default', $id);
|
||||
if ($plugin) {
|
||||
$plugin->init($this->view, $this, $id);
|
||||
|
||||
if ($plugin->access() || $this->options['default_argument_type'] == $id) {
|
||||
$options[$id] = $info['title'];
|
||||
$plugin->argument_form($form, $form_state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$form['default_options_div_suffix'] = array(
|
||||
'#value' => '</fieldset></div>',
|
||||
);
|
||||
|
||||
asort($options);
|
||||
$form['default_argument_type']['#options'] = $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the default action, which means our argument wasn't present.
|
||||
*
|
||||
* Override this method only with extreme care.
|
||||
*
|
||||
* @return
|
||||
* A boolean value; if TRUE, continue building this view. If FALSE,
|
||||
* building the view will be aborted here.
|
||||
*/
|
||||
function default_action($info = NULL) {
|
||||
if (!isset($info)) {
|
||||
$info = $this->default_actions($this->options['default_action']);
|
||||
}
|
||||
|
||||
if (!$info) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!empty($info['method args'])) {
|
||||
return call_user_func_array(array(&$this, $info['method']), $info['method args']);
|
||||
}
|
||||
else {
|
||||
return $this->{$info['method']}();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* How to act if validation failes
|
||||
*/
|
||||
function validate_fail() {
|
||||
$info = $this->default_actions($this->options['validate_fail']);
|
||||
return $this->default_action($info);
|
||||
}
|
||||
/**
|
||||
* Default action: ignore.
|
||||
*
|
||||
* If an argument was expected and was not given, in this case, simply
|
||||
* ignore the argument entirely.
|
||||
*/
|
||||
function default_ignore() {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Default action: not found.
|
||||
*
|
||||
* If an argument was expected and was not given, in this case, report
|
||||
* the view as 'not found' or hide it.
|
||||
*/
|
||||
function default_not_found() {
|
||||
// Set a failure condition and let the display manager handle it.
|
||||
$this->view->build_info['fail'] = TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Default action: empty
|
||||
*
|
||||
* If an argument was expected and was not given, in this case, display
|
||||
* the view's empty text
|
||||
*/
|
||||
function default_empty() {
|
||||
// We return with no query; this will force the empty text.
|
||||
$this->view->built = TRUE;
|
||||
$this->view->executed = TRUE;
|
||||
$this->view->result = array();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* This just returns true. The view argument builder will know where
|
||||
* to find the argument from.
|
||||
*/
|
||||
function default_default() {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the argument is set to provide a default argument.
|
||||
*/
|
||||
function has_default_argument() {
|
||||
$info = $this->default_actions($this->options['default_action']);
|
||||
return !empty($info['has default argument']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a default argument, if available.
|
||||
*/
|
||||
function get_default_argument() {
|
||||
$plugin = views_get_plugin('argument default', $this->options['default_argument_type']);
|
||||
if ($plugin) {
|
||||
$plugin->init($this->view, $this);
|
||||
return $plugin->get_argument();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Default action: summary.
|
||||
*
|
||||
* If an argument was expected and was not given, in this case, display
|
||||
* a summary query.
|
||||
*/
|
||||
function default_summary($order) {
|
||||
$this->view->build_info['summary'] = TRUE;
|
||||
$this->view->build_info['summary_level'] = $this->options['id'];
|
||||
|
||||
// Change the display style to the summary style for this
|
||||
// argument.
|
||||
$this->view->plugin_name = $this->options['style_plugin'];
|
||||
$this->view->style_options = $this->options['style_options'];
|
||||
|
||||
// Clear out the normal primary field and whatever else may have
|
||||
// been added and let the summary do the work.
|
||||
$this->query->clear_fields();
|
||||
$this->summary_query();
|
||||
|
||||
$this->summary_sort($order);
|
||||
|
||||
// Summaries have their own sorting and fields, so tell the View not
|
||||
// to build these.
|
||||
$this->view->build_sort = $this->view->build_fields = FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the info for the summary query.
|
||||
*
|
||||
* This must:
|
||||
* - add_groupby: group on this field in order to create summaries.
|
||||
* - add_field: add a 'num_nodes' field for the count. Usually it will
|
||||
* be a count on $view->base_field
|
||||
* - set_count_field: Reset the count field so we get the right paging.
|
||||
*
|
||||
* @return
|
||||
* The alias used to get the number of records (count) for this entry.
|
||||
*/
|
||||
function summary_query() {
|
||||
$this->ensure_my_table();
|
||||
// Add the field.
|
||||
$this->base_alias = $this->query->add_field($this->table_alias, $this->real_field);
|
||||
|
||||
$this->summary_name_field();
|
||||
return $this->summary_basics();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the name field, which is the field displayed in summary queries.
|
||||
* This is often used when the argument is numeric.
|
||||
*/
|
||||
function summary_name_field() {
|
||||
// Add the 'name' field. For example, if this is a uid argument, the
|
||||
// name field would be 'name' (i.e, the username).
|
||||
|
||||
if (isset($this->name_table)) {
|
||||
// if the alias is different then we're probably added, not ensured,
|
||||
// so look up the join and add it instead.
|
||||
if ($this->table_alias != $this->table) {
|
||||
$j = views_get_table_join($this->name_table, $this->table);
|
||||
if ($j) {
|
||||
$join = drupal_clone($j);
|
||||
$join->left_table = $this->table_alias;
|
||||
$this->name_table_alias = $this->query->add_table($this->name_table, $this->relationship, $join);
|
||||
}
|
||||
}
|
||||
else {
|
||||
$this->name_table_alias = $this->query->ensure_table($this->name_table, $this->relationship);
|
||||
}
|
||||
}
|
||||
else {
|
||||
$this->name_table_alias = $this->table_alias;
|
||||
}
|
||||
|
||||
if (isset($this->name_field)) {
|
||||
$this->name_alias = $this->query->add_field($this->name_table_alias, $this->name_field);
|
||||
}
|
||||
else {
|
||||
$this->name_alias = $this->base_alias;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Some basic summary behavior that doesn't need to be repeated as much as
|
||||
* code that goes into summary_query()
|
||||
*/
|
||||
function summary_basics($count_field = TRUE) {
|
||||
// Add the number of nodes counter
|
||||
$field = $this->query->base_table . '.' . $this->query->base_field;
|
||||
$distinct = ($this->view->display_handler->get_option('distinct') && empty($this->query->no_distinct));
|
||||
|
||||
$count_alias = $this->query->add_field(NULL, $field, 'num_records',
|
||||
array('count' => TRUE, 'distinct' => $distinct));
|
||||
$this->query->add_groupby($this->name_alias);
|
||||
|
||||
if ($count_field) {
|
||||
$this->query->set_count_field($this->table_alias, $this->real_field);
|
||||
}
|
||||
|
||||
$this->count_alias = $count_alias;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sorts the summary based upon the user's selection. The base variant of
|
||||
* this is usually adequte.
|
||||
*
|
||||
* @param $order
|
||||
* The order selected in the UI.
|
||||
*/
|
||||
function summary_sort($order) {
|
||||
$this->query->add_orderby(NULL, NULL, $order, $this->name_alias);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide the argument to use to link from the summary to the next level;
|
||||
* this will be called once per row of a summary, and used as part of
|
||||
* $view->get_url().
|
||||
*
|
||||
* @param $data
|
||||
* The query results for the row.
|
||||
*/
|
||||
function summary_argument($data) {
|
||||
return $data->{$this->base_alias};
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the name to use for the summary. By default this is just
|
||||
* the name field.
|
||||
*
|
||||
* @param $data
|
||||
* The query results for the row.
|
||||
*/
|
||||
function summary_name($data) {
|
||||
$value = $data->{$this->name_alias};
|
||||
if (empty($value) && !empty($this->definition['empty field name'])) {
|
||||
$value = $this->definition['empty field name'];
|
||||
}
|
||||
return check_plain($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up the query for this argument.
|
||||
*
|
||||
* The argument sent may be found at $this->argument.
|
||||
*/
|
||||
function query() {
|
||||
$this->ensure_my_table();
|
||||
$placeholder = empty($this->definition['numeric']) ? "'%s'" : '%d';
|
||||
$this->query->add_where(0, "$this->table_alias.$this->real_field = $placeholder", $this->argument);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the title this argument will assign the view, given the argument.
|
||||
*
|
||||
* This usually needs to be overridden to provide a proper title.
|
||||
*/
|
||||
function title() {
|
||||
return check_plain($this->argument);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by the view object to get the title. This may be set by a
|
||||
* validator so we don't necessarily call through to title().
|
||||
*/
|
||||
function get_title() {
|
||||
if (isset($this->validated_title)) {
|
||||
return $this->validated_title;
|
||||
}
|
||||
else {
|
||||
return $this->title();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that this argument works. By default, all arguments are valid.
|
||||
*/
|
||||
function validate_arg($arg) {
|
||||
// By using % in URLs, arguments could be validated twice; this eases
|
||||
// that pain.
|
||||
if (isset($this->argument_validated)) {
|
||||
return $this->argument_validated;
|
||||
}
|
||||
|
||||
if ($this->is_wildcard($arg)) {
|
||||
return $this->argument_validated = TRUE;
|
||||
}
|
||||
|
||||
if ($this->options['validate_type'] == 'none') {
|
||||
return $this->argument_validated = $this->validate_argument_basic($arg);
|
||||
}
|
||||
|
||||
$plugin = views_get_plugin('argument validator', $this->options['validate_type']);
|
||||
if ($plugin) {
|
||||
$plugin->init($this->view, $this, $this->options['validate_type']);
|
||||
return $this->argument_validated = $plugin->validate_argument($arg);
|
||||
}
|
||||
|
||||
// If the plugin isn't found, fall back to the basic validation path:
|
||||
return $this->argument_validated = $this->validate_argument_basic($arg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by the menu system to validate an argument.
|
||||
*
|
||||
* This checks to see if this is a 'soft fail', which means that if the
|
||||
* argument fails to validate, but there is an action to take anyway,
|
||||
* then validation cannot actually fail.
|
||||
*/
|
||||
function validate_argument($arg) {
|
||||
$validate_info = $this->default_actions($this->options['validate_fail']);
|
||||
if (empty($validate_info['hard fail'])) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
$rc = $this->validate_arg($arg);
|
||||
|
||||
// If the validator has changed the validate fail condition to a
|
||||
// soft fail, deal with that:
|
||||
$validate_info = $this->default_actions($this->options['validate_fail']);
|
||||
if (empty($validate_info['hard fail'])) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return $rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide a basic argument validation.
|
||||
*
|
||||
* This can be overridden for more complex types; the basic
|
||||
* validator only checks to see if the argument is not NULL
|
||||
* or is numeric if the definition says it's numeric.
|
||||
*/
|
||||
function validate_argument_basic($arg) {
|
||||
if (!isset($arg) || $arg === '') {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!empty($this->definition['numeric']) && !isset($this->options['break_phrase']) && !is_numeric($arg)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the input for this argument
|
||||
*
|
||||
* @return TRUE if it successfully validates; FALSE if it does not.
|
||||
*/
|
||||
function set_argument($arg) {
|
||||
$this->argument = $arg;
|
||||
return $this->validate_arg($arg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of this argument.
|
||||
*/
|
||||
function get_value() {
|
||||
// If we already processed this argument, we're done.
|
||||
if (isset($this->argument)) {
|
||||
return $this->argument;
|
||||
}
|
||||
|
||||
// Otherwise, we have to pretend to process ourself to find the value.
|
||||
$value = NULL;
|
||||
// Find the position of this argument within the view.
|
||||
$position = 0;
|
||||
foreach ($this->view->argument as $id => $argument) {
|
||||
if ($id == $this->options['id']) {
|
||||
break;
|
||||
}
|
||||
$position++;
|
||||
}
|
||||
|
||||
$arg = isset($this->view->args[$position]) ? $this->view->args[$position] : NULL;
|
||||
$this->position = $position;
|
||||
|
||||
// Clone ourselves so that we don't break things when we're really
|
||||
// processing the arguments.
|
||||
$argument = drupal_clone($this);
|
||||
if (!isset($arg) && $argument->has_default_argument()) {
|
||||
$arg = $argument->get_default_argument();
|
||||
}
|
||||
// Set the argument, which will also validate that the argument can be set.
|
||||
if ($argument->set_argument($arg)) {
|
||||
$value = $argument->argument;
|
||||
}
|
||||
unset($argument);
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A special handler to take the place of missing or broken handlers.
|
||||
*
|
||||
* @ingroup views_argument_handlers
|
||||
*/
|
||||
class views_handler_argument_broken extends views_handler_argument {
|
||||
function ui_name($short = FALSE) {
|
||||
return t('Broken/missing handler');
|
||||
}
|
||||
|
||||
function ensure_my_table() { /* No table to ensure! */ }
|
||||
function query() { /* No query to run */ }
|
||||
function options_form(&$form, &$form_state) {
|
||||
$form['markup'] = array(
|
||||
'#prefix' => '<div class="form-item description">',
|
||||
'#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.'),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the handler is considered 'broken'
|
||||
*/
|
||||
function broken() { return TRUE; }
|
||||
}
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
66
modules/views/handlers/views_handler_argument_date.inc
Normal file
66
modules/views/handlers/views_handler_argument_date.inc
Normal file
|
@ -0,0 +1,66 @@
|
|||
<?php
|
||||
/**
|
||||
* Abstract argument handler for dates.
|
||||
*
|
||||
* Adds an option to set a default argument based on the current date.
|
||||
*
|
||||
* @param $arg_format
|
||||
* The format string to use on the current time when
|
||||
* creating a default date argument.
|
||||
*
|
||||
* Definitions terms:
|
||||
* - many to one: If true, the "many to one" helper will be used.
|
||||
* - invalid input: A string to give to the user for obviously invalid input.
|
||||
* This is deprecated in favor of argument validators.
|
||||
* @see views_many_to_one_helper
|
||||
*
|
||||
* @ingroup views_argument_handlers
|
||||
*/
|
||||
class views_handler_argument_date extends views_handler_argument_formula {
|
||||
var $option_name = 'default_argument_date';
|
||||
var $arg_format = 'Y-m-d';
|
||||
|
||||
/**
|
||||
* Add an option to set the default value to the current date.
|
||||
*/
|
||||
function default_argument_form(&$form, &$form_state) {
|
||||
parent::default_argument_form($form, $form_state);
|
||||
$form['default_argument_type']['#options'] += array('date' => t('Current date'));
|
||||
$form['default_argument_type']['#options'] += array('node_created' => t("Current node's creation time"));
|
||||
$form['default_argument_type']['#options'] += array('node_changed' => t("Current node's update time")); }
|
||||
|
||||
/**
|
||||
* Set the empty argument value to the current date,
|
||||
* formatted appropriately for this argument.
|
||||
*/
|
||||
function get_default_argument($raw = FALSE) {
|
||||
if (!$raw && $this->options['default_argument_type'] == 'date') {
|
||||
return date($this->arg_format, time());
|
||||
}
|
||||
else if (!$raw && in_array($this->options['default_argument_type'], array('node_created', 'node_changed'))) {
|
||||
foreach (range(1, 3) as $i) {
|
||||
$node = menu_get_object('node', $i);
|
||||
if (!empty($node)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (arg(0) == 'node' && is_numeric(arg(1))) {
|
||||
$node = node_load(arg(1));
|
||||
}
|
||||
|
||||
if (empty($node)) {
|
||||
return parent::get_default_argument();
|
||||
}
|
||||
else if ($this->options['default_argument_type'] == 'node_created') {
|
||||
return date($this->arg_format, $node->created);
|
||||
}
|
||||
else if ($this->options['default_argument_type'] == 'node_changed') {
|
||||
return date($this->arg_format, $node->changed);
|
||||
}
|
||||
}
|
||||
|
||||
return parent::get_default_argument($raw);
|
||||
|
||||
}
|
||||
}
|
54
modules/views/handlers/views_handler_argument_formula.inc
Normal file
54
modules/views/handlers/views_handler_argument_formula.inc
Normal file
|
@ -0,0 +1,54 @@
|
|||
<?php
|
||||
/**
|
||||
* Abstract argument handler for simple formulae.
|
||||
*
|
||||
* Child classes of this object should implement summary_argument, at least.
|
||||
*
|
||||
* Definition terms:
|
||||
* - formula: The formula to use for this handler.
|
||||
*
|
||||
* @ingroup views_argument_handlers
|
||||
*/
|
||||
class views_handler_argument_formula extends views_handler_argument {
|
||||
var $formula = NULL;
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
function construct() {
|
||||
parent::construct();
|
||||
|
||||
if (!empty($this->definition['formula'])) {
|
||||
$this->formula = $this->definition['formula'];
|
||||
}
|
||||
}
|
||||
|
||||
function get_formula() {
|
||||
return str_replace('***table***', $this->table_alias, $this->formula);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the summary query based on a formula
|
||||
*/
|
||||
function summary_query() {
|
||||
$this->ensure_my_table();
|
||||
// Now that our table is secure, get our formula.
|
||||
$formula = $this->get_formula();
|
||||
|
||||
// Add the field.
|
||||
$this->base_alias = $this->name_alias = $this->query->add_field(NULL, $formula, $this->field);
|
||||
$this->query->set_count_field(NULL, $formula, $this->field);
|
||||
|
||||
return $this->summary_basics(FALSE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the query based upon the formula
|
||||
*/
|
||||
function query() {
|
||||
$this->ensure_my_table();
|
||||
// Now that our table is secure, get our formula.
|
||||
$formula = $this->get_formula();
|
||||
|
||||
$this->query->add_where(0, "$formula = '%s'", $this->argument);
|
||||
}
|
||||
}
|
170
modules/views/handlers/views_handler_argument_many_to_one.inc
Normal file
170
modules/views/handlers/views_handler_argument_many_to_one.inc
Normal file
|
@ -0,0 +1,170 @@
|
|||
<?php
|
||||
/**
|
||||
* An argument handler for use in fields that have a many to one relationship
|
||||
* with the table(s) to the left. This adds a bunch of options that are
|
||||
* reasonably common with this type of relationship.
|
||||
* Definition terms:
|
||||
* - numeric: If true, the field will be considered numeric. Probably should
|
||||
* always be set TRUE as views_handler_argument_string has many to one
|
||||
* capabilities.
|
||||
* - zero is null: If true, a 0 will be handled as empty, so for example
|
||||
* a default argument can be provided or a summary can be shown.
|
||||
*
|
||||
* @ingroup views_argument_handlers
|
||||
*/
|
||||
class views_handler_argument_many_to_one extends views_handler_argument {
|
||||
function init(&$view, $options) {
|
||||
parent::init($view, $options);
|
||||
$this->helper = new views_many_to_one_helper($this);
|
||||
|
||||
// Ensure defaults for these, during summaries and stuff:
|
||||
$this->operator = 'or';
|
||||
$this->value = array();
|
||||
}
|
||||
|
||||
function option_definition() {
|
||||
$options = parent::option_definition();
|
||||
|
||||
if (!empty($this->definition['numeric'])) {
|
||||
$options['break_phrase'] = array('default' => FALSE);
|
||||
}
|
||||
|
||||
$options['add_table'] = array('default' => FALSE);
|
||||
$options['require_value'] = array('default' => FALSE);
|
||||
|
||||
views_many_to_one_helper::option_definition($options);
|
||||
return $options;
|
||||
}
|
||||
|
||||
function options_form(&$form, &$form_state) {
|
||||
parent::options_form($form, $form_state);
|
||||
|
||||
// allow + for or, , for and
|
||||
if (!empty($this->definition['numeric'])) {
|
||||
$form['break_phrase'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Allow multiple terms per argument.'),
|
||||
'#description' => t('If selected, users can enter multiple arguments in the form of 1+2+3 (for OR) or 1,2,3 (for AND).'),
|
||||
'#default_value' => !empty($this->options['break_phrase']),
|
||||
);
|
||||
}
|
||||
|
||||
$form['add_table'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Allow multiple arguments to work together.'),
|
||||
'#description' => t('If selected, multiple instances of this argument can work together, as though multiple terms were supplied to the same argument. This setting is not compatible with the "Reduce duplicates" setting.'),
|
||||
'#default_value' => !empty($this->options['add_table']),
|
||||
);
|
||||
|
||||
$form['require_value'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Do not display items with no value in summary'),
|
||||
'#default_value' => !empty($this->options['require_value']),
|
||||
);
|
||||
|
||||
$this->helper->options_form($form, $form_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Override ensure_my_table so we can control how this joins in.
|
||||
* The operator actually has influence over joining.
|
||||
*/
|
||||
function ensure_my_table() {
|
||||
$this->helper->ensure_my_table();
|
||||
}
|
||||
|
||||
function query() {
|
||||
$empty = FALSE;
|
||||
if (isset($this->definition['zero is null']) && $this->definition['zero is null']) {
|
||||
if (empty($this->argument)) {
|
||||
$empty = TRUE;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!isset($this->argument)) {
|
||||
$empty = TRUE;
|
||||
}
|
||||
}
|
||||
if ($empty) {
|
||||
parent::ensure_my_table();
|
||||
$this->query->add_where(0, "$this->table_alias.$this->real_field IS NULL");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!empty($this->options['break_phrase'])) {
|
||||
views_break_phrase($this->argument, $this);
|
||||
}
|
||||
else {
|
||||
$this->value = array($this->argument);
|
||||
$this->operator = 'or';
|
||||
}
|
||||
|
||||
$this->helper->add_filter();
|
||||
}
|
||||
|
||||
function title() {
|
||||
if (!$this->argument) {
|
||||
return !empty($this->definition['empty field name']) ? $this->definition['empty field name'] : t('Uncategorized');
|
||||
}
|
||||
|
||||
if (!empty($this->options['break_phrase'])) {
|
||||
views_break_phrase($this->argument, $this);
|
||||
}
|
||||
else {
|
||||
$this->value = array($this->argument);
|
||||
$this->operator = 'or';
|
||||
}
|
||||
|
||||
// @todo -- both of these should check definition for alternate keywords.
|
||||
|
||||
if (empty($this->value)) {
|
||||
return !empty($this->definition['empty field name']) ? $this->definition['empty field name'] : t('Uncategorized');
|
||||
}
|
||||
|
||||
if ($this->value === array(-1)) {
|
||||
return !empty($this->definition['invalid input']) ? $this->definition['invalid input'] : t('Invalid input');
|
||||
}
|
||||
|
||||
return implode($this->operator == 'or' ? ' + ' : ', ', $this->title_query());
|
||||
}
|
||||
|
||||
function summary_query() {
|
||||
$field = $this->table . '.' . $this->field;
|
||||
$join = $this->get_join();
|
||||
|
||||
if (!empty($this->options['require_value'])) {
|
||||
$join->type = 'INNER';
|
||||
}
|
||||
|
||||
if (empty($this->options['add_table']) || empty($this->view->many_to_one_tables[$field])) {
|
||||
$this->table_alias = $this->query->ensure_table($this->table, $this->relationship, $join);
|
||||
}
|
||||
else {
|
||||
$this->table_alias = $this->helper->summary_join();
|
||||
}
|
||||
|
||||
// Add the field.
|
||||
$this->base_alias = $this->query->add_field($this->table_alias, $this->real_field);
|
||||
|
||||
$this->summary_name_field();
|
||||
|
||||
return $this->summary_basics();
|
||||
}
|
||||
|
||||
function summary_argument($data) {
|
||||
$value = $data->{$this->base_alias};
|
||||
if (empty($value)) {
|
||||
$value = 0;
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override for specific title lookups.
|
||||
*/
|
||||
function title_query() {
|
||||
return $this->value;
|
||||
}
|
||||
}
|
||||
|
59
modules/views/handlers/views_handler_argument_null.inc
Normal file
59
modules/views/handlers/views_handler_argument_null.inc
Normal file
|
@ -0,0 +1,59 @@
|
|||
<?php
|
||||
/**
|
||||
* Argument handler that ignores the argument.
|
||||
*/
|
||||
class views_handler_argument_null extends views_handler_argument {
|
||||
function option_definition() {
|
||||
$options = parent::option_definition();
|
||||
$options['must_not_be'] = array('default' => FALSE);
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override options_form() so that only the relevant options
|
||||
* are displayed to the user.
|
||||
*/
|
||||
function options_form(&$form, &$form_state) {
|
||||
parent::options_form($form, $form_state);
|
||||
$form['must_not_be'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Fail basic validation if any argument is given'),
|
||||
'#default_value' => !empty($this->options['must_not_be']),
|
||||
'#description' => t('By checking this field, you can use this to make sure views with more arguments than necessary fail validation.'),
|
||||
);
|
||||
|
||||
unset($form['wildcard']);
|
||||
unset($form['wildcard_substitution']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Override default_actions() to remove actions that don't
|
||||
* make sense for a null argument.
|
||||
*/
|
||||
function default_actions($which = NULL) {
|
||||
if ($which) {
|
||||
if (in_array($which, array('ignore', 'not found', 'empty', 'default'))) {
|
||||
return parent::default_actions($which);
|
||||
}
|
||||
return;
|
||||
}
|
||||
$actions = parent::default_actions();
|
||||
unset($actions['summary asc']);
|
||||
unset($actions['summary desc']);
|
||||
return $actions;
|
||||
}
|
||||
|
||||
function validate_argument_basic($arg) {
|
||||
if (!empty($this->options['must_not_be'])) {
|
||||
return !isset($arg);
|
||||
}
|
||||
|
||||
return parent::validate_argument_basic($arg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Override the behavior of query() to prevent the query
|
||||
* from being changed in any way.
|
||||
*/
|
||||
function query() {}
|
||||
}
|
95
modules/views/handlers/views_handler_argument_numeric.inc
Normal file
95
modules/views/handlers/views_handler_argument_numeric.inc
Normal file
|
@ -0,0 +1,95 @@
|
|||
<?php
|
||||
/**
|
||||
* @file
|
||||
* Contains the numeric argument handler.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Basic argument handler for arguments that are numeric. Incorporates
|
||||
* break_phrase.
|
||||
*
|
||||
* @ingroup views_argument_handlers
|
||||
*/
|
||||
class views_handler_argument_numeric extends views_handler_argument {
|
||||
function option_definition() {
|
||||
$options = parent::option_definition();
|
||||
|
||||
$options['break_phrase'] = array('default' => FALSE);
|
||||
$options['not'] = array('default' => FALSE);
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
function options_form(&$form, &$form_state) {
|
||||
parent::options_form($form, $form_state);
|
||||
|
||||
// allow + for or, , for and
|
||||
$form['break_phrase'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Allow multiple terms per argument.'),
|
||||
'#description' => t('If selected, users can enter multiple arguments in the form of 1+2+3 or 1,2,3.'),
|
||||
'#default_value' => !empty($this->options['break_phrase']),
|
||||
);
|
||||
|
||||
$form['not'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Exclude the argument'),
|
||||
'#description' => t('If selected, the numbers entered in the argument will be excluded rather than limiting the view.'),
|
||||
'#default_value' => !empty($this->options['not']),
|
||||
);
|
||||
}
|
||||
|
||||
function title() {
|
||||
if (!$this->argument) {
|
||||
return !empty($this->definition['empty field name']) ? $this->definition['empty field name'] : t('Uncategorized');
|
||||
}
|
||||
|
||||
if (!empty($this->options['break_phrase'])) {
|
||||
views_break_phrase($this->argument, $this);
|
||||
}
|
||||
else {
|
||||
$this->value = array($this->argument);
|
||||
$this->operator = 'or';
|
||||
}
|
||||
|
||||
if (empty($this->value)) {
|
||||
return !empty($this->definition['empty field name']) ? $this->definition['empty field name'] : t('Uncategorized');
|
||||
}
|
||||
|
||||
if ($this->value === array(-1)) {
|
||||
return !empty($this->definition['invalid input']) ? $this->definition['invalid input'] : t('Invalid input');
|
||||
}
|
||||
|
||||
return implode($this->operator == 'or' ? ' + ' : ', ', $this->title_query());
|
||||
}
|
||||
|
||||
/**
|
||||
* Override for specific title lookups.
|
||||
*/
|
||||
function title_query() {
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
function query() {
|
||||
$this->ensure_my_table();
|
||||
|
||||
if (!empty($this->options['break_phrase'])) {
|
||||
views_break_phrase($this->argument, $this);
|
||||
}
|
||||
else {
|
||||
$this->value = array($this->argument);
|
||||
}
|
||||
|
||||
$null_check = empty($this->options['not']) ? '' : " OR $this->table_alias.$this->real_field IS NULL";
|
||||
|
||||
if (count($this->value) > 1) {
|
||||
$operator = empty($this->options['not']) ? 'IN' : 'NOT IN';
|
||||
$placeholders = implode(', ', array_fill(0, sizeof($this->value), '%d'));
|
||||
$this->query->add_where(0, "$this->table_alias.$this->real_field $operator ($placeholders) $null_check", $this->value);
|
||||
}
|
||||
else {
|
||||
$operator = empty($this->options['not']) ? '=' : '!=';
|
||||
$this->query->add_where(0, "$this->table_alias.$this->real_field $operator %d $null_check", $this->argument);
|
||||
}
|
||||
}
|
||||
}
|
240
modules/views/handlers/views_handler_argument_string.inc
Normal file
240
modules/views/handlers/views_handler_argument_string.inc
Normal file
|
@ -0,0 +1,240 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Basic argument handler to implement string arguments that may have length
|
||||
* limits.
|
||||
*
|
||||
* @ingroup views_argument_handlers
|
||||
*/
|
||||
class views_handler_argument_string extends views_handler_argument {
|
||||
function init(&$view, $options) {
|
||||
parent::init($view, $options);
|
||||
if (!empty($this->definition['many to one'])) {
|
||||
$this->helper = new views_many_to_one_helper($this);
|
||||
|
||||
// Ensure defaults for these, during summaries and stuff:
|
||||
$this->operator = 'or';
|
||||
$this->value = array();
|
||||
}
|
||||
}
|
||||
|
||||
function option_definition() {
|
||||
$options = parent::option_definition();
|
||||
|
||||
$options['glossary'] = array('default' => FALSE);
|
||||
$options['ignorecase'] = array('default' => FALSE);
|
||||
$options['limit'] = array('default' => 0);
|
||||
$options['case'] = array('default' => 'none');
|
||||
$options['path_case'] = array('default' => 'none');
|
||||
$options['transform_dash'] = array('default' => FALSE);
|
||||
|
||||
if (!empty($this->definition['many to one'])) {
|
||||
$options['add_table'] = array('default' => FALSE);
|
||||
$options['require_value'] = array('default' => FALSE);
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
function options_form(&$form, &$form_state) {
|
||||
parent::options_form($form, $form_state);
|
||||
|
||||
$form['glossary'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Glossary mode'),
|
||||
'#description' => t('Glossary mode applies a limit to the number of characters used in the argument, which allows the summary view to act as a glossary.'),
|
||||
'#default_value' => $this->options['glossary'],
|
||||
);
|
||||
|
||||
$form['ignorecase'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Ignore case'),
|
||||
'#description' => t('Ignore case allows for doing database searches without case sensitivity. MySQL already works in lower-case mode, so MySQL users should leave this unchecked to improve performance.'),
|
||||
'#default_value' => $this->options['ignorecase'],
|
||||
);
|
||||
|
||||
$form['limit'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Character limit'),
|
||||
'#description' => t('How many characters of the argument to filter against. If set to 1, all fields starting with the letter in the argument would be matched.'),
|
||||
'#default_value' => $this->options['limit'],
|
||||
'#process' => array('views_process_dependency'),
|
||||
'#dependency' => array('edit-options-glossary' => array(TRUE)),
|
||||
);
|
||||
|
||||
$form['case'] = array(
|
||||
'#type' => 'select',
|
||||
'#title' => t('Case'),
|
||||
'#description' => t('When printing the argument result, how to transform the case.'),
|
||||
'#options' => array(
|
||||
'none' => t('No transform'),
|
||||
'upper' => t('Upper case'),
|
||||
'lower' => t('Lower case'),
|
||||
'ucfirst' => t('Capitalize first letter'),
|
||||
'ucwords' => t('Capitalize each word'),
|
||||
),
|
||||
'#default_value' => $this->options['case'],
|
||||
);
|
||||
|
||||
$form['path_case'] = array(
|
||||
'#type' => 'select',
|
||||
'#title' => t('Case in path'),
|
||||
'#description' => t('When printing url paths, how to transform the case of the argument. Do not use this unless with Postgres as it uses case sensitive comparisons.'),
|
||||
'#options' => array(
|
||||
'none' => t('No transform'),
|
||||
'upper' => t('Upper case'),
|
||||
'lower' => t('Lower case'),
|
||||
'ucfirst' => t('Capitalize first letter'),
|
||||
'ucwords' => t('Capitalize each word'),
|
||||
),
|
||||
'#default_value' => $this->options['path_case'],
|
||||
);
|
||||
|
||||
$form['transform_dash'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Transform spaces to dashes in URL'),
|
||||
'#default_value' => $this->options['transform_dash'],
|
||||
);
|
||||
|
||||
if (!empty($this->definition['many to one'])) {
|
||||
$form['add_table'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Allow multiple arguments to work together.'),
|
||||
'#description' => t('If selected, multiple instances of this argument can work together, as though multiple terms were supplied to the same argument. This setting is not compatible with the "Reduce duplicates" setting.'),
|
||||
'#default_value' => !empty($this->options['add_table']),
|
||||
);
|
||||
|
||||
$form['require_value'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Do not display items with no value in summary'),
|
||||
'#default_value' => !empty($this->options['require_value']),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the summary query based on a string
|
||||
*/
|
||||
function summary_query() {
|
||||
if (empty($this->definition['many to one'])) {
|
||||
$this->ensure_my_table();
|
||||
}
|
||||
else {
|
||||
$this->table_alias = $this->helper->summary_join();
|
||||
}
|
||||
|
||||
if (empty($this->options['glossary'])) {
|
||||
// Add the field.
|
||||
if (empty($this->options['ignorecase'])){
|
||||
$this->base_alias = $this->name_alias = $this->query->add_field($this->table_alias, $this->real_field);
|
||||
$this->query->set_count_field($this->table_alias, $this->real_field);
|
||||
}
|
||||
else {
|
||||
$this->base_alias = $this->name_alias = $this->query->add_field($this->table_alias, 'LOWER(' . $this->real_field . ')');
|
||||
$this->query->set_count_field($this->table_alias, 'LOWER(' . $this->real_field . ')');
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Add the field.
|
||||
$formula = $this->get_formula();
|
||||
if (empty($this->options['ignorecase'])){
|
||||
$this->base_alias = $this->name_alias = $this->query->add_field(NULL, $formula, $this->field . '_truncated');
|
||||
$this->query->set_count_field(NULL, $formula, $this->field, $this->field . '_truncated');
|
||||
}
|
||||
else {
|
||||
$this->base_alias = $this->name_alias = $this->query->add_field(NULL, 'LOWER(' . $formula . ')', $this->field . '_truncated');
|
||||
$this->query->set_count_field(NULL, $formula, $this->field, $this->field . '_truncated');
|
||||
}
|
||||
}
|
||||
|
||||
return $this->summary_basics(FALSE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the formula for this argument.
|
||||
*
|
||||
* $this->ensure_my_table() MUST have been called prior to this.
|
||||
*/
|
||||
function get_formula() {
|
||||
return "SUBSTR($this->table_alias.$this->real_field, 1, " . intval($this->options['limit']) . ")";
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the query based upon the formula
|
||||
*/
|
||||
function query() {
|
||||
$argument = $this->argument;
|
||||
if (!empty($this->options['transform_dash'])) {
|
||||
$argument = strtr($argument, '-', ' ');
|
||||
}
|
||||
|
||||
if (!empty($this->definition['many to one'])) {
|
||||
if (!empty($this->options['glossary'])) {
|
||||
$this->helper->formula = TRUE;
|
||||
}
|
||||
$this->value = array($argument);
|
||||
$this->helper->ensure_my_table();
|
||||
$this->helper->add_filter();
|
||||
return;
|
||||
}
|
||||
|
||||
$this->ensure_my_table();
|
||||
if (empty($this->options['glossary'])) {
|
||||
$field = "$this->table_alias.$this->real_field";
|
||||
}
|
||||
else {
|
||||
$field = $this->get_formula();
|
||||
}
|
||||
|
||||
if (empty($this->options['ignorecase'])){
|
||||
$this->query->add_where(0, "$field = '%s'", $argument);
|
||||
}
|
||||
else {
|
||||
$this->query->add_where(0, "LOWER($field) = LOWER('%s')", $argument);
|
||||
}
|
||||
}
|
||||
|
||||
function summary_argument($data) {
|
||||
$value = $this->case_transform($data->{$this->base_alias}, 'path_case');
|
||||
if (!empty($this->options['transform_dash'])) {
|
||||
$value = strtr($value, ' ', '-');
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
function case_transform($string, $option) {
|
||||
global $multibyte;
|
||||
|
||||
switch ($this->options[$option]) {
|
||||
default:
|
||||
return $string;
|
||||
case 'upper':
|
||||
return drupal_strtoupper($string);
|
||||
case 'lower':
|
||||
return drupal_strtolower($string);
|
||||
case 'ucfirst':
|
||||
return drupal_strtoupper(drupal_substr($string, 0, 1)) . drupal_substr($string, 1);
|
||||
case 'ucwords':
|
||||
if ($multibyte == UNICODE_MULTIBYTE) {
|
||||
return mb_convert_case($string, MB_CASE_TITLE);
|
||||
} else {
|
||||
return ucwords($string);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function title() {
|
||||
$title = $this->case_transform($this->argument, 'case');
|
||||
if (!empty($this->options['transform_dash'])) {
|
||||
$title = strtr($title, '-', ' ');
|
||||
}
|
||||
|
||||
return check_plain($title);
|
||||
}
|
||||
|
||||
function summary_name($data) {
|
||||
return $this->case_transform(parent::summary_name($data), 'case');
|
||||
}
|
||||
|
||||
}
|
||||
|
859
modules/views/handlers/views_handler_field.inc
Normal file
859
modules/views/handlers/views_handler_field.inc
Normal file
|
@ -0,0 +1,859 @@
|
|||
<?php
|
||||
/**
|
||||
* @defgroup views_field_handlers Views' field handlers
|
||||
* @{
|
||||
* Handlers to tell Views how to build and display fields.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Base field handler that has no options and renders an unformatted field.
|
||||
*
|
||||
* Definition terms:
|
||||
* - additional fields: An array of fields that should be added to the query
|
||||
* for some purpose. The array is in the form of:
|
||||
* array('identifier' => array('table' => tablename,
|
||||
* 'field' => fieldname); as many fields as are necessary
|
||||
* may be in this array.
|
||||
* - click sortable: If TRUE, this field may be click sorted.
|
||||
*/
|
||||
class views_handler_field extends views_handler {
|
||||
var $field_alias = 'unknown';
|
||||
var $aliases = array();
|
||||
|
||||
/**
|
||||
* Construct a new field handler.
|
||||
*/
|
||||
function construct() {
|
||||
parent::construct();
|
||||
|
||||
$this->additional_fields = array();
|
||||
if (!empty($this->definition['additional fields'])) {
|
||||
$this->additional_fields = $this->definition['additional fields'];
|
||||
}
|
||||
|
||||
if (!isset($this->options['exclude'])) {
|
||||
$this->options['exclude'] = '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if this field can allow advanced rendering.
|
||||
*
|
||||
* Fields can set this to FALSE if they do not wish to allow
|
||||
* token based rewriting or link-making.
|
||||
*/
|
||||
function allow_advanced_render() {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
function init(&$view, $options) {
|
||||
parent::init($view, $options);
|
||||
|
||||
$this->options += array(
|
||||
'exclude' => FALSE,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called to add the field to a query.
|
||||
*/
|
||||
function query() {
|
||||
$this->ensure_my_table();
|
||||
// Add the field.
|
||||
$this->field_alias = $this->query->add_field($this->table_alias, $this->real_field);
|
||||
|
||||
$this->add_additional_fields();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add 'additional' fields to the query.
|
||||
*
|
||||
* @param $fields
|
||||
* An array of fields. The key is an identifier used to later find the
|
||||
* field alias used. The value is either a string in which case it's
|
||||
* assumed to be a field on this handler's table; or it's an array in the
|
||||
* form of
|
||||
* @code array('table' => $tablename, 'field' => $fieldname) @endcode
|
||||
*/
|
||||
function add_additional_fields($fields = NULL) {
|
||||
if (!isset($fields)) {
|
||||
// notice check
|
||||
if (empty($this->additional_fields)) {
|
||||
return;
|
||||
}
|
||||
$fields = $this->additional_fields;
|
||||
}
|
||||
if (!empty($fields) && is_array($fields)) {
|
||||
foreach ($fields as $identifier => $info) {
|
||||
if (is_array($info)) {
|
||||
if (isset($info['table'])) {
|
||||
$table_alias = $this->query->ensure_table($info['table'], $this->relationship);
|
||||
}
|
||||
else {
|
||||
$table_alias = $this->table_alias;
|
||||
}
|
||||
if (empty($table_alias)) {
|
||||
vpr(t('Handler @handler tried to add additional_field @identifier but @table could not be added!', array('@handler' => $this->definition['handler'], '@identifier' => $identifier, '@table' => $info['table'])));
|
||||
$this->aliases[$identifier] = 'broken';
|
||||
continue;
|
||||
}
|
||||
$this->aliases[$identifier] = $this->query->add_field($table_alias, $info['field']);
|
||||
}
|
||||
else {
|
||||
$this->aliases[$info] = $this->query->add_field($this->table_alias, $info);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called to determine what to tell the clicksorter.
|
||||
*/
|
||||
function click_sort($order) {
|
||||
$this->query->add_orderby($this->table_alias, $this->real_field, $order, $this->field_alias);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if this field is click sortable.
|
||||
*/
|
||||
function click_sortable() {
|
||||
return !empty($this->definition['click sortable']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get this field's label.
|
||||
*/
|
||||
function label() {
|
||||
if (!isset($this->options['label'])) {
|
||||
return '';
|
||||
}
|
||||
return $this->options['label'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return DIV or SPAN based upon the field's element type.
|
||||
*/
|
||||
function element_type() {
|
||||
if (isset($this->definition['element type'])) {
|
||||
return $this->definition['element type'];
|
||||
}
|
||||
|
||||
return 'span';
|
||||
}
|
||||
|
||||
function option_definition() {
|
||||
$options = parent::option_definition();
|
||||
|
||||
$options['label'] = array('default' => $this->definition['title'], 'translatable' => TRUE);
|
||||
$options['alter'] = array(
|
||||
'contains' => array(
|
||||
'alter_text' => array('default' => FALSE),
|
||||
'text' => array('default' => '', 'translatable' => TRUE),
|
||||
'make_link' => array('default' => FALSE),
|
||||
'path' => array('default' => '', 'translatable' => TRUE),
|
||||
'absolute' => array('default' => '', 'translatable' => FALSE),
|
||||
'alt' => array('default' => '', 'translatable' => TRUE),
|
||||
'rel' => array('default' => ''),
|
||||
'link_class' => array('default' => ''),
|
||||
'prefix' => array('default' => '', 'translatable' => TRUE),
|
||||
'suffix' => array('default' => '', 'translatable' => TRUE),
|
||||
'target' => array('default' => '', 'translatable' => TRUE),
|
||||
'trim' => array('default' => FALSE),
|
||||
'max_length' => array('default' => ''),
|
||||
'word_boundary' => array('default' => TRUE),
|
||||
'ellipsis' => array('default' => TRUE),
|
||||
'strip_tags' => array('default' => FALSE),
|
||||
'html' => array('default' => FALSE),
|
||||
),
|
||||
);
|
||||
$options['empty'] = array('default' => '', 'translatable' => TRUE);
|
||||
$options['hide_empty'] = array('default' => FALSE);
|
||||
$options['empty_zero'] = array('default' => FALSE);
|
||||
$options['hide_alter_empty'] = array('default' => TRUE);
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Default options form that provides the label widget that all fields
|
||||
* should have.
|
||||
*/
|
||||
function options_form(&$form, &$form_state) {
|
||||
$form['label'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Label'),
|
||||
'#default_value' => isset($this->options['label']) ? $this->options['label'] : '',
|
||||
'#description' => t('The label for this field that will be displayed to end users if the style requires it.'),
|
||||
);
|
||||
$form['exclude'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Exclude from display'),
|
||||
'#default_value' => $this->options['exclude'],
|
||||
'#description' => t('Check this box to not display this field, but still load it in the view. Use this option to not show a grouping field in each record, or when doing advanced theming.'),
|
||||
);
|
||||
|
||||
if ($this->allow_advanced_render()) {
|
||||
$form['alter']['#tree'] = TRUE;
|
||||
$form['alter']['alter_text'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Rewrite the output of this field'),
|
||||
'#description' => t('If checked, you can alter the output of this field by specifying a string of text with replacement tokens that can use any existing field output.'),
|
||||
'#default_value' => $this->options['alter']['alter_text'],
|
||||
);
|
||||
|
||||
$form['alter']['text'] = array(
|
||||
'#title' => t('Text'),
|
||||
'#type' => 'textarea',
|
||||
'#default_value' => $this->options['alter']['text'],
|
||||
'#description' => t('The text to display for this field. You may include HTML. You may enter data from this view as per the "Replacement patterns" below.'),
|
||||
'#process' => array('views_process_dependency'),
|
||||
'#dependency' => array(
|
||||
'edit-options-alter-alter-text' => array(1)
|
||||
),
|
||||
);
|
||||
|
||||
$form['alter']['make_link'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Output this field as a link'),
|
||||
'#description' => t('If checked, this field will be made into a link. The destination must be given below.'),
|
||||
'#default_value' => $this->options['alter']['make_link'],
|
||||
);
|
||||
$form['alter']['path'] = array(
|
||||
'#title' => t('Link path'),
|
||||
'#type' => 'textfield',
|
||||
'#default_value' => $this->options['alter']['path'],
|
||||
'#description' => t('The Drupal path or absolute URL for this link. You may enter data from this view as per the "Replacement patterns" below.'),
|
||||
'#process' => array('views_process_dependency'),
|
||||
'#dependency' => array(
|
||||
'edit-options-alter-make-link' => array(1)
|
||||
),
|
||||
'#maxlength' => 255,
|
||||
);
|
||||
$form['alter']['absolute'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Use absolute path'),
|
||||
'#default_value' => $this->options['alter']['absolute'],
|
||||
'#process' => array('views_process_dependency'),
|
||||
'#dependency' => array(
|
||||
'edit-options-alter-make-link' => array(1)
|
||||
),
|
||||
);
|
||||
|
||||
$form['alter']['link_class'] = array(
|
||||
'#title' => t('Link class'),
|
||||
'#type' => 'textfield',
|
||||
'#default_value' => $this->options['alter']['link_class'],
|
||||
'#description' => t('The CSS class to apply to the link.'),
|
||||
'#process' => array('views_process_dependency'),
|
||||
'#dependency' => array(
|
||||
'edit-options-alter-make-link' => array(1)
|
||||
),
|
||||
);
|
||||
$form['alter']['alt'] = array(
|
||||
'#title' => t('Alt text'),
|
||||
'#type' => 'textfield',
|
||||
'#default_value' => $this->options['alter']['alt'],
|
||||
'#description' => t('Text to place as "alt" text which most browsers display as a tooltip when hovering over the link.'),
|
||||
'#process' => array('views_process_dependency'),
|
||||
'#dependency' => array(
|
||||
'edit-options-alter-make-link' => array(1)
|
||||
),
|
||||
);
|
||||
$form['alter']['rel'] = array(
|
||||
'#title' => t('Rel Text'),
|
||||
'#type' => 'textfield',
|
||||
'#default_value' => $this->options['alter']['rel'],
|
||||
'#description' => t('Include Rel attribute for use in lightbox2 or other javascript utility.'),
|
||||
'#process' => array('views_process_dependency'),
|
||||
'#dependency' => array(
|
||||
'edit-options-alter-make-link' => array(1)
|
||||
),
|
||||
);
|
||||
$form['alter']['prefix'] = array(
|
||||
'#title' => t('Prefix text'),
|
||||
'#type' => 'textfield',
|
||||
'#default_value' => $this->options['alter']['prefix'],
|
||||
'#description' => t('Any text to display before this link. You may include HTML.'),
|
||||
'#process' => array('views_process_dependency'),
|
||||
'#dependency' => array(
|
||||
'edit-options-alter-make-link' => array(1)
|
||||
),
|
||||
);
|
||||
$form['alter']['suffix'] = array(
|
||||
'#title' => t('Suffix text'),
|
||||
'#type' => 'textfield',
|
||||
'#default_value' => $this->options['alter']['suffix'],
|
||||
'#description' => t('Any text to display after this link. You may include HTML.'),
|
||||
'#process' => array('views_process_dependency'),
|
||||
'#dependency' => array(
|
||||
'edit-options-alter-make-link' => array(1)
|
||||
),
|
||||
);
|
||||
$form['alter']['target'] = array(
|
||||
'#title' => t('Target'),
|
||||
'#type' => 'textfield',
|
||||
'#default_value' => $this->options['alter']['target'],
|
||||
'#description' => t("Target of the link, such as _blank, _parent or an iframe's name. This field is rarely used."),
|
||||
'#process' => array('views_process_dependency'),
|
||||
'#dependency' => array(
|
||||
'edit-options-alter-make-link' => array(1)
|
||||
),
|
||||
);
|
||||
|
||||
|
||||
// Get a list of the available fields and arguments for token replacement.
|
||||
$options = array();
|
||||
foreach ($this->view->display_handler->get_handlers('field') as $field => $handler) {
|
||||
$options[t('Fields')]["[$field]"] = $handler->ui_name();
|
||||
// We only use fields up to (and including) this one.
|
||||
if ($field == $this->options['id']) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
$count = 0; // This lets us prepare the key as we want it printed.
|
||||
foreach ($this->view->display_handler->get_handlers('argument') as $arg => $handler) {
|
||||
$options[t('Arguments')]['%' . ++$count] = t('@argument title', array('@argument' => $handler->ui_name()));
|
||||
$options[t('Arguments')]['!' . $count] = t('@argument input', array('@argument' => $handler->ui_name()));
|
||||
}
|
||||
|
||||
$this->document_self_tokens($options[t('Fields')]);
|
||||
|
||||
// Default text.
|
||||
$output = t('<p>You must add some additional fields to this display before using this field. These fields may be marked as <em>Exclude from display</em> if you prefer. Note that due to rendering order, you cannot use fields that come after this field; if you need a field not listed here, rearrange your fields.</p>');
|
||||
// We have some options, so make a list.
|
||||
if (!empty($options)) {
|
||||
$output = t('<p>The following tokens are available for this field. Note that due to rendering order, you cannot use fields that come after this field; if you need a field not listed here, rearrange your fields.
|
||||
If you would like to have the characters %5B and %5D please use the html entity codes \'%5B\' or \'%5D\' or they will get replaced with empty space.</p>');
|
||||
foreach (array_keys($options) as $type) {
|
||||
if (!empty($options[$type])) {
|
||||
$items = array();
|
||||
foreach ($options[$type] as $key => $value) {
|
||||
$items[] = $key . ' == ' . $value;
|
||||
}
|
||||
$output .= theme('item_list', $items, $type);
|
||||
}
|
||||
}
|
||||
}
|
||||
// This construct uses 'hidden' and not markup because process doesn't
|
||||
// run. It also has an extra div because the dependency wants to hide
|
||||
// the parent in situations like this, so we need a second div to
|
||||
// make this work.
|
||||
$form['alter']['help'] = array(
|
||||
'#type' => 'hidden',
|
||||
'#id' => 'views-tokens-help',
|
||||
'#prefix' => '<div><fieldset id="views-tokens-help"><legend>' . t('Replacement patterns') . '</legend>' . $output . '</fieldset></div>',
|
||||
'#process' => array('views_process_dependency'),
|
||||
'#dependency' => array(
|
||||
'edit-options-alter-make-link' => array(1),
|
||||
'edit-options-alter-alter-text' => array(1),
|
||||
),
|
||||
);
|
||||
|
||||
$form['alter']['trim'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Trim this field to a maximum length'),
|
||||
'#description' => t('If checked, this field be trimmed to a maximum length in characters.'),
|
||||
'#default_value' => $this->options['alter']['trim'],
|
||||
);
|
||||
|
||||
$form['alter']['max_length'] = array(
|
||||
'#title' => t('Maximum length'),
|
||||
'#type' => 'textfield',
|
||||
'#default_value' => $this->options['alter']['max_length'],
|
||||
'#description' => t('The maximum number of characters this field can be.'),
|
||||
'#process' => array('views_process_dependency'),
|
||||
'#dependency' => array(
|
||||
'edit-options-alter-trim' => array(1)
|
||||
),
|
||||
);
|
||||
|
||||
$form['alter']['word_boundary'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Trim only on a word boundary'),
|
||||
'#description' => t('If checked, this field be trimmed only on a word boundary. This is guaranteed to be the maximum characters stated or less. If there are no word boundaries this could trim a field to nothing.'),
|
||||
'#default_value' => $this->options['alter']['word_boundary'],
|
||||
'#process' => array('views_process_dependency'),
|
||||
'#dependency' => array(
|
||||
'edit-options-alter-trim' => array(1)
|
||||
),
|
||||
);
|
||||
|
||||
$form['alter']['ellipsis'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Add an ellipsis'),
|
||||
'#description' => t('If checked, a "..." will be added if a field was trimmed.'),
|
||||
'#default_value' => $this->options['alter']['ellipsis'],
|
||||
'#process' => array('views_process_dependency'),
|
||||
'#dependency' => array(
|
||||
'edit-options-alter-trim' => array(1)
|
||||
),
|
||||
);
|
||||
|
||||
$form['alter']['html'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Field can contain HTML'),
|
||||
'#description' => t('If checked, HTML corrector will be run to ensure tags are properly closed after trimming.'),
|
||||
'#default_value' => $this->options['alter']['html'],
|
||||
'#process' => array('views_process_dependency'),
|
||||
'#dependency' => array(
|
||||
'edit-options-alter-trim' => array(1)
|
||||
),
|
||||
);
|
||||
|
||||
$form['alter']['strip_tags'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Strip HTML tags'),
|
||||
'#description' => t('If checked, all HTML tags will be stripped.'),
|
||||
'#default_value' => $this->options['alter']['strip_tags'],
|
||||
'#process' => array('views_process_dependency'),
|
||||
);
|
||||
}
|
||||
|
||||
$form['empty'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Empty text'),
|
||||
'#default_value' => $this->options['empty'],
|
||||
'#description' => t('If the field is empty, display this text instead.'),
|
||||
);
|
||||
|
||||
$form['empty_zero'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Count the number 0 as empty'),
|
||||
'#default_value' => $this->options['empty_zero'],
|
||||
'#description' => t('If the field contains the number zero, display the empty text instead'),
|
||||
);
|
||||
|
||||
$form['hide_empty'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Hide if empty'),
|
||||
'#default_value' => $this->options['hide_empty'],
|
||||
'#description' => t('Enable to hide this field if it is empty. Note that the field label or rewritten output may still be displayed. To hide labels, check the style or row style settings for empty fields. To hide rewritten content, check the Hide rewriting if empty checkbox.'),
|
||||
);
|
||||
|
||||
$form['hide_alter_empty'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Do not rewrite if empty'),
|
||||
'#default_value' => $this->options['hide_alter_empty'],
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide extra data to the administration form
|
||||
*/
|
||||
function admin_summary() {
|
||||
return $this->label();
|
||||
}
|
||||
|
||||
/**
|
||||
* Run before any fields are rendered.
|
||||
*
|
||||
* This gives the handlers some time to set up before any handler has
|
||||
* been rendered.
|
||||
*
|
||||
* @param $values
|
||||
* An array of all objects returned from the query.
|
||||
*/
|
||||
function pre_render($values) { }
|
||||
|
||||
/**
|
||||
* Render the field.
|
||||
*
|
||||
* @param $values
|
||||
* The values retrieved from the database.
|
||||
*/
|
||||
function render($values) {
|
||||
$value = $values->{$this->field_alias};
|
||||
return check_plain($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a field using advanced settings.
|
||||
*
|
||||
* This renders a field normally, then decides if render-as-link and
|
||||
* text-replacement rendering is necessary.
|
||||
*/
|
||||
function advanced_render($values) {
|
||||
if ($this->allow_advanced_render() && method_exists($this, 'render_item')) {
|
||||
$raw_items = $this->get_items($values);
|
||||
}
|
||||
else {
|
||||
$this->last_render = $value = $this->render($values);
|
||||
$this->original_value = $value;
|
||||
}
|
||||
|
||||
if ($this->allow_advanced_render()) {
|
||||
$tokens = NULL;
|
||||
if (method_exists($this, 'render_item')) {
|
||||
$items = array();
|
||||
foreach ($raw_items as $count => $item) {
|
||||
$this->last_render = $this->render_item($count, $item);
|
||||
$this->original_value = $this->last_render;
|
||||
|
||||
$alter = $item + $this->options['alter'];
|
||||
$items[] = $this->render_text($alter);
|
||||
}
|
||||
|
||||
$value = $this->render_items($items);
|
||||
}
|
||||
else {
|
||||
$value = $this->render_text($this->options['alter']);
|
||||
}
|
||||
|
||||
// This happens here so that render_as_link can get the unaltered value of
|
||||
// this field as a token rather than the altered value.
|
||||
$this->last_render = $value;
|
||||
}
|
||||
|
||||
if (empty($this->last_render)) {
|
||||
if (($this->last_render !== 0 && $this->last_render !== '0') || !empty($this->options['empty_zero'])) {
|
||||
$alter = $this->options['alter'];
|
||||
$alter['alter_text'] = 1;
|
||||
$alter['text'] = $this->options['empty'];
|
||||
$this->last_render = $this->render_text($alter);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->last_render;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform an advanced text render for the item.
|
||||
*
|
||||
* This is separated out as some fields may render lists, and this allows
|
||||
* each item to be handled individually.
|
||||
*/
|
||||
function render_text($alter) {
|
||||
$value = trim($this->last_render);
|
||||
|
||||
if (!empty($alter['alter_text']) && $alter['text'] !== '') {
|
||||
$tokens = $this->get_render_tokens($alter);
|
||||
$value = $this->render_altered($alter, $tokens);
|
||||
}
|
||||
|
||||
if ((($this->options['hide_empty'] && empty($value)) || ($this->options['hide_alter_empty'] && empty($this->original_value))) && ($value !== 0 || $this->options['empty_zero'])) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if (!empty($alter['strip_tags'])) {
|
||||
$value = strip_tags($value);
|
||||
}
|
||||
|
||||
if (!empty($alter['trim']) && !empty($alter['max_length'])) {
|
||||
$value = $this->render_trim_text($alter, $value);
|
||||
}
|
||||
|
||||
if (!empty($alter['make_link']) && !empty($alter['path'])) {
|
||||
if (!isset($tokens)) {
|
||||
$tokens = $this->get_render_tokens($alter);
|
||||
}
|
||||
$value = $this->render_as_link($alter, $value, $tokens);
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render this field as altered text, from a fieldset set by the user.
|
||||
*/
|
||||
function render_altered($alter, $tokens) {
|
||||
// Filter this right away as our substitutions are already sanitized.
|
||||
$value = filter_xss_admin($alter['text']);
|
||||
$value = strtr($value, $tokens);
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Trim the field down to the specified length.
|
||||
*/
|
||||
function render_trim_text($alter, $value) {
|
||||
if (!empty($alter['strip_tags'])) {
|
||||
// NOTE: It's possible that some external fields might override the
|
||||
// element type so if someone from, say, CCK runs into a bug here,
|
||||
// this may be why =)
|
||||
$this->definition['element type'] = 'span';
|
||||
}
|
||||
return views_trim_text($alter, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render this field as a link, with the info from a fieldset set by
|
||||
* the user.
|
||||
*/
|
||||
function render_as_link($alter, $text, $tokens) {
|
||||
$value = '';
|
||||
|
||||
if (!empty($alter['prefix'])) {
|
||||
$value .= filter_xss_admin(strtr($alter['prefix'], $tokens));
|
||||
}
|
||||
|
||||
$options = array(
|
||||
'html' => TRUE,
|
||||
'absolute' => !empty($alter['absolute']) ? TRUE : FALSE,
|
||||
);
|
||||
|
||||
// $path will be run through check_url() by l() so we do not need to
|
||||
// sanitize it ourselves.
|
||||
$path = $alter['path'];
|
||||
|
||||
// html_entity_decode removes <front>, so check whether its different to front.
|
||||
if ($path != '<front>') {
|
||||
// Use strip tags as there should never be HTML in the path.
|
||||
// However, we need to preserve special characters like " that
|
||||
// were removed by check_plain().
|
||||
$path = strip_tags(html_entity_decode(strtr($path, $tokens)));
|
||||
}
|
||||
|
||||
// If the path is empty do not build a link around the given text and return
|
||||
// it as is.
|
||||
if (empty($path)) {
|
||||
return $text;
|
||||
}
|
||||
|
||||
// Parse the URL and move any query and fragment parameters out of the path.
|
||||
$url = parse_url($path);
|
||||
if (isset($url['query'])) {
|
||||
$path = strtr($path, array('?' . $url['query'] => ''));
|
||||
$options['query'] = $url['query'];
|
||||
}
|
||||
if (isset($url['fragment'])) {
|
||||
$path = strtr($path, array('#' . $url['fragment'] => ''));
|
||||
// If the path is empty we want to have a fragment for the current site.
|
||||
if ($path == '') {
|
||||
$options['external'] = TRUE;
|
||||
}
|
||||
$options['fragment'] = $url['fragment'];
|
||||
}
|
||||
|
||||
$alt = strtr($alter['alt'], $tokens);
|
||||
// Set the title attribute of the link only if it improves accessibility
|
||||
if ($alt && $alt != $text) {
|
||||
$options['attributes']['title'] = html_entity_decode($alt, ENT_QUOTES);
|
||||
}
|
||||
|
||||
$class = strtr($alter['link_class'], $tokens);
|
||||
if ($class) {
|
||||
$options['attributes']['class'] = $class;
|
||||
}
|
||||
|
||||
if (!empty($alter['rel']) && $rel = strtr($alter['rel'], $tokens)) {
|
||||
$options['attributes']['rel'] = $rel;
|
||||
}
|
||||
|
||||
$target = check_plain(trim(strtr($alter['target'],$tokens)));
|
||||
if (!empty($target)) {
|
||||
$options['attributes']['target'] = $target;
|
||||
}
|
||||
|
||||
// Allow the addition of arbitrary attributes to links. Additional attributes
|
||||
// currently can only be altered in preprocessors and not within the UI.
|
||||
if (isset($alter['link_attributes']) && is_array($alter['link_attributes'])) {
|
||||
foreach ($alter['link_attributes'] as $key => $attribute) {
|
||||
if (!isset($options['attributes'][$key])) {
|
||||
$options['attributes'][$key] = strtr($attribute, $tokens);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If the query and fragment were programatically assigned overwrite any
|
||||
// parsed values.
|
||||
if (isset($alter['query'])) {
|
||||
$options['query'] = strtr($alter['query'], $tokens);
|
||||
}
|
||||
if (isset($alter['alias'])) {
|
||||
// Alias is a boolean field, so no token.
|
||||
$options['alias'] = $alter['alias'];
|
||||
}
|
||||
if (isset($alter['fragment'])) {
|
||||
$options['fragment'] = strtr($alter['fragment'], $tokens);
|
||||
}
|
||||
if (isset($this->options['alter']['language'])) {
|
||||
$options['language'] = $this->options['alter']['language'];
|
||||
}
|
||||
|
||||
$value .= l($text, $path, $options);
|
||||
|
||||
if (!empty($alter['suffix'])) {
|
||||
$value .= filter_xss_admin(strtr($alter['suffix'], $tokens));
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the 'render' tokens to use for advanced rendering.
|
||||
*
|
||||
* This runs through all of the fields and arguments that
|
||||
* are available and gets their values. This will then be
|
||||
* used in one giant str_replace().
|
||||
*/
|
||||
function get_render_tokens($item) {
|
||||
$tokens = array();
|
||||
if (!empty($this->view->build_info['substitutions'])) {
|
||||
$tokens = $this->view->build_info['substitutions'];
|
||||
}
|
||||
$count = 0;
|
||||
foreach ($this->view->display_handler->get_handlers('argument') as $arg => $handler) {
|
||||
$token = '%' . ++$count;
|
||||
if (!isset($tokens[$token])) {
|
||||
$tokens[$token] = '';
|
||||
}
|
||||
|
||||
// Use strip tags as there should never be HTML in the path.
|
||||
// However, we need to preserve special characters like " that
|
||||
// were removed by check_plain().
|
||||
$tokens['!' . $count] = isset($this->view->args[$count - 1]) ? strip_tags(html_entity_decode($this->view->args[$count - 1])) : '';
|
||||
}
|
||||
|
||||
// Now add replacements for our fields.
|
||||
foreach ($this->view->display_handler->get_handlers('field') as $field => $handler) {
|
||||
if (isset($handler->last_render)) {
|
||||
$tokens["[$field]"] = $handler->last_render;
|
||||
}
|
||||
else {
|
||||
$tokens["[$field]"] = '';
|
||||
}
|
||||
$this->add_self_tokens($tokens, $item);
|
||||
|
||||
// We only use fields up to (and including) this one.
|
||||
if ($field == $this->options['id']) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $tokens;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add any special tokens this field might use for itself.
|
||||
*
|
||||
* This method is intended to be overridden by items that generate
|
||||
* fields as a list. For example, the field that displays all terms
|
||||
* on a node might have tokens for the tid and the term.
|
||||
*
|
||||
* By convention, tokens should follow the format of [token-subtoken]
|
||||
* where token is the field ID and subtoken is the field. If the
|
||||
* field ID is terms, then the tokens might be [terms-tid] and [terms-name].
|
||||
*/
|
||||
function add_self_tokens(&$tokens, $item) { }
|
||||
|
||||
/**
|
||||
* Document any special tokens this field might use for itself.
|
||||
*
|
||||
* @see add_self_tokens() for details.
|
||||
*/
|
||||
function document_self_tokens(&$tokens) { }
|
||||
|
||||
/**
|
||||
* Call out to the theme() function, which probably just calls render() but
|
||||
* allows sites to override output fairly easily.
|
||||
*/
|
||||
function theme($values) {
|
||||
return theme($this->theme_functions(), $this->view, $this, $values);
|
||||
}
|
||||
|
||||
function theme_functions() {
|
||||
$themes = array();
|
||||
$hook = 'views_view_field';
|
||||
|
||||
$display = $this->view->display[$this->view->current_display];
|
||||
|
||||
if (!empty($display)) {
|
||||
$themes[] = $hook . '__' . $this->view->name . '__' . $display->id . '__' . $this->options['id'];
|
||||
$themes[] = $hook . '__' . $this->view->name . '__' . $display->id;
|
||||
$themes[] = $hook . '__' . $display->id . '__' . $this->options['id'];
|
||||
$themes[] = $hook . '__' . $display->id;
|
||||
if ($display->id != $display->display_plugin) {
|
||||
$themes[] = $hook . '__' . $this->view->name . '__' . $display->display_plugin . '__' . $this->options['id'];
|
||||
$themes[] = $hook . '__' . $this->view->name . '__' . $display->display_plugin;
|
||||
$themes[] = $hook . '__' . $display->display_plugin . '__' . $this->options['id'];
|
||||
$themes[] = $hook . '__' . $display->display_plugin;
|
||||
}
|
||||
}
|
||||
$themes[] = $hook . '__' . $this->view->name . '__' . $this->options['id'];
|
||||
$themes[] = $hook . '__' . $this->view->name;
|
||||
$themes[] = $hook . '__' . $this->options['id'];
|
||||
$themes[] = $hook;
|
||||
|
||||
return $themes;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A special handler to take the place of missing or broken handlers.
|
||||
*/
|
||||
class views_handler_field_broken extends views_handler_field {
|
||||
function ui_name($short = FALSE) {
|
||||
return t('Broken/missing handler');
|
||||
}
|
||||
|
||||
function ensure_my_table() { /* No table to ensure! */ }
|
||||
function query() { /* No query to run */ }
|
||||
function options_form(&$form, &$form_state) {
|
||||
$form['markup'] = array(
|
||||
'#prefix' => '<div class="form-item description">',
|
||||
'#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.'),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the handler is considered 'broken'
|
||||
*/
|
||||
function broken() { return TRUE; }
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a numeric value as a size.
|
||||
*/
|
||||
class views_handler_field_file_size extends views_handler_field {
|
||||
function option_definition() {
|
||||
$options = parent::option_definition();
|
||||
|
||||
$options['file_size_display'] = array('default' => 'formatted');
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
function options_form(&$form, &$form_state) {
|
||||
parent::options_form($form, $form_state);
|
||||
$form['file_size_display'] = array(
|
||||
'#title' => t('File size display'),
|
||||
'#type' => 'select',
|
||||
'#options' => array(
|
||||
'formatted' => t('Formatted (in KB or MB)'),
|
||||
'bytes' => t('Raw bytes'),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
function render($values) {
|
||||
if ($values->{$this->field_alias}) {
|
||||
switch ($this->options['file_size_display']) {
|
||||
case 'bytes':
|
||||
return $values->{$this->field_alias};
|
||||
case 'formatted':
|
||||
default:
|
||||
return format_size($values->{$this->field_alias});
|
||||
}
|
||||
}
|
||||
else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A handler to run a field through simple XSS filtering
|
||||
*/
|
||||
class views_handler_field_xss extends views_handler_field {
|
||||
function render($values) {
|
||||
$value = $values->{$this->field_alias};
|
||||
return filter_xss($value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
73
modules/views/handlers/views_handler_field_boolean.inc
Normal file
73
modules/views/handlers/views_handler_field_boolean.inc
Normal file
|
@ -0,0 +1,73 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* A handler to provide proper displays for booleans.
|
||||
*
|
||||
* Allows for display of true/false, yes/no, on/off.
|
||||
*
|
||||
* Definition terms:
|
||||
* - output formats: An array where the first entry is displayed on boolean true
|
||||
* and the second is displayed on boolean false. An example for sticky is:
|
||||
* @code
|
||||
* 'output formats' => array(
|
||||
* 'sticky' => array(t('Sticky'), ''),
|
||||
* ),
|
||||
* @endcode
|
||||
*
|
||||
* @ingroup views_field_handlers
|
||||
*/
|
||||
class views_handler_field_boolean extends views_handler_field {
|
||||
function option_definition() {
|
||||
$options = parent::option_definition();
|
||||
$options['type'] = array('default' => 'yes-no');
|
||||
$options['not'] = array('definition bool' => 'reverse');
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
function init(&$view, $options) {
|
||||
parent::init($view, $options);
|
||||
|
||||
$default_formats = array(
|
||||
'yes-no' => array(t('Yes'), t('No')),
|
||||
'true-false' => array(t('True'), t('False')),
|
||||
'on-off' => array(t('On'), t('Off')),
|
||||
);
|
||||
$output_formats = isset($this->definition['output formats']) ? $this->definition['output formats'] : array();
|
||||
$this->formats = array_merge($default_formats, $output_formats);
|
||||
}
|
||||
|
||||
function options_form(&$form, &$form_state) {
|
||||
parent::options_form($form, $form_state);
|
||||
foreach ($this->formats as $key => $item) {
|
||||
$options[$key] = implode('/', $item);
|
||||
}
|
||||
|
||||
$form['type'] = array(
|
||||
'#type' => 'select',
|
||||
'#title' => t('Output format'),
|
||||
'#options' => $options,
|
||||
'#default_value' => $this->options['type'],
|
||||
);
|
||||
$form['not'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Reverse'),
|
||||
'#description' => t('If checked, true will be displayed as false.'),
|
||||
'#default_value' => $this->options['not'],
|
||||
);
|
||||
}
|
||||
|
||||
function render($values) {
|
||||
$value = $values->{$this->field_alias};
|
||||
if (!empty($this->options['not'])) {
|
||||
$value = !$value;
|
||||
}
|
||||
|
||||
if (isset($this->formats[$this->options['type']])) {
|
||||
return $value ? $this->formats[$this->options['type']][0] : $this->formats[$this->options['type']][1];
|
||||
}
|
||||
else {
|
||||
return $value ? $this->formats['yes-no'][0] : $this->formats['yes-no'][1];
|
||||
}
|
||||
}
|
||||
}
|
41
modules/views/handlers/views_handler_field_counter.inc
Normal file
41
modules/views/handlers/views_handler_field_counter.inc
Normal file
|
@ -0,0 +1,41 @@
|
|||
<?php
|
||||
|
||||
class views_handler_field_counter extends views_handler_field {
|
||||
function option_definition() {
|
||||
$options = parent::option_definition();
|
||||
$options['counter_start'] = array('default' => 1);
|
||||
return $options;
|
||||
}
|
||||
|
||||
function options_form(&$form, &$form_state) {
|
||||
parent::options_form($form, $form_state);
|
||||
|
||||
$form['counter_start'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Starting value'),
|
||||
'#default_value' => $this->options['counter_start'],
|
||||
'#description' => t('Specify the number the counter should start at.'),
|
||||
//'#process' => array('views_process_dependency'),
|
||||
'#size' => 2,
|
||||
);
|
||||
}
|
||||
|
||||
function query() {
|
||||
// do nothing -- to override the parent query.
|
||||
}
|
||||
|
||||
function render($values) {
|
||||
// Note: 1 is subtracted from the counter start value below because the
|
||||
// counter value is incremented by 1 at the end of this function.
|
||||
$count = is_numeric($this->options['counter_start']) ? $this->options['counter_start'] - 1 : 0;
|
||||
$pager = $this->view->pager;
|
||||
// Get the base count of the pager.
|
||||
if ($pager['use_pager']) {
|
||||
$count += ($pager['items_per_page'] * $pager['current_page']) + $pager['offset'];
|
||||
}
|
||||
// Add the counter for the current site.
|
||||
$count += $this->view->row_index + 1;
|
||||
|
||||
return $count;
|
||||
}
|
||||
}
|
35
modules/views/handlers/views_handler_field_custom.inc
Normal file
35
modules/views/handlers/views_handler_field_custom.inc
Normal file
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* A handler to provide a field that is completely custom by the administrator.
|
||||
*
|
||||
* @ingroup views_field_handlers
|
||||
*/
|
||||
class views_handler_field_custom extends views_handler_field {
|
||||
function query() {
|
||||
// do nothing -- to override the parent query.
|
||||
}
|
||||
|
||||
function option_definition() {
|
||||
$options = parent::option_definition();
|
||||
|
||||
// Override the alter text option to always alter the text.
|
||||
$options['alter']['contains']['alter_text'] = array('default' => TRUE);
|
||||
$options['hide_alter_empty'] = array('default' => FALSE);
|
||||
return $options;
|
||||
}
|
||||
|
||||
function options_form(&$form, &$form_state) {
|
||||
parent::options_form($form, $form_state);
|
||||
|
||||
// Remove the checkbox
|
||||
unset($form['alter']['alter_text']);
|
||||
unset($form['alter']['text']['#dependency']);
|
||||
unset($form['alter']['text']['#process']);
|
||||
}
|
||||
|
||||
function render($values) {
|
||||
// Return the text, so the code never thinks the value is empty.
|
||||
return $this->options['alter']['text'];
|
||||
}
|
||||
}
|
74
modules/views/handlers/views_handler_field_date.inc
Normal file
74
modules/views/handlers/views_handler_field_date.inc
Normal file
|
@ -0,0 +1,74 @@
|
|||
<?php
|
||||
/**
|
||||
* A handler to provide proper displays for dates.
|
||||
*
|
||||
* @ingroup views_field_handlers
|
||||
*/
|
||||
class views_handler_field_date extends views_handler_field {
|
||||
function option_definition() {
|
||||
$options = parent::option_definition();
|
||||
|
||||
$options['date_format'] = array('default' => 'small');
|
||||
$options['custom_date_format'] = array('default' => '');
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
function options_form(&$form, &$form_state) {
|
||||
parent::options_form($form, $form_state);
|
||||
$time = time();
|
||||
|
||||
$form['date_format'] = array(
|
||||
'#type' => 'select',
|
||||
'#title' => t('Date format'),
|
||||
'#options' => array(
|
||||
'small' => t('Short date format') . ' ' . format_date($time, 'small'),
|
||||
'medium' => t('Medium date format') . ' ' . format_date($time, 'medium'),
|
||||
'large' => t('Long date format') . ' ' . format_date($time, 'large'),
|
||||
'custom' => t('Custom'),
|
||||
'raw time ago' => t('Time ago'),
|
||||
'time ago' => t('Time ago (with "ago" appended)'),
|
||||
'raw time span' => t('Time span (future dates start with - )'),
|
||||
'time span' => t('Time span (with "ago/hence" appended)'),
|
||||
),
|
||||
'#default_value' => isset($this->options['date_format']) ? $this->options['date_format'] : 'small',
|
||||
);
|
||||
$form['custom_date_format'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Custom date format'),
|
||||
'#description' => t('If "Custom", see <a href="http://us.php.net/manual/en/function.date.php" target="_blank">the PHP docs</a> for date formats. If "Time ago", enter the number of different time units to display, which defaults to 2.'),
|
||||
'#default_value' => isset($this->options['custom_date_format']) ? $this->options['custom_date_format'] : '',
|
||||
'#process' => array('views_process_dependency'),
|
||||
'#dependency' => array('edit-options-date-format' => array('custom', 'raw time ago', 'time ago', 'raw time span', 'time span')),
|
||||
);
|
||||
}
|
||||
|
||||
function render($values) {
|
||||
$value = $values->{$this->field_alias};
|
||||
$format = $this->options['date_format'];
|
||||
if (in_array($format, array('custom', 'raw time ago', 'time ago', 'raw time span', 'time span'))) {
|
||||
$custom_format = $this->options['custom_date_format'];
|
||||
}
|
||||
|
||||
if ($value) {
|
||||
$time_diff = time() - $value; // will be positive for a datetime in the past (ago), and negative for a datetime in the future (hence)
|
||||
switch ($format) {
|
||||
case 'raw time ago':
|
||||
return format_interval($time_diff, is_numeric($custom_format) ? $custom_format : 2);
|
||||
case 'time ago':
|
||||
return t('%time ago', array('%time' => format_interval($time_diff, is_numeric($custom_format) ? $custom_format : 2)));
|
||||
case 'raw time span':
|
||||
return ($time_diff < 0 ? '-' : '') . format_interval(abs($time_diff), is_numeric($custom_format) ? $custom_format : 2);
|
||||
case 'time span':
|
||||
return t(($time_diff < 0 ? '%time hence' : '%time ago'), array('%time' => format_interval(abs($time_diff), is_numeric($custom_format) ? $custom_format : 2)));
|
||||
case 'custom':
|
||||
if ($custom_format == 'r') {
|
||||
return format_date($value, $format, $custom_format, null, 'en');
|
||||
}
|
||||
return format_date($value, $format, $custom_format);
|
||||
default:
|
||||
return format_date($value, $format);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
44
modules/views/handlers/views_handler_field_markup.inc
Normal file
44
modules/views/handlers/views_handler_field_markup.inc
Normal file
|
@ -0,0 +1,44 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* A handler to run a field through check_markup, using a companion
|
||||
* format field.
|
||||
*
|
||||
* - format: (REQUIRED) The field in this table used to control the format
|
||||
* such as the 'format' field in the node, which goes with the
|
||||
* 'body' field.
|
||||
*
|
||||
* @ingroup views_field_handlers
|
||||
*/
|
||||
class views_handler_field_markup extends views_handler_field {
|
||||
/**
|
||||
* Constructor; calls to base object constructor.
|
||||
*/
|
||||
function construct() {
|
||||
parent::construct();
|
||||
|
||||
$this->format = $this->definition['format'];
|
||||
|
||||
$this->additional_fields = array();
|
||||
if (!is_numeric($this->format)) {
|
||||
$this->additional_fields['format'] = array('field' => $this->format);
|
||||
}
|
||||
}
|
||||
|
||||
function render($values) {
|
||||
$value = $values->{$this->field_alias};
|
||||
$format = is_numeric($this->format) ? $this->format : $values->{$this->aliases['format']};
|
||||
if ($value) {
|
||||
$value = str_replace('<!--break-->', '', $value);
|
||||
return check_markup($value, $format, FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
function element_type() {
|
||||
if (isset($this->definition['element type'])) {
|
||||
return $this->definition['element type'];
|
||||
}
|
||||
|
||||
return 'div';
|
||||
}
|
||||
}
|
73
modules/views/handlers/views_handler_field_math.inc
Normal file
73
modules/views/handlers/views_handler_field_math.inc
Normal file
|
@ -0,0 +1,73 @@
|
|||
<?php
|
||||
/**
|
||||
* Render a mathematical expression as a numeric value
|
||||
*
|
||||
* Definition terms:
|
||||
* - float: If true this field contains a decimal value. If unset this field
|
||||
* will be assumed to be integer.
|
||||
*
|
||||
* @ingroup views_field_handlers
|
||||
*/
|
||||
class views_handler_field_math extends views_handler_field_numeric {
|
||||
function option_definition() {
|
||||
$options = parent::option_definition();
|
||||
$options['expression'] = array('default' => '');
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
function options_form(&$form, &$form_state) {
|
||||
$form['expression'] = array(
|
||||
'#type' => 'textarea',
|
||||
'#title' => t('Expression'),
|
||||
'#description' => t('Enter mathematical expressions such as 2 + 2 or sqrt(5). You my assign variables and create mathematical functions and evaluate them. Use the ; to separate these. For example: f(x) = x + 2; f(2).'),
|
||||
'#default_value' => $this->options['expression'],
|
||||
);
|
||||
|
||||
// Create a place for the help
|
||||
$form['expression_help'] = array();
|
||||
parent::options_form($form, $form_state);
|
||||
|
||||
// Then move the existing help:
|
||||
$form['expression_help'] = $form['alter']['help'];
|
||||
unset($form['expression_help']['#dependency']);
|
||||
unset($form['expression_help']['#process']);
|
||||
unset($form['alter']['help']);
|
||||
}
|
||||
|
||||
function render($values) {
|
||||
ctools_include('math-expr');
|
||||
$value = strtr($this->options['expression'], $this->get_render_tokens(array()));
|
||||
$expressions = explode(';', $value);
|
||||
$math = new ctools_math_expr;
|
||||
foreach ($expressions as $expression) {
|
||||
if ($expression !== '') {
|
||||
$value = $math->evaluate($expression);
|
||||
}
|
||||
}
|
||||
|
||||
// The rest is directly from views_handler_field_numeric but because it
|
||||
// does not allow the value to be passed in, it is copied.
|
||||
if (!empty($this->options['set_precision'])) {
|
||||
$value = number_format($value, $this->options['precision'], $this->options['decimal'], $this->options['separator']);
|
||||
}
|
||||
else {
|
||||
$remainder = abs($value) - intval(abs($value));
|
||||
$value = $value > 0 ? floor($value) : ceil($value);
|
||||
$value = number_format($value, 0, '', $this->options['separator']);
|
||||
if ($remainder) {
|
||||
// The substr may not be locale safe.
|
||||
$value .= $this->options['decimal'] . substr($remainder, 2);
|
||||
}
|
||||
}
|
||||
|
||||
// Check to see if hiding should happen before adding prefix and suffix.
|
||||
if ($this->options['hide_empty'] && empty($value) && ($value !== 0 || $this->options['empty_zero'])) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return check_plain($this->options['prefix'] . $value . $this->options['suffix']);
|
||||
}
|
||||
|
||||
function query() { }
|
||||
}
|
125
modules/views/handlers/views_handler_field_numeric.inc
Normal file
125
modules/views/handlers/views_handler_field_numeric.inc
Normal file
|
@ -0,0 +1,125 @@
|
|||
<?php
|
||||
/**
|
||||
* Render a field as a numeric value
|
||||
*
|
||||
* Definition terms:
|
||||
* - float: If true this field contains a decimal value. If unset this field
|
||||
* will be assumed to be integer.
|
||||
*
|
||||
* @ingroup views_field_handlers
|
||||
*/
|
||||
class views_handler_field_numeric extends views_handler_field {
|
||||
function option_definition() {
|
||||
$options = parent::option_definition();
|
||||
|
||||
$options['set_precision'] = array('default' => FALSE);
|
||||
$options['precision'] = array('default' => 0);
|
||||
$options['decimal'] = array('default' => '.', 'translatable' => TRUE);
|
||||
$options['separator'] = array('default' => ',', 'translatable' => TRUE);
|
||||
$options['format_plural'] = array('default' => FALSE);
|
||||
$options['format_plural_singular'] = array('default' => '1');
|
||||
$options['format_plural_plural'] = array('default' => '@count');
|
||||
$options['prefix'] = array('default' => '', 'translatable' => TRUE);
|
||||
$options['suffix'] = array('default' => '', 'translatable' => TRUE);
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
function options_form(&$form, &$form_state) {
|
||||
parent::options_form($form, $form_state);
|
||||
|
||||
if (!empty($this->definition['float'])) {
|
||||
$form['set_precision'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Round'),
|
||||
'#description' => t('If checked, the number will be rounded.'),
|
||||
'#default_value' => $this->options['set_precision'],
|
||||
);
|
||||
$form['precision'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Precision'),
|
||||
'#default_value' => $this->options['precision'],
|
||||
'#description' => t('Specify how many digits to print after the decimal point.'),
|
||||
'#process' => array('views_process_dependency'),
|
||||
'#dependency' => array('edit-options-set-precision' => array(TRUE)),
|
||||
'#size' => 2,
|
||||
);
|
||||
$form['decimal'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Decimal point'),
|
||||
'#default_value' => $this->options['decimal'],
|
||||
'#description' => t('What single character to use as a decimal point.'),
|
||||
'#size' => 2,
|
||||
);
|
||||
}
|
||||
$form['separator'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Thousands separator'),
|
||||
'#default_value' => $this->options['separator'],
|
||||
'#description' => t('What single character to use as the thousands separator.'),
|
||||
'#size' => 2,
|
||||
);
|
||||
$form['format_plural'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Format plural'),
|
||||
'#description' => t('If checked, special handling will be used for plurality.'),
|
||||
'#default_value' => $this->options['format_plural'],
|
||||
);
|
||||
$form['format_plural_singular'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Singular form'),
|
||||
'#default_value' => $this->options['format_plural_singular'],
|
||||
'#description' => t('Text to use for the singular form.'),
|
||||
'#process' => array('views_process_dependency'),
|
||||
'#dependency' => array('edit-options-format-plural' => array(TRUE)),
|
||||
);
|
||||
$form['format_plural_plural'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Plural form'),
|
||||
'#default_value' => $this->options['format_plural_plural'],
|
||||
'#description' => t('Text to use for the plural form, @count will be replaced with the value.'),
|
||||
'#process' => array('views_process_dependency'),
|
||||
'#dependency' => array('edit-options-format-plural' => array(TRUE)),
|
||||
);
|
||||
$form['prefix'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Prefix'),
|
||||
'#default_value' => $this->options['prefix'],
|
||||
'#description' => t('Text to put before the number, such as currency symbol.'),
|
||||
);
|
||||
$form['suffix'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Suffix'),
|
||||
'#default_value' => $this->options['suffix'],
|
||||
'#description' => t('Text to put after the number, such as currency symbol.'),
|
||||
);
|
||||
}
|
||||
|
||||
function render($values) {
|
||||
$value = $values->{$this->field_alias};
|
||||
if (!empty($this->options['set_precision'])) {
|
||||
$value = number_format($value, $this->options['precision'], $this->options['decimal'], $this->options['separator']);
|
||||
}
|
||||
else {
|
||||
$remainder = abs($value) - intval(abs($value));
|
||||
$value = $value > 0 ? floor($value) : ceil($value);
|
||||
$value = number_format($value, 0, '', $this->options['separator']);
|
||||
if ($remainder) {
|
||||
// The substr may not be locale safe.
|
||||
$value .= $this->options['decimal'] . substr($remainder, 2);
|
||||
}
|
||||
}
|
||||
|
||||
// Check to see if hiding should happen before adding prefix and suffix.
|
||||
if ($this->options['hide_empty'] && empty($value) && ($value !== 0 || $this->options['empty_zero'])) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// Should we format as a plural.
|
||||
if (!empty($this->options['format_plural'])) {
|
||||
$value = format_plural($value, $this->options['format_plural_singular'], $this->options['format_plural_plural']);
|
||||
}
|
||||
|
||||
return filter_xss($this->options['prefix']) . check_plain($value) . filter_xss($this->options['suffix']);
|
||||
}
|
||||
}
|
111
modules/views/handlers/views_handler_field_prerender_list.inc
Normal file
111
modules/views/handlers/views_handler_field_prerender_list.inc
Normal file
|
@ -0,0 +1,111 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Field handler to provide a list of items.
|
||||
*
|
||||
* The items are expected to be loaded by a child object during pre_render,
|
||||
* and 'my field' is expected to be the pointer to the items in the list.
|
||||
*
|
||||
* Items to render should be in a list in $this->items
|
||||
*
|
||||
* @ingroup views_field_handlers
|
||||
*/
|
||||
class views_handler_field_prerender_list extends views_handler_field {
|
||||
function option_definition() {
|
||||
$options = parent::option_definition();
|
||||
|
||||
$options['type'] = array('default' => 'separator');
|
||||
$options['separator'] = array('default' => ', ');
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
function options_form(&$form, &$form_state) {
|
||||
parent::options_form($form, $form_state);
|
||||
$form['type'] = array(
|
||||
'#type' => 'radios',
|
||||
'#title' => t('Display type'),
|
||||
'#options' => array(
|
||||
'ul' => t('Unordered list'),
|
||||
'ol' => t('Ordered list'),
|
||||
'separator' => t('Simple separator'),
|
||||
),
|
||||
'#default_value' => $this->options['type'],
|
||||
);
|
||||
|
||||
$form['separator'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Separator'),
|
||||
'#default_value' => $this->options['separator'],
|
||||
'#process' => array('views_process_dependency'),
|
||||
'#dependency' => array('radio:options[type]' => array('separator')),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the field.
|
||||
*
|
||||
* This function is deprecated, but left in for older systems that have not
|
||||
* yet or won't update their prerender list fields. If a render_item method
|
||||
* exists, this will not get used by advanced_render.
|
||||
*/
|
||||
function render($values) {
|
||||
$field = $values->{$this->field_alias};
|
||||
if (!empty($this->items[$field])) {
|
||||
if ($this->options['type'] == 'separator') {
|
||||
return implode(check_plain($this->options['separator']), $this->items[$field]);
|
||||
}
|
||||
else {
|
||||
return theme('item_list', $this->items[$field], NULL, $this->options['type']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Render all items in this field together.
|
||||
*
|
||||
* When using advanced render, each possible item in the list is rendered
|
||||
* individually. Then the items are all pasted together.
|
||||
*/
|
||||
function render_items($items) {
|
||||
if (!empty($items)) {
|
||||
if ($this->options['type'] == 'separator') {
|
||||
return implode(check_plain($this->options['separator']), $items);
|
||||
}
|
||||
else {
|
||||
return theme('item_list', $items, NULL, $this->options['type']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array of items for the field.
|
||||
*
|
||||
* Items should be stored in the result array, if possible, as an array
|
||||
* with 'value' as the actual displayable value of the item, plus
|
||||
* any items that might be found in the 'alter' options array for
|
||||
* creating links, such as 'path', 'fragment', 'query' etc, such a thing
|
||||
* is to be made. Additionally, items that might be turned into tokens
|
||||
* should also be in this array.
|
||||
*/
|
||||
function get_items($values) {
|
||||
$field = $values->{$this->field_alias};
|
||||
if (!empty($this->items[$field])) {
|
||||
return $this->items[$field];
|
||||
}
|
||||
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if advanced rendering is allowed.
|
||||
*
|
||||
* By default, advanced rendering will NOT be allowed if the class
|
||||
* inheriting from this does not implement a 'render_items' method.
|
||||
*/
|
||||
function allow_advanced_render() {
|
||||
// Note that the advanced render bits also use the presence of
|
||||
// this method to determine if it needs to render items as a list.
|
||||
return method_exists($this, 'render_item');
|
||||
}
|
||||
}
|
38
modules/views/handlers/views_handler_field_url.inc
Normal file
38
modules/views/handlers/views_handler_field_url.inc
Normal file
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Field handler to provide simple renderer that turns a URL into a clickable link.
|
||||
*
|
||||
* @ingroup views_field_handlers
|
||||
*/
|
||||
class views_handler_field_url extends views_handler_field {
|
||||
function option_definition() {
|
||||
$options = parent::option_definition();
|
||||
|
||||
$options['display_as_link'] = array('default' => TRUE);
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide link to the page being visited.
|
||||
*/
|
||||
function options_form(&$form, &$form_state) {
|
||||
parent::options_form($form, $form_state);
|
||||
$form['display_as_link'] = array(
|
||||
'#title' => t('Display as link'),
|
||||
'#type' => 'checkbox',
|
||||
'#default_value' => !empty($this->options['display_as_link']),
|
||||
);
|
||||
}
|
||||
|
||||
function render($values) {
|
||||
$value = $values->{$this->field_alias};
|
||||
if (!empty($this->options['display_as_link'])) {
|
||||
return l(check_plain($value), $value, array('html' => TRUE));
|
||||
}
|
||||
else {
|
||||
return check_url($value);
|
||||
}
|
||||
}
|
||||
}
|
636
modules/views/handlers/views_handler_filter.inc
Normal file
636
modules/views/handlers/views_handler_filter.inc
Normal file
|
@ -0,0 +1,636 @@
|
|||
<?php
|
||||
/**
|
||||
* @defgroup views_filter_handlers Views' filter handlers
|
||||
* @{
|
||||
* Handlers to tell Views how to filter queries.
|
||||
*
|
||||
* Definition items:
|
||||
* - allow empty: If true, the 'IS NULL' and 'IS NOT NULL' operators become
|
||||
* available as standard operators.
|
||||
*
|
||||
* Object flags:
|
||||
* You can set some specific behavior by setting up the following flags on
|
||||
* your custom class.
|
||||
*
|
||||
* - no_single:
|
||||
* Disable the possibility to force a single value.
|
||||
* - no_operator:
|
||||
* Disable the possibility to use operators.
|
||||
* - no_optional:
|
||||
* Disable the possibility to allow a exposed input to be optional.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Base class for filters.
|
||||
*/
|
||||
class views_handler_filter extends views_handler {
|
||||
/**
|
||||
* Provide some extra help to get the operator/value easier to use.
|
||||
*
|
||||
* This likely has to be overridden by filters which are more complex
|
||||
* than simple operator/value.
|
||||
*/
|
||||
function init(&$view, $options) {
|
||||
parent::init($view, $options);
|
||||
|
||||
$this->operator = $this->options['operator'];
|
||||
$this->value = $this->options['value'];
|
||||
|
||||
// Compatibility: Set use_operator to true if the old way of using
|
||||
// the operator is set and use_operator is NULL (was never set).
|
||||
if (!empty($options['exposed']) && !empty($options['expose']['operator']) && !isset($options['expose']['use_operator'])) {
|
||||
$this->options['expose']['use_operator'] = TRUE;
|
||||
}
|
||||
|
||||
// If there are relationships in the view, allow empty should be true
|
||||
// so that we can do IS NULL checks on items. Not all filters respect
|
||||
// allow empty, but string and numeric do and that covers enough.
|
||||
if ($this->view->display_handler->get_option('relationships')) {
|
||||
$this->definition['allow empty'] = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
function option_definition() {
|
||||
$options = parent::option_definition();
|
||||
|
||||
$options['operator'] = array('default' => '=');
|
||||
$options['value'] = array('default' => '');
|
||||
$options['group'] = array('default' => '0');
|
||||
$options['exposed'] = array('default' => FALSE);
|
||||
$options['expose'] = array(
|
||||
'contains' => array(
|
||||
'operator' => array('default' => FALSE),
|
||||
'label' => array('default' => '', 'translatable' => TRUE),
|
||||
),
|
||||
);
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the filter on the administrative summary
|
||||
*/
|
||||
function admin_summary() {
|
||||
return check_plain((string) $this->operator) . ' ' . check_plain((string) $this->value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if a filter can be exposed.
|
||||
*/
|
||||
function can_expose() { return TRUE; }
|
||||
|
||||
/**
|
||||
* Provide the basic form which calls through to subforms.
|
||||
* If overridden, it is best to call through to the parent,
|
||||
* or to at least make sure all of the functions in this form
|
||||
* are called.
|
||||
*/
|
||||
function options_form(&$form, &$form_state) {
|
||||
if ($this->can_expose()) {
|
||||
$this->show_expose_button($form, $form_state);
|
||||
}
|
||||
$form['op_val_start'] = array('#value' => '<div class="clear-block">');
|
||||
$this->show_operator_form($form, $form_state);
|
||||
$this->show_value_form($form, $form_state);
|
||||
$form['op_val_end'] = array('#value' => '</div>');
|
||||
if ($this->can_expose()) {
|
||||
$this->show_expose_form($form, $form_state);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple validate handler
|
||||
*/
|
||||
function options_validate($form, &$form_state) {
|
||||
$this->operator_validate($form, $form_state);
|
||||
$this->value_validate($form, $form_state);
|
||||
if (!empty($this->options['exposed'])) {
|
||||
$this->expose_validate($form, $form_state);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple submit handler
|
||||
*/
|
||||
function options_submit($form, &$form_state) {
|
||||
unset($form_state['values']['expose_button']); // don't store this.
|
||||
$this->operator_submit($form, $form_state);
|
||||
$this->value_submit($form, $form_state);
|
||||
if (!empty($this->options['exposed'])) {
|
||||
$this->expose_submit($form, $form_state);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Shortcut to display the operator form.
|
||||
*/
|
||||
function show_operator_form(&$form, &$form_state) {
|
||||
$this->operator_form($form, $form_state);
|
||||
$form['operator']['#prefix'] = '<div class="views-left-30">';
|
||||
$form['operator']['#suffix'] = '</div>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide a form for setting the operator.
|
||||
*
|
||||
* This may be overridden by child classes, and it must
|
||||
* define $form['operator'];
|
||||
*/
|
||||
function operator_form(&$form, &$form_state) {
|
||||
$options = $this->operator_options();
|
||||
if (!empty($options)) {
|
||||
$form['operator'] = array(
|
||||
'#type' => count($options) < 10 ? 'radios' : 'select',
|
||||
'#title' => t('Operator'),
|
||||
'#default_value' => $this->operator,
|
||||
'#options' => $options,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide a list of options for the default operator form.
|
||||
* Should be overridden by classes that don't override operator_form
|
||||
*/
|
||||
function operator_options() { return array(); }
|
||||
|
||||
/**
|
||||
* Validate the operator form.
|
||||
*/
|
||||
function operator_validate($form, &$form_state) { }
|
||||
|
||||
/**
|
||||
* Perform any necessary changes to the form values prior to storage.
|
||||
* There is no need for this function to actually store the data.
|
||||
*/
|
||||
function operator_submit($form, &$form_state) { }
|
||||
|
||||
/**
|
||||
* Shortcut to display the value form.
|
||||
*/
|
||||
function show_value_form(&$form, &$form_state) {
|
||||
$this->value_form($form, $form_state);
|
||||
if (empty($this->no_operator)) {
|
||||
$form['value']['#prefix'] = '<div class="views-right-70">' . (isset($form['value']['#prefix']) ? $form['value']['#prefix'] : '');
|
||||
$form['value']['#suffix'] = (isset($form['value']['#suffix']) ? $form['value']['#suffix'] : '') . '</div>';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide a form for setting options.
|
||||
*
|
||||
* This should be overridden by all child classes and it must
|
||||
* define $form['value']
|
||||
*/
|
||||
function value_form(&$form, &$form_state) { $form['value'] = array(); }
|
||||
|
||||
/**
|
||||
* Validate the options form.
|
||||
*/
|
||||
function value_validate($form, &$form_state) { }
|
||||
|
||||
/**
|
||||
* Perform any necessary changes to the form values prior to storage.
|
||||
* There is no need for this function to actually store the data.
|
||||
*/
|
||||
function value_submit($form, &$form_state) { }
|
||||
|
||||
/**
|
||||
* Shortcut to display the expose/hide button.
|
||||
*/
|
||||
function show_expose_button(&$form, &$form_state) {
|
||||
$form['expose_button'] = array(
|
||||
'#prefix' => '<div class="views-expose clear-block">',
|
||||
'#suffix' => '</div>',
|
||||
);
|
||||
if (empty($this->options['exposed'])) {
|
||||
$form['expose_button']['button'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Expose'),
|
||||
'#submit' => array('views_ui_config_item_form_expose'),
|
||||
);
|
||||
$form['expose_button']['markup'] = array(
|
||||
'#prefix' => '<div class="description">',
|
||||
'#value' => t('This item is currently not exposed. If you <strong>expose</strong> it, users will be able to change the filter as they view it.'),
|
||||
'#suffix' => '</div>',
|
||||
);
|
||||
}
|
||||
else {
|
||||
$form['expose_button']['button'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Hide'),
|
||||
'#submit' => array('views_ui_config_item_form_expose'),
|
||||
);
|
||||
$form['expose_button']['markup'] = array(
|
||||
'#prefix' => '<div class="description">',
|
||||
'#value' => t('This item is currently exposed. If you <strong>hide</strong> it, users will not be able to change the filter as they view it.'),
|
||||
'#suffix' => '</div>',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Shortcut to display the exposed options form.
|
||||
*/
|
||||
function show_expose_form(&$form, &$form_state) {
|
||||
if (empty($this->options['exposed'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
$form['expose'] = array(
|
||||
'#prefix' => '<div class="views-expose-options clear-block">',
|
||||
'#suffix' => '</div>',
|
||||
);
|
||||
$this->expose_form($form, $form_state);
|
||||
|
||||
// When we click the expose button, we add new gadgets to the form but they
|
||||
// have no data in $_POST so their defaults get wiped out. This prevents
|
||||
// these defaults from getting wiped out. This setting will only be TRUE
|
||||
// during a 2nd pass rerender.
|
||||
if (!empty($form_state['force_expose_options'])) {
|
||||
foreach (element_children($form['expose']) as $id) {
|
||||
if (isset($form['expose'][$id]['#default_value']) && !isset($form['expose'][$id]['#value'])) {
|
||||
$form['expose'][$id]['#value'] = $form['expose'][$id]['#default_value'];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Overridable form for exposed filter options.
|
||||
*
|
||||
* If overridden, it is best to call the parent or re-implement
|
||||
* the stuff here.
|
||||
*
|
||||
* Many filters will need to override this in order to provide options
|
||||
* that are nicely tailored to the given filter.
|
||||
*/
|
||||
function expose_form(&$form, &$form_state) {
|
||||
$form['expose']['start_left'] = array(
|
||||
'#value' => '<div class="views-left-50">',
|
||||
);
|
||||
|
||||
$this->expose_form_left($form, $form_state);
|
||||
|
||||
$form['expose']['end_left'] = array(
|
||||
'#value' => '</div>',
|
||||
);
|
||||
|
||||
$form['expose']['start_checkboxes'] = array(
|
||||
'#value' => '<div class="form-checkboxes views-left-40 clear-block">',
|
||||
);
|
||||
|
||||
$this->expose_form_right($form, $form_state);
|
||||
|
||||
$form['expose']['end_checkboxes'] = array(
|
||||
'#value' => '</div>',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the 'left' side fo the exposed options form.
|
||||
*/
|
||||
function expose_form_left(&$form, &$form_state) {
|
||||
if (!empty($form['operator']['#type'])) {
|
||||
$form['expose']['use_operator'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Unlock operator'),
|
||||
'#description' => t('When checked, the operator will be exposed to the user'),
|
||||
'#default_value' => !empty($this->options['expose']['use_operator']),
|
||||
);
|
||||
$form['expose']['operator'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#default_value' => $this->options['expose']['operator'],
|
||||
'#title' => t('Operator identifier'),
|
||||
'#size' => 40,
|
||||
'#description' => t('This will appear in the URL after the ? to identify this operator.'),
|
||||
'#process' => array('views_process_dependency'),
|
||||
'#dependency' => array(
|
||||
'edit-options-expose-use-operator' => array(1)
|
||||
),
|
||||
);
|
||||
}
|
||||
else {
|
||||
$form['expose']['operator'] = array(
|
||||
'#type' => 'value',
|
||||
'#value' => '',
|
||||
);
|
||||
}
|
||||
|
||||
$form['expose']['identifier'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#default_value' => $this->options['expose']['identifier'],
|
||||
'#title' => t('Filter identifier'),
|
||||
'#size' => 40,
|
||||
'#description' => t('This will appear in the URL after the ? to identify this filter. Cannot be blank.'),
|
||||
);
|
||||
$form['expose']['label'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#default_value' => $this->options['expose']['label'],
|
||||
'#title' => t('Label'),
|
||||
'#size' => 40,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the 'right' side fo the exposed options form.
|
||||
*/
|
||||
function expose_form_right(&$form, &$form_state) {
|
||||
if (empty($this->no_optional)) {
|
||||
$form['expose']['optional'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Optional'),
|
||||
'#description' => t('This exposed filter is optional and will have added options to allow it not to be set.'),
|
||||
'#default_value' => $this->options['expose']['optional'],
|
||||
);
|
||||
}
|
||||
if (empty($this->no_single)) {
|
||||
$form['expose']['single'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Force single'),
|
||||
'#description' => t('Force this exposed filter to accept only one option.'),
|
||||
'#default_value' => $this->options['expose']['single'],
|
||||
);
|
||||
}
|
||||
$form['expose']['remember'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Remember'),
|
||||
'#description' => t('Remember the last setting the user gave this filter.'),
|
||||
'#default_value' => $this->options['expose']['remember'],
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the options form.
|
||||
*/
|
||||
function expose_validate($form, &$form_state) {
|
||||
if (empty($this->options['expose']['identifier'])) {
|
||||
if (empty($form_state['values']['options']['expose']['identifier'])) {
|
||||
form_error($form['expose']['identifier'], t('The identifier is required if the filter is exposed.'));
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($form_state['values']['options']['expose']['identifier']) && $form_state['values']['options']['expose']['identifier'] == 'value') {
|
||||
form_error($form['expose']['identifier'], t('This identifier is not allowed.'));
|
||||
}
|
||||
|
||||
if (!$this->view->display_handler->is_identifier_unique($form_state['id'], $form_state['values']['options']['expose']['identifier'])) {
|
||||
form_error($form['expose']['identifier'], t('This identifier is used by another handler.'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform any necessary changes to the form exposes prior to storage.
|
||||
* There is no need for this function to actually store the data.
|
||||
*/
|
||||
function expose_submit($form, &$form_state) { }
|
||||
|
||||
/**
|
||||
* Provide default options for exposed filters.
|
||||
*/
|
||||
function expose_options() {
|
||||
$this->options['expose'] = array(
|
||||
'use_operator' => FALSE,
|
||||
'operator' => $this->options['id'] . '_op',
|
||||
'identifier' => $this->options['id'],
|
||||
'label' => $this->ui_name(),
|
||||
'remember' => FALSE,
|
||||
'single' => TRUE,
|
||||
'optional' => TRUE,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render our chunk of the exposed filter form when selecting
|
||||
*
|
||||
* You can override this if it doesn't do what you expect.
|
||||
*/
|
||||
function exposed_form(&$form, &$form_state) {
|
||||
if (empty($this->options['exposed'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!empty($this->options['expose']['use_operator']) && !empty($this->options['expose']['operator'])) {
|
||||
$operator = $this->options['expose']['operator'];
|
||||
$this->operator_form($form, $form_state);
|
||||
$form[$operator] = $form['operator'];
|
||||
|
||||
if (isset($form[$operator]['#title'])) {
|
||||
unset($form[$operator]['#title']);
|
||||
}
|
||||
|
||||
$this->exposed_translate($form[$operator], 'operator');
|
||||
|
||||
unset($form['operator']);
|
||||
}
|
||||
|
||||
if (!empty($this->options['expose']['identifier'])) {
|
||||
$value = $this->options['expose']['identifier'];
|
||||
$this->value_form($form, $form_state);
|
||||
$form[$value] = $form['value'];
|
||||
|
||||
if (isset($form[$value]['#title']) && !empty($form[$value]['#type']) && $form[$value]['#type'] != 'checkbox') {
|
||||
unset($form[$value]['#title']);
|
||||
}
|
||||
|
||||
$this->exposed_translate($form[$value], 'value');
|
||||
|
||||
if (!empty($form['#type']) && ($form['#type'] == 'checkboxes' || ($form['#type'] == 'select' && !empty($form['#multiple'])))) {
|
||||
unset($form[$value]['#default_value']);
|
||||
}
|
||||
|
||||
if (!empty($form['#type']) && $form['#type'] == 'select' && empty($form['#multiple'])) {
|
||||
$form[$value]['#default_value'] = 'All';
|
||||
}
|
||||
|
||||
if ($value != 'value') {
|
||||
unset($form['value']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Make some translations to a form item to make it more suitable to
|
||||
* exposing.
|
||||
*/
|
||||
function exposed_translate(&$form, $type) {
|
||||
if (!isset($form['#type'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($form['#type'] == 'radios') {
|
||||
$form['#type'] = 'select';
|
||||
}
|
||||
// Checkboxes don't work so well in exposed forms due to GET conversions.
|
||||
if ($form['#type'] == 'checkboxes') {
|
||||
if (empty($form['#no_convert']) || !empty($this->options['expose']['single'])) {
|
||||
$form['#type'] = 'select';
|
||||
}
|
||||
if (empty($this->options['expose']['single'])) {
|
||||
$form['#multiple'] = TRUE;
|
||||
}
|
||||
}
|
||||
if (!empty($this->options['expose']['single']) && isset($form['#multiple'])) {
|
||||
unset($form['#multiple']);
|
||||
$form['#size'] = NULL;
|
||||
}
|
||||
|
||||
if ($type == 'value' && empty($this->no_optional) && !empty($this->options['expose']['optional']) && $form['#type'] == 'select' && empty($form['#multiple'])) {
|
||||
$any_label = variable_get('views_exposed_filter_any_label', 'old_any') == 'old_any' ? '<Any>' : t('- Any -');
|
||||
$form['#options'] = array('All' => $any_label) + $form['#options'];
|
||||
$form['#default_value'] = 'All';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tell the renderer about our exposed form. This only needs to be
|
||||
* overridden for particularly complex forms. And maybe not even then.
|
||||
*/
|
||||
function exposed_info() {
|
||||
if (empty($this->options['exposed'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
return array(
|
||||
'operator' => $this->options['expose']['operator'],
|
||||
'value' => $this->options['expose']['identifier'],
|
||||
'label' => $this->options['expose']['label'],
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to see if input from the exposed filters should change
|
||||
* the behavior of this filter.
|
||||
*/
|
||||
function accept_exposed_input($input) {
|
||||
if (empty($this->options['exposed'])) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
if (!empty($this->options['expose']['use_operator']) && !empty($this->options['expose']['operator']) && isset($input[$this->options['expose']['operator']])) {
|
||||
$this->operator = $input[$this->options['expose']['operator']];
|
||||
}
|
||||
|
||||
if (!empty($this->options['expose']['identifier'])) {
|
||||
$value = $input[$this->options['expose']['identifier']];
|
||||
|
||||
// Various ways to check for the absence of optional input.
|
||||
if (!empty($this->options['expose']['optional'])) {
|
||||
|
||||
if (($this->operator == 'empty' || $this->operator == 'not empty') && $value === '') {
|
||||
$value = ' ';
|
||||
}
|
||||
|
||||
if ($this->operator != 'empty' && $this->operator != 'not empty') {
|
||||
if ($value == 'All' || $value === array()) {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($this->no_single) && $value === '') {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (isset($value)) {
|
||||
$this->value = $value;
|
||||
if (empty($this->no_single) && !empty($this->options['expose']['single'])) {
|
||||
$this->value = array($value);
|
||||
}
|
||||
}
|
||||
else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
function store_exposed_input($input, $status) {
|
||||
if (empty($this->options['exposed']) || empty($this->options['expose']['identifier'])) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (empty($this->options['expose']['remember'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Figure out which display id is responsible for the filters, so we
|
||||
// know where to look for session stored values.
|
||||
$display_id = ($this->view->display_handler->is_defaulted('filters')) ? 'default' : $this->view->current_display;
|
||||
|
||||
// shortcut test.
|
||||
$operator = !empty($this->options['expose']['use_operator']) && !empty($this->options['expose']['operator']);
|
||||
|
||||
// false means that we got a setting that means to recuse ourselves,
|
||||
// so we should erase whatever happened to be there.
|
||||
if (!$status && isset($_SESSION['views'][$this->view->name][$display_id])) {
|
||||
$session = &$_SESSION['views'][$this->view->name][$display_id];
|
||||
if ($operator && isset($session[$this->options['expose']['operator']])) {
|
||||
unset($session[$this->options['expose']['operator']]);
|
||||
}
|
||||
|
||||
if (isset($session[$this->options['expose']['identifier']])) {
|
||||
unset($session[$this->options['expose']['identifier']]);
|
||||
}
|
||||
}
|
||||
|
||||
if ($status) {
|
||||
if (!isset($_SESSION['views'][$this->view->name][$display_id])) {
|
||||
$_SESSION['views'][$this->view->name][$display_id] = array();
|
||||
}
|
||||
|
||||
$session = &$_SESSION['views'][$this->view->name][$display_id];
|
||||
|
||||
if ($operator && isset($input[$this->options['expose']['operator']])) {
|
||||
$session[$this->options['expose']['operator']] = $input[$this->options['expose']['operator']];
|
||||
}
|
||||
|
||||
$session[$this->options['expose']['identifier']] = $input[$this->options['expose']['identifier']];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add this filter to the query.
|
||||
*
|
||||
* Due to the nature of fapi, the value and the operator have an unintended
|
||||
* level of indirection. You will find them in $this->operator
|
||||
* and $this->value respectively.
|
||||
*/
|
||||
function query() {
|
||||
$this->ensure_my_table();
|
||||
$this->query->add_where($this->options['group'], "$this->table_alias.$this->real_field " . $this->operator . " '%s'", $this->value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A special handler to take the place of missing or broken handlers.
|
||||
*/
|
||||
class views_handler_filter_broken extends views_handler_filter {
|
||||
function ui_name($short = FALSE) {
|
||||
return t('Broken/missing handler');
|
||||
}
|
||||
|
||||
function ensure_my_table() { /* No table to ensure! */ }
|
||||
function query() { /* No query to run */ }
|
||||
function options_form(&$form, &$form_state) {
|
||||
$form['markup'] = array(
|
||||
'#prefix' => '<div class="form-item description">',
|
||||
'#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.'),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the handler is considered 'broken'
|
||||
*/
|
||||
function broken() { return TRUE; }
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
159
modules/views/handlers/views_handler_filter_boolean_operator.inc
Normal file
159
modules/views/handlers/views_handler_filter_boolean_operator.inc
Normal file
|
@ -0,0 +1,159 @@
|
|||
<?php
|
||||
/**
|
||||
* Simple filter to handle matching of boolean values
|
||||
*
|
||||
* Definition items:
|
||||
* - label: (REQUIRED) The label for the checkbox.
|
||||
* - type: For basic 'true false' types, an item can specify the following:
|
||||
* - true-false: True/false (this is the default)
|
||||
* - yes-no: Yes/No
|
||||
* - on-off: On/Off
|
||||
* - accept null: Treat a NULL value as false.
|
||||
*/
|
||||
class views_handler_filter_boolean_operator extends views_handler_filter {
|
||||
// exposed filter options
|
||||
var $no_single = TRUE;
|
||||
// Don't display empty space where the operator would be.
|
||||
var $no_operator = TRUE;
|
||||
// Whether to accept NULL as a false value or not
|
||||
var $accept_null = FALSE;
|
||||
|
||||
function construct() {
|
||||
$this->value_value = t('True');
|
||||
if (isset($this->definition['label'])) {
|
||||
$this->value_value = $this->definition['label'];
|
||||
}
|
||||
if (isset($this->definition['accept null'])) {
|
||||
$this->accept_null = (bool) $this->definition['accept null'];
|
||||
}
|
||||
else if (isset($this->definition['accept_null'])) {
|
||||
$this->accept_null = (bool) $this->definition['accept_null'];
|
||||
}
|
||||
$this->value_options = NULL;
|
||||
parent::construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the possible options for this filter.
|
||||
*
|
||||
* Child classes should override this function to set the possible values
|
||||
* for the filter. Since this is a boolean filter, the array should have
|
||||
* two possible keys: 1 for "True" and 0 for "False", although the labels
|
||||
* can be whatever makes sense for the filter. These values are used for
|
||||
* configuring the filter, when the filter is exposed, and in the admin
|
||||
* summary of the filter. Normally, this should be static data, but if it's
|
||||
* dynamic for some reason, child classes should use a guard to reduce
|
||||
* database hits as much as possible.
|
||||
*/
|
||||
function get_value_options() {
|
||||
if (isset($this->definition['type'])) {
|
||||
if ($this->definition['type'] == 'yes-no') {
|
||||
$this->value_options = array(1 => t('Yes'), 0 => t('No'));
|
||||
}
|
||||
if ($this->definition['type'] == 'on-off') {
|
||||
$this->value_options = array(1 => t('On'), 0 => t('Off'));
|
||||
}
|
||||
}
|
||||
|
||||
// Provide a fallback if the above didn't set anything.
|
||||
if (!isset($this->value_options)) {
|
||||
$this->value_options = array(1 => t('True'), 0 => t('False'));
|
||||
}
|
||||
}
|
||||
|
||||
function option_definition() {
|
||||
$options = parent::option_definition();
|
||||
|
||||
$options['value']['default'] = FALSE;
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
function operator_form(&$form, &$form_state) {
|
||||
$form['operator'] = array();
|
||||
}
|
||||
|
||||
function value_form(&$form, &$form_state) {
|
||||
if (empty($this->value_options)) {
|
||||
// Initialize the array of possible values for this filter.
|
||||
$this->get_value_options();
|
||||
}
|
||||
if (!empty($form_state['exposed'])) {
|
||||
// Exposed filter: use a select box to save space.
|
||||
$filter_form_type = 'select';
|
||||
}
|
||||
else {
|
||||
// Configuring a filter: use radios for clarity.
|
||||
$filter_form_type = 'radios';
|
||||
}
|
||||
$form['value'] = array(
|
||||
'#type' => $filter_form_type,
|
||||
'#title' => $this->value_value,
|
||||
'#options' => $this->value_options,
|
||||
'#default_value' => $this->value,
|
||||
);
|
||||
if (!empty($this->options['exposed'])) {
|
||||
$identifier = $this->options['expose']['identifier'];
|
||||
if (!isset($form_state['input'][$identifier])) {
|
||||
$form_state['input'][$identifier] = $this->value;
|
||||
}
|
||||
// If we're configuring an exposed filter, add an <Any> option.
|
||||
if (empty($form_state['exposed']) || !empty($this->options['optional'])) {
|
||||
$any_label = variable_get('views_exposed_filter_any_label', 'old_any') == 'old_any' ? '<Any>' : t('- Any -');
|
||||
if ($form['value']['#type'] != 'select') {
|
||||
$any_label = check_plain($any_label);
|
||||
}
|
||||
$form['value']['#options'] = array('All' => $any_label) + $form['value']['#options'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function value_validate($form, &$form_state) {
|
||||
if ($form_state['values']['options']['value'] == 'All' && empty($form_state['values']['options']['expose']['optional'])) {
|
||||
form_set_error('value', t('You must select a value unless this is an optional exposed filter.'));
|
||||
}
|
||||
}
|
||||
|
||||
function admin_summary() {
|
||||
if (!empty($this->options['exposed'])) {
|
||||
return t('exposed');
|
||||
}
|
||||
if (empty($this->value_options)) {
|
||||
$this->get_value_options();
|
||||
}
|
||||
// Now that we have the valid options for this filter, just return the
|
||||
// human-readable label based on the current value. The value_options
|
||||
// array is keyed with either 0 or 1, so if the current value is not
|
||||
// empty, use the label for 1, and if it's empty, use the label for 0.
|
||||
return $this->value_options[!empty($this->value)];
|
||||
}
|
||||
|
||||
function expose_options() {
|
||||
parent::expose_options();
|
||||
$this->options['expose']['operator'] = '';
|
||||
$this->options['expose']['label'] = $this->value_value;
|
||||
$this->options['expose']['optional'] = FALSE;
|
||||
}
|
||||
|
||||
function query() {
|
||||
$this->ensure_my_table();
|
||||
|
||||
$where = "$this->table_alias.$this->real_field ";
|
||||
|
||||
if (empty($this->value)) {
|
||||
$where .= '= 0';
|
||||
if ($this->accept_null) {
|
||||
$where = '(' . $where . " OR $this->table_alias.$this->real_field IS NULL)";
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!empty($this->definition['use equal'])) {
|
||||
$where .= '= 1';
|
||||
}
|
||||
else {
|
||||
$where .= '<> 0';
|
||||
}
|
||||
}
|
||||
$this->query->add_where($this->options['group'], $where);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
/**
|
||||
* Simple filter to handle matching of boolean values.
|
||||
*
|
||||
* This handler checks to see if a string field is empty (equal to '') or not.
|
||||
* It is otherwise identical to the parent operator.
|
||||
*
|
||||
* Definition items:
|
||||
* - label: (REQUIRED) The label for the checkbox.
|
||||
*/
|
||||
class views_handler_filter_boolean_operator_string extends views_handler_filter_boolean_operator {
|
||||
function query() {
|
||||
$this->ensure_my_table();
|
||||
$where = "$this->table_alias.$this->real_field ";
|
||||
|
||||
if (empty($this->value)) {
|
||||
$where .= "= ''";
|
||||
if ($this->accept_null) {
|
||||
$where = '(' . $where . " OR $this->table_alias.$this->real_field IS NULL)";
|
||||
}
|
||||
}
|
||||
else {
|
||||
$where .= "<> ''";
|
||||
}
|
||||
$this->query->add_where($this->options['group'], $where);
|
||||
}
|
||||
}
|
157
modules/views/handlers/views_handler_filter_date.inc
Normal file
157
modules/views/handlers/views_handler_filter_date.inc
Normal file
|
@ -0,0 +1,157 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Filter to handle dates stored as a timestamp.
|
||||
*/
|
||||
class views_handler_filter_date extends views_handler_filter_numeric {
|
||||
function option_definition() {
|
||||
$options = parent::option_definition();
|
||||
|
||||
// value is already set up properly, we're just adding our new field to it.
|
||||
$options['value']['type']['default'] = 'date';
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a type selector to the value form
|
||||
*/
|
||||
function value_form(&$form, &$form_state) {
|
||||
if (empty($form_state['exposed'])) {
|
||||
$form['value']['type'] = array(
|
||||
'#type' => 'radios',
|
||||
'#title' => t('Value type'),
|
||||
'#options' => array(
|
||||
'date' => t('A date in any machine readable format. CCYY-MM-DD HH:MM:SS is preferred.'),
|
||||
'offset' => t('An offset from the current time such as "!example1" or "!example2"', array('!example1' => '+1 day', '!example2' => '-2 hours -30 minutes')),
|
||||
),
|
||||
'#default_value' => !empty($this->value['type']) ? $this->value['type'] : 'date',
|
||||
);
|
||||
}
|
||||
parent::value_form($form, $form_state);
|
||||
}
|
||||
|
||||
function options_validate($form, &$form_state) {
|
||||
parent::options_validate($form, $form_state);
|
||||
|
||||
if (!empty($form_state['values']['options']['expose']['optional'])) {
|
||||
// Who cares what the value is if it's exposed and optional.
|
||||
return;
|
||||
}
|
||||
|
||||
$this->validate_valid_time($form['value'], $form_state['values']['options']['operator'], $form_state['values']['options']['value']);
|
||||
}
|
||||
|
||||
function exposed_validate($form, &$form_state) {
|
||||
if (empty($this->options['exposed'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!empty($this->options['expose']['optional'])) {
|
||||
// Who cares what the value is if it's exposed and optional.
|
||||
return;
|
||||
}
|
||||
|
||||
$value = &$form_state['values'][$this->options['expose']['identifier']];
|
||||
if (!empty($this->options['expose']['use_operator']) && !empty($this->options['expose']['operator'])) {
|
||||
$operator = $form_state['values'][$this->options['expose']['operator']];
|
||||
}
|
||||
else {
|
||||
$operator = $this->operator;
|
||||
}
|
||||
|
||||
$this->validate_valid_time($this->options['expose']['identifier'], $operator, $value);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that the time values convert to something usable.
|
||||
*/
|
||||
function validate_valid_time(&$form, $operator, $value) {
|
||||
$operators = $this->operators();
|
||||
|
||||
if ($operators[$operator]['values'] == 1) {
|
||||
$convert = strtotime($value['value']);
|
||||
if (!empty($form['value']) && ($convert == -1 || $convert === FALSE)) {
|
||||
form_error($form['value'], t('Invalid date format.'));
|
||||
}
|
||||
}
|
||||
elseif ($operators[$operator]['values'] == 2) {
|
||||
$min = strtotime($value['min']);
|
||||
if ($min == -1 || $min === FALSE) {
|
||||
form_error($form['min'], t('Invalid date format.'));
|
||||
}
|
||||
$max = strtotime($value['max']);
|
||||
if ($max == -1 || $max === FALSE) {
|
||||
form_error($form['max'], t('Invalid date format.'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function accept_exposed_input($input) {
|
||||
if (empty($this->options['exposed'])) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// Store this because it will get overwritten.
|
||||
$type = $this->value['type'];
|
||||
$rc = parent::accept_exposed_input($input);
|
||||
|
||||
// Don't filter if value(s) are empty.
|
||||
$operators = $this->operators();
|
||||
if (!empty($this->options['expose']['use_operator']) && !empty($this->options['expose']['operator'])) {
|
||||
$operator = $input[$this->options['expose']['operator']];
|
||||
}
|
||||
else {
|
||||
$operator = $this->operator;
|
||||
}
|
||||
|
||||
if ($operators[$operator]['values'] == 1) {
|
||||
if ($this->value['value'] == '') {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ($this->value['min'] == '' || $this->value['max'] == '') {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
// restore what got overwritten by the parent.
|
||||
$this->value['type'] = $type;
|
||||
return $rc;
|
||||
}
|
||||
|
||||
function op_between($field) {
|
||||
if ($this->operator == 'between') {
|
||||
$a = intval(strtotime($this->value['min'], 0));
|
||||
$b = intval(strtotime($this->value['max'], 0));
|
||||
}
|
||||
else {
|
||||
$a = intval(strtotime($this->value['max'], 0));
|
||||
$b = intval(strtotime($this->value['min'], 0));
|
||||
}
|
||||
|
||||
if ($this->value['type'] == 'offset') {
|
||||
$a = '***CURRENT_TIME***' . sprintf('%+d', $a); // keep sign
|
||||
$b = '***CURRENT_TIME***' . sprintf('%+d', $b); // keep sign
|
||||
}
|
||||
// %s is safe here because strtotime scrubbed the input and we might
|
||||
// have a string if using offset.
|
||||
if ($this->operator == 'between') {
|
||||
$this->query->add_where($this->options['group'], "$field >= %s", $a);
|
||||
$this->query->add_where($this->options['group'], "$field <= %s", $b);
|
||||
}
|
||||
else {
|
||||
$this->query->add_where($this->options['group'], "$field >= %s OR $field <= %s", array($a, $b));
|
||||
}
|
||||
}
|
||||
|
||||
function op_simple($field) {
|
||||
$value = intval(strtotime($this->value['value'], 0));
|
||||
if (!empty($this->value['type']) && $this->value['type'] == 'offset') {
|
||||
$value = '***CURRENT_TIME***' . sprintf('%+d', $value); // keep sign
|
||||
}
|
||||
$this->query->add_where($this->options['group'], "$field $this->operator %s", $value);
|
||||
}
|
||||
}
|
38
modules/views/handlers/views_handler_filter_equality.inc
Normal file
38
modules/views/handlers/views_handler_filter_equality.inc
Normal file
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
/**
|
||||
* Simple filter to handle equal to / not equal to filters
|
||||
*/
|
||||
class views_handler_filter_equality extends views_handler_filter {
|
||||
// exposed filter options
|
||||
var $no_single = TRUE;
|
||||
|
||||
/**
|
||||
* Provide simple equality operator
|
||||
*/
|
||||
function operator_options() {
|
||||
return array(
|
||||
'=' => t('Is equal to'),
|
||||
'!=' => t('Is not equal to'),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide a simple textfield for equality
|
||||
*/
|
||||
function value_form(&$form, &$form_state) {
|
||||
$form['value'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Value'),
|
||||
'#size' => 30,
|
||||
'#default_value' => $this->value,
|
||||
);
|
||||
|
||||
if (!empty($form_state['exposed'])) {
|
||||
$identifier = $this->options['expose']['identifier'];
|
||||
if (!isset($form_state['input'][$identifier])) {
|
||||
$form_state['input'][$identifier] = $this->value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
22
modules/views/handlers/views_handler_filter_float.inc
Normal file
22
modules/views/handlers/views_handler_filter_float.inc
Normal file
|
@ -0,0 +1,22 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Simple filter to handle greater than/less than filters.
|
||||
* It based on views_handler_filter_numeric but deals with
|
||||
* float numbers.
|
||||
*/
|
||||
class views_handler_filter_float extends views_handler_filter_numeric {
|
||||
function op_between($field) {
|
||||
if ($this->operator == 'between') {
|
||||
$this->query->add_where($this->options['group'], "$field >= %f", $this->value['min']);
|
||||
$this->query->add_where($this->options['group'], "$field <= %f", $this->value['max']);
|
||||
}
|
||||
else {
|
||||
$this->query->add_where($this->options['group'], "$field <= %f OR $field >= %f", $this->value['min'], $this->value['max']);
|
||||
}
|
||||
}
|
||||
|
||||
function op_simple($field) {
|
||||
$this->query->add_where($this->options['group'], "$field $this->operator %f", $this->value['value']);
|
||||
}
|
||||
}
|
364
modules/views/handlers/views_handler_filter_in_operator.inc
Normal file
364
modules/views/handlers/views_handler_filter_in_operator.inc
Normal file
|
@ -0,0 +1,364 @@
|
|||
<?php
|
||||
/**
|
||||
* Simple filter to handle matching of multiple options selectable via checkboxes
|
||||
*
|
||||
* Definition items:
|
||||
* - numeric: If set to true, this item will use numeric operators instead of string.
|
||||
*
|
||||
*/
|
||||
class views_handler_filter_in_operator extends views_handler_filter {
|
||||
var $value_form_type = 'checkboxes';
|
||||
|
||||
function construct() {
|
||||
parent::construct();
|
||||
$this->value_title = t('Options');
|
||||
$this->value_options = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Child classes should be used to override this function and set the
|
||||
* 'value options', unless 'options callback' is defined as a valid function
|
||||
* or static public method to generate these values.
|
||||
*
|
||||
* This can use a guard to be used to reduce database hits as much as
|
||||
* possible.
|
||||
*/
|
||||
function get_value_options() {
|
||||
if (isset($this->value_options)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isset($this->definition['options callback']) && is_callable($this->definition['options callback'])) {
|
||||
$this->value_options = call_user_func($this->definition['options callback']);
|
||||
}
|
||||
else {
|
||||
$this->value_options = array(t('Yes'), t('No'));
|
||||
}
|
||||
}
|
||||
|
||||
function expose_options() {
|
||||
parent::expose_options();
|
||||
$this->options['expose']['reduce'] = FALSE;
|
||||
}
|
||||
|
||||
function expose_form_right(&$form, &$form_state) {
|
||||
parent::expose_form_right($form, $form_state);
|
||||
$form['expose']['reduce'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Limit list to selected items'),
|
||||
'#description' => t('If checked, the only items presented to the user will be the ones selected here.'),
|
||||
'#default_value' => !empty($this->options['expose']['reduce']), // safety
|
||||
);
|
||||
}
|
||||
|
||||
function option_definition() {
|
||||
$options = parent::option_definition();
|
||||
|
||||
$options['operator']['default'] = 'in';
|
||||
$options['value']['default'] = array();
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* This kind of construct makes it relatively easy for a child class
|
||||
* to add or remove functionality by overriding this function and
|
||||
* adding/removing items from this array.
|
||||
*/
|
||||
function operators() {
|
||||
$operators = array(
|
||||
'in' => array(
|
||||
'title' => t('Is one of'),
|
||||
'short' => t('in'),
|
||||
'short_single' => t('='),
|
||||
'method' => 'op_simple',
|
||||
'values' => 1,
|
||||
),
|
||||
'not in' => array(
|
||||
'title' => t('Is not one of'),
|
||||
'short' => t('not in'),
|
||||
'short_single' => t('<>'),
|
||||
'method' => 'op_simple',
|
||||
'values' => 1,
|
||||
),
|
||||
);
|
||||
// if the definition allows for the empty operator, add it.
|
||||
if (!empty($this->definition['allow empty'])) {
|
||||
$operators += array(
|
||||
'empty' => array(
|
||||
'title' => t('Is empty (NULL)'),
|
||||
'method' => 'op_empty',
|
||||
'short' => t('empty'),
|
||||
'values' => 0,
|
||||
),
|
||||
'not empty' => array(
|
||||
'title' => t('Is not empty (NOT NULL)'),
|
||||
'method' => 'op_empty',
|
||||
'short' => t('not empty'),
|
||||
'values' => 0,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return $operators;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build strings from the operators() for 'select' options
|
||||
*/
|
||||
function operator_options($which = 'title') {
|
||||
$options = array();
|
||||
foreach ($this->operators() as $id => $info) {
|
||||
$options[$id] = $info[$which];
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
function operator_values($values = 1) {
|
||||
$options = array();
|
||||
foreach ($this->operators() as $id => $info) {
|
||||
if (isset($info['values']) && $info['values'] == $values) {
|
||||
$options[] = $id;
|
||||
}
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
function value_form(&$form, &$form_state) {
|
||||
$form['value'] = array();
|
||||
|
||||
$this->get_value_options();
|
||||
$options = $this->value_options;
|
||||
$default_value = (array) $this->value;
|
||||
|
||||
$which = 'all';
|
||||
if (!empty($form['operator'])) {
|
||||
$source = ($form['operator']['#type'] == 'radios') ? 'radio:options[operator]' : 'edit-options-operator';
|
||||
}
|
||||
if (!empty($form_state['exposed'])) {
|
||||
$identifier = $this->options['expose']['identifier'];
|
||||
|
||||
if (empty($this->options['expose']['use_operator']) || empty($this->options['expose']['operator'])) {
|
||||
// exposed and locked.
|
||||
$which = in_array($this->operator, $this->operator_values(1)) ? 'value' : 'none';
|
||||
}
|
||||
else {
|
||||
$source = 'edit-' . form_clean_id($this->options['expose']['operator']);
|
||||
}
|
||||
|
||||
if (!empty($this->options['expose']['reduce'])) {
|
||||
$options = $this->reduce_value_options();
|
||||
|
||||
if (empty($this->options['expose']['single']) && !empty($this->options['expose']['optional'])) {
|
||||
$default_value = array();
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($this->options['expose']['single'])) {
|
||||
if (!empty($this->options['expose']['optional']) && (empty($default_value) || !empty($this->options['expose']['reduce']))) {
|
||||
$default_value = 'All';
|
||||
}
|
||||
else if (empty($default_value)) {
|
||||
$keys = array_keys($options);
|
||||
$default_value = array_shift($keys);
|
||||
}
|
||||
else {
|
||||
$copy = $default_value;
|
||||
$default_value = array_shift($copy);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($which == 'all' || $which == 'value') {
|
||||
$form['value'] = array(
|
||||
'#type' => $this->value_form_type,
|
||||
'#title' => $this->value_title,
|
||||
'#options' => $options,
|
||||
'#default_value' => $default_value,
|
||||
// These are only valid for 'select' type, but do no harm to checkboxes.
|
||||
'#multiple' => TRUE,
|
||||
'#size' => count($options) > 8 ? 8 : count($options),
|
||||
);
|
||||
if (!empty($form_state['exposed']) && !isset($form_state['input'][$identifier])) {
|
||||
$form_state['input'][$identifier] = $default_value;
|
||||
}
|
||||
|
||||
$process = array();
|
||||
if ($this->value_form_type == 'checkboxes') {
|
||||
// If this form element will use checkboxes in the UI, we need to
|
||||
// check_plain() all the options ourselves since FAPI is inconsistent
|
||||
// about this. However, instead of directly doing that to the #options
|
||||
// right now, we define a #process callback since we might change our
|
||||
// mind later and convert this into a 'select' form element, which
|
||||
// would lead to double-escaping the options.
|
||||
$process[] = 'views_process_check_options';
|
||||
}
|
||||
if ($which == 'all') {
|
||||
if (empty($form_state['exposed']) && ($this->value_form_type == 'checkboxes' || $this->value_form_type == 'radios')) {
|
||||
$process[] = "expand_$this->value_form_type";
|
||||
$form['value']['#prefix'] = '<div id="edit-options-value-wrapper">';
|
||||
$form['value']['#suffix'] = '</div>';
|
||||
}
|
||||
$process[] = 'views_process_dependency';
|
||||
$form['value']['#dependency'] = array($source => $this->operator_values(1));
|
||||
}
|
||||
if (!empty($process)) {
|
||||
$form['value']['#process'] = $process;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* When using exposed filters, we may be required to reduce the set.
|
||||
*/
|
||||
function reduce_value_options($input = NULL) {
|
||||
if (!isset($input)) {
|
||||
$input = $this->value_options;
|
||||
}
|
||||
|
||||
// Because options may be an array of strings, or an array of mixed arrays
|
||||
// and strings (optgroups) or an array of objects, we have to
|
||||
// step through and handle each one individually.
|
||||
$options = array();
|
||||
foreach ($input as $id => $option) {
|
||||
if (is_array($option)) {
|
||||
$options[$id] = $this->reduce_value_options($option);
|
||||
continue;
|
||||
}
|
||||
else if (is_object($option)) {
|
||||
$keys = array_keys($option->option);
|
||||
$key = array_shift($keys);
|
||||
if (isset($this->options['value'][$key])) {
|
||||
$options[$id] = $option;
|
||||
}
|
||||
}
|
||||
else if (isset($this->options['value'][$id])) {
|
||||
$options[$id] = $option;
|
||||
}
|
||||
}
|
||||
return $options;
|
||||
}
|
||||
|
||||
function accept_exposed_input($input) {
|
||||
// A very special override because the All state for this type of
|
||||
// filter could have a default:
|
||||
if (empty($this->options['exposed'])) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// If this is single and optional, this says that yes this filter will
|
||||
// participate, but using the default settings, *if* 'limit is true.
|
||||
if (!empty($this->options['expose']['single']) && !empty($this->options['expose']['optional']) && !empty($this->options['expose']['limit'])) {
|
||||
$identifier = $this->options['expose']['identifier'];
|
||||
if ($input[$identifier] == 'All') {
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return parent::accept_exposed_input($input);
|
||||
}
|
||||
|
||||
function value_submit($form, &$form_state) {
|
||||
// Drupal's FAPI system automatically puts '0' in for any checkbox that
|
||||
// was not set, and the key to the checkbox if it is set.
|
||||
// Unfortunately, this means that if the key to that checkbox is 0,
|
||||
// we are unable to tell if that checkbox was set or not.
|
||||
|
||||
// Luckily, the '#value' on the checkboxes form actually contains
|
||||
// *only* a list of checkboxes that were set, and we can use that
|
||||
// instead.
|
||||
|
||||
$form_state['values']['options']['value'] = $form['value']['#value'];
|
||||
// $form_state['values']['options']['value'] = array_filter($form_state['values']['options']['value']);
|
||||
}
|
||||
|
||||
function admin_summary() {
|
||||
if (!empty($this->options['exposed'])) {
|
||||
return t('exposed');
|
||||
}
|
||||
$info = $this->operators();
|
||||
|
||||
$this->get_value_options();
|
||||
|
||||
if (!is_array($this->value)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$operator = check_plain($info[$this->operator]['short']);
|
||||
$values = '';
|
||||
if (in_array($this->operator, $this->operator_values(1))) {
|
||||
// Remove every element which is not known.
|
||||
foreach ($this->value as $value) {
|
||||
if (!isset($this->value_options[$value])) {
|
||||
unset($this->value[$value]);
|
||||
}
|
||||
}
|
||||
// Choose different kind of ouput for 0, a single and multiple values.
|
||||
if (count($this->value) == 0) {
|
||||
$values = t('Unknown');
|
||||
}
|
||||
else if (count($this->value) == 1) {
|
||||
// If any, use the 'single' short name of the operator instead.
|
||||
if (isset($info[$this->operator]['short_single'])) {
|
||||
$operator = check_plain($info[$this->operator]['short_single']);
|
||||
}
|
||||
|
||||
$keys = $this->value;
|
||||
$value = array_shift($keys);
|
||||
$values = check_plain($this->value_options[$value]);
|
||||
}
|
||||
else {
|
||||
foreach ($this->value as $value) {
|
||||
if ($values !== '') {
|
||||
$values .= ', ';
|
||||
}
|
||||
if (strlen($values) > 8) {
|
||||
$values .= '...';
|
||||
break;
|
||||
}
|
||||
$values .= check_plain($this->value_options[$value]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $operator . (($values !== '') ? ' ' . $values : '');
|
||||
}
|
||||
|
||||
function query() {
|
||||
$info = $this->operators();
|
||||
if (!empty($info[$this->operator]['method'])) {
|
||||
$this->{$info[$this->operator]['method']}();
|
||||
}
|
||||
}
|
||||
|
||||
function op_simple() {
|
||||
if (empty($this->value)) {
|
||||
return;
|
||||
}
|
||||
$this->ensure_my_table();
|
||||
$placeholder = !empty($this->definition['numeric']) ? '%d' : "'%s'";
|
||||
|
||||
$replace = array_fill(0, sizeof($this->value), $placeholder);
|
||||
$in = ' (' . implode(", ", $replace) . ')';
|
||||
|
||||
// We use array_values() because the checkboxes keep keys and that can cause
|
||||
// array addition problems.
|
||||
$this->query->add_where($this->options['group'], "$this->table_alias.$this->real_field " . $this->operator . $in, array_values($this->value));
|
||||
}
|
||||
|
||||
function op_empty() {
|
||||
$this->ensure_my_table();
|
||||
$field = "$this->table_alias.$this->real_field";
|
||||
|
||||
if ($this->operator == 'empty') {
|
||||
$operator = "IS NULL";
|
||||
}
|
||||
else {
|
||||
$operator = "IS NOT NULL";
|
||||
}
|
||||
|
||||
$this->query->add_where($this->options['group'], "$field $operator");
|
||||
}
|
||||
}
|
103
modules/views/handlers/views_handler_filter_many_to_one.inc
Normal file
103
modules/views/handlers/views_handler_filter_many_to_one.inc
Normal file
|
@ -0,0 +1,103 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Complex filter to handle filtering for many to one relationships,
|
||||
* such as terms (many terms per node) or roles (many roles per user).
|
||||
*
|
||||
* The construct method needs to be overridden to provide a list of options;
|
||||
* alternately, the value_form and admin_summary methods need to be overriden
|
||||
* to provide something that isn't just a select list.
|
||||
*/
|
||||
class views_handler_filter_many_to_one extends views_handler_filter_in_operator {
|
||||
function init(&$view, $options) {
|
||||
parent::init($view, $options);
|
||||
$this->helper = new views_many_to_one_helper($this);
|
||||
}
|
||||
|
||||
function option_definition() {
|
||||
$options = parent::option_definition();
|
||||
|
||||
$options['operator']['default'] = 'or';
|
||||
$options['value']['default'] = array();
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
function operators() {
|
||||
$operators = array(
|
||||
'or' => array(
|
||||
'title' => t('Is one of'),
|
||||
'short' => t('or'),
|
||||
'short_single' => t('='),
|
||||
'method' => 'op_helper',
|
||||
'values' => 1,
|
||||
'ensure_my_table' => 'helper',
|
||||
),
|
||||
'and' => array(
|
||||
'title' => t('Is all of'),
|
||||
'short' => t('and'),
|
||||
'short_single' => t('='),
|
||||
'method' => 'op_helper',
|
||||
'values' => 1,
|
||||
'ensure_my_table' => 'helper',
|
||||
),
|
||||
'not' => array(
|
||||
'title' => t('Is none of'),
|
||||
'short' => t('not'),
|
||||
'short_single' => t('<>'),
|
||||
'method' => 'op_helper',
|
||||
'values' => 1,
|
||||
'ensure_my_table' => 'helper',
|
||||
),
|
||||
);
|
||||
// if the definition allows for the empty operator, add it.
|
||||
if (!empty($this->definition['allow empty'])) {
|
||||
$operators += array(
|
||||
'empty' => array(
|
||||
'title' => t('Is empty (NULL)'),
|
||||
'method' => 'op_empty',
|
||||
'short' => t('empty'),
|
||||
'values' => 0,
|
||||
),
|
||||
'not empty' => array(
|
||||
'title' => t('Is not empty (NOT NULL)'),
|
||||
'method' => 'op_empty',
|
||||
'short' => t('not empty'),
|
||||
'values' => 0,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return $operators;
|
||||
}
|
||||
|
||||
var $value_form_type = 'select';
|
||||
function value_form(&$form, &$form_state) {
|
||||
parent::value_form($form, $form_state);
|
||||
|
||||
if (empty($form_state['exposed'])) {
|
||||
$this->helper->options_form($form, $form_state);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Override ensure_my_table so we can control how this joins in.
|
||||
* The operator actually has influence over joining.
|
||||
*/
|
||||
function ensure_my_table() {
|
||||
// Defer to helper if the operator specifies it.
|
||||
$info = $this->operators();
|
||||
if (isset($info[$this->operator]['ensure_my_table']) && $info[$this->operator]['ensure_my_table'] == 'helper') {
|
||||
return $this->helper->ensure_my_table();
|
||||
}
|
||||
|
||||
return parent::ensure_my_table();
|
||||
}
|
||||
|
||||
function op_helper() {
|
||||
if (empty($this->value)) {
|
||||
return;
|
||||
}
|
||||
$this->helper->add_filter();
|
||||
}
|
||||
}
|
302
modules/views/handlers/views_handler_filter_numeric.inc
Normal file
302
modules/views/handlers/views_handler_filter_numeric.inc
Normal file
|
@ -0,0 +1,302 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Simple filter to handle greater than/less than filters
|
||||
*/
|
||||
class views_handler_filter_numeric extends views_handler_filter {
|
||||
var $no_single = TRUE;
|
||||
function option_definition() {
|
||||
$options = parent::option_definition();
|
||||
|
||||
$options['value'] = array(
|
||||
'contains' => array(
|
||||
'min' => array('default' => ''),
|
||||
'max' => array('default' => ''),
|
||||
'value' => array('default' => ''),
|
||||
),
|
||||
);
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
function operators() {
|
||||
$operators = array(
|
||||
'<' => array(
|
||||
'title' => t('Is less than'),
|
||||
'method' => 'op_simple',
|
||||
'short' => t('<'),
|
||||
'values' => 1,
|
||||
),
|
||||
'<=' => array(
|
||||
'title' => t('Is less than or equal to'),
|
||||
'method' => 'op_simple',
|
||||
'short' => t('<='),
|
||||
'values' => 1,
|
||||
),
|
||||
'=' => array(
|
||||
'title' => t('Is equal to'),
|
||||
'method' => 'op_simple',
|
||||
'short' => t('='),
|
||||
'values' => 1,
|
||||
),
|
||||
'!=' => array(
|
||||
'title' => t('Is not equal to'),
|
||||
'method' => 'op_simple',
|
||||
'short' => t('!='),
|
||||
'values' => 1,
|
||||
),
|
||||
'>=' => array(
|
||||
'title' => t('Is greater than or equal to'),
|
||||
'method' => 'op_simple',
|
||||
'short' => t('>='),
|
||||
'values' => 1,
|
||||
),
|
||||
'>' => array(
|
||||
'title' => t('Is greater than'),
|
||||
'method' => 'op_simple',
|
||||
'short' => t('>'),
|
||||
'values' => 1,
|
||||
),
|
||||
'between' => array(
|
||||
'title' => t('Is between'),
|
||||
'method' => 'op_between',
|
||||
'short' => t('between'),
|
||||
'values' => 2,
|
||||
),
|
||||
'not between' => array(
|
||||
'title' => t('Is not between'),
|
||||
'method' => 'op_between',
|
||||
'short' => t('not between'),
|
||||
'values' => 2,
|
||||
),
|
||||
);
|
||||
|
||||
// if the definition allows for the empty operator, add it.
|
||||
if (!empty($this->definition['allow empty'])) {
|
||||
$operators += array(
|
||||
'empty' => array(
|
||||
'title' => t('Is empty (NULL)'),
|
||||
'method' => 'op_empty',
|
||||
'short' => t('empty'),
|
||||
'values' => 0,
|
||||
),
|
||||
'not empty' => array(
|
||||
'title' => t('Is not empty (NOT NULL)'),
|
||||
'method' => 'op_empty',
|
||||
'short' => t('not empty'),
|
||||
'values' => 0,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return $operators;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide a list of all the numeric operators
|
||||
*/
|
||||
function operator_options($which = 'title') {
|
||||
$options = array();
|
||||
foreach ($this->operators() as $id => $info) {
|
||||
$options[$id] = $info[$which];
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
function operator_values($values = 1) {
|
||||
$options = array();
|
||||
foreach ($this->operators() as $id => $info) {
|
||||
if ($info['values'] == $values) {
|
||||
$options[] = $id;
|
||||
}
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
/**
|
||||
* Provide a simple textfield for equality
|
||||
*/
|
||||
function value_form(&$form, &$form_state) {
|
||||
$form['value']['#tree'] = TRUE;
|
||||
|
||||
// We have to make some choices when creating this as an exposed
|
||||
// filter form. For example, if the operator is locked and thus
|
||||
// not rendered, we can't render dependencies; instead we only
|
||||
// render the form items we need.
|
||||
$which = 'all';
|
||||
if (!empty($form['operator'])) {
|
||||
$source = ($form['operator']['#type'] == 'radios') ? 'radio:options[operator]' : 'edit-options-operator';
|
||||
}
|
||||
|
||||
if (!empty($form_state['exposed'])) {
|
||||
$identifier = $this->options['expose']['identifier'];
|
||||
|
||||
if (empty($this->options['expose']['use_operator']) || empty($this->options['expose']['operator'])) {
|
||||
// exposed and locked.
|
||||
$which = in_array($this->operator, $this->operator_values(2)) ? 'minmax' : 'value';
|
||||
}
|
||||
else {
|
||||
$source = 'edit-' . form_clean_id($this->options['expose']['operator']);
|
||||
}
|
||||
}
|
||||
|
||||
if ($which == 'all') {
|
||||
$form['value']['value'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => empty($form_state['exposed']) ? t('Value') : '',
|
||||
'#size' => 30,
|
||||
'#default_value' => $this->value['value'],
|
||||
'#process' => array('views_process_dependency'),
|
||||
'#dependency' => array($source => $this->operator_values(1)),
|
||||
);
|
||||
if (!empty($form_state['exposed']) && !isset($form_state['input'][$identifier]['value'])) {
|
||||
$form_state['input'][$identifier]['value'] = $this->value['value'];
|
||||
}
|
||||
}
|
||||
else if ($which == 'value') {
|
||||
// When exposed we drop the value-value and just do value if
|
||||
// the operator is locked.
|
||||
$form['value'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => empty($form_state['exposed']) ? t('Value') : '',
|
||||
'#size' => 30,
|
||||
'#default_value' => $this->value['value'],
|
||||
);
|
||||
if (!empty($form_state['exposed']) && !isset($form_state['input'][$identifier])) {
|
||||
$form_state['input'][$identifier] = $this->value['value'];
|
||||
}
|
||||
}
|
||||
|
||||
if ($which == 'all' || $which == 'minmax') {
|
||||
$form['value']['min'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => empty($form_state['exposed']) ? t('Min') : '',
|
||||
'#size' => 30,
|
||||
'#default_value' => $this->value['min'],
|
||||
);
|
||||
$form['value']['max'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => empty($form_state['exposed']) ? t('And max') : t('And'),
|
||||
'#size' => 30,
|
||||
'#default_value' => $this->value['max'],
|
||||
);
|
||||
if ($which == 'all') {
|
||||
$dependency = array(
|
||||
'#process' => array('views_process_dependency'),
|
||||
'#dependency' => array($source => $this->operator_values(2)),
|
||||
);
|
||||
$form['value']['min'] += $dependency;
|
||||
$form['value']['max'] += $dependency;
|
||||
}
|
||||
if (!empty($form_state['exposed']) && !isset($form_state['input'][$identifier]['min'])) {
|
||||
$form_state['input'][$identifier]['min'] = $this->value['min'];
|
||||
}
|
||||
if (!empty($form_state['exposed']) && !isset($form_state['input'][$identifier]['max'])) {
|
||||
$form_state['input'][$identifier]['max'] = $this->value['max'];
|
||||
}
|
||||
|
||||
if (!isset($form['value'])) {
|
||||
// Ensure there is something in the 'value'.
|
||||
$form['value'] = array(
|
||||
'#type' => 'value',
|
||||
'#value' => NULL
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function query() {
|
||||
$this->ensure_my_table();
|
||||
$field = "$this->table_alias.$this->real_field";
|
||||
|
||||
$info = $this->operators();
|
||||
if (!empty($info[$this->operator]['method'])) {
|
||||
$this->{$info[$this->operator]['method']}($field);
|
||||
}
|
||||
}
|
||||
|
||||
function op_between($field) {
|
||||
if ($this->operator == 'between') {
|
||||
$this->query->add_where($this->options['group'], "$field >= %d", $this->value['min']);
|
||||
$this->query->add_where($this->options['group'], "$field <= %d", $this->value['max']);
|
||||
}
|
||||
else {
|
||||
$this->query->add_where($this->options['group'], "$field <= %d OR $field >= %d", $this->value['min'], $this->value['max']);
|
||||
}
|
||||
}
|
||||
|
||||
function op_simple($field) {
|
||||
$this->query->add_where($this->options['group'], "$field $this->operator %d", $this->value['value']);
|
||||
}
|
||||
|
||||
function op_empty($field) {
|
||||
if ($this->operator == 'empty') {
|
||||
$operator = "IS NULL";
|
||||
}
|
||||
else {
|
||||
$operator = "IS NOT NULL";
|
||||
}
|
||||
|
||||
$this->query->add_where($this->options['group'], "$field $operator");
|
||||
}
|
||||
|
||||
function admin_summary() {
|
||||
if (!empty($this->options['exposed'])) {
|
||||
return t('exposed');
|
||||
}
|
||||
|
||||
$options = $this->operator_options('short');
|
||||
$output = check_plain($options[$this->operator]);
|
||||
if (in_array($this->operator, $this->operator_values(2))) {
|
||||
$output .= ' ' . t('@min and @max', array('@min' => $this->value['min'], '@max' => $this->value['max']));
|
||||
}
|
||||
elseif (in_array($this->operator, $this->operator_values(1))) {
|
||||
$output .= ' ' . check_plain($this->value['value']);
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Do some minor translation of the exposed input
|
||||
*/
|
||||
function accept_exposed_input($input) {
|
||||
if (empty($this->options['exposed'])) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// rewrite the input value so that it's in the correct format so that
|
||||
// the parent gets the right data.
|
||||
if (!empty($this->options['expose']['identifier'])) {
|
||||
$value = &$input[$this->options['expose']['identifier']];
|
||||
if (!is_array($value)) {
|
||||
$value = array(
|
||||
'value' => $value,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$rc = parent::accept_exposed_input($input);
|
||||
|
||||
if (!empty($this->options['expose']['optional'])) {
|
||||
// We have to do some of our own optional checking.
|
||||
$info = $this->operators();
|
||||
if (!empty($info[$this->operator]['values'])) {
|
||||
switch ($info[$this->operator]['values']) {
|
||||
case 1:
|
||||
if ($value['value'] === '') {
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if ($value['min'] === '' && $value['max'] === '') {
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $rc;
|
||||
}
|
||||
}
|
303
modules/views/handlers/views_handler_filter_string.inc
Normal file
303
modules/views/handlers/views_handler_filter_string.inc
Normal file
|
@ -0,0 +1,303 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Basic textfield filter to handle string filtering commands
|
||||
* including equality, like, not like, etc.
|
||||
*/
|
||||
class views_handler_filter_string extends views_handler_filter {
|
||||
// exposed filter options
|
||||
var $no_single = TRUE;
|
||||
var $no_optional = TRUE;
|
||||
|
||||
function option_definition() {
|
||||
$options = parent::option_definition();
|
||||
|
||||
$options['expose']['contains']['optional'] = array('default' => FALSE);
|
||||
$options['case'] = array('default' => TRUE);
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* This kind of construct makes it relatively easy for a child class
|
||||
* to add or remove functionality by overriding this function and
|
||||
* adding/removing items from this array.
|
||||
*/
|
||||
function operators() {
|
||||
$operators = array(
|
||||
'=' => array(
|
||||
'title' => t('Is equal to'),
|
||||
'short' => t('='),
|
||||
'method' => 'op_equal',
|
||||
'values' => 1,
|
||||
),
|
||||
'!=' => array(
|
||||
'title' => t('Is not equal to'),
|
||||
'short' => t('!='),
|
||||
'method' => 'op_equal',
|
||||
'values' => 1,
|
||||
),
|
||||
'contains' => array(
|
||||
'title' => t('Contains'),
|
||||
'short' => t('contains'),
|
||||
'method' => 'op_contains',
|
||||
'values' => 1,
|
||||
),
|
||||
'word' => array(
|
||||
'title' => t('Contains any word'),
|
||||
'short' => t('has word'),
|
||||
'method' => 'op_word',
|
||||
'values' => 1,
|
||||
),
|
||||
'allwords' => array(
|
||||
'title' => t('Contains all words'),
|
||||
'short' => t('has all'),
|
||||
'method' => 'op_word',
|
||||
'values' => 1,
|
||||
),
|
||||
'starts' => array(
|
||||
'title' => t('Starts with'),
|
||||
'short' => t('begins'),
|
||||
'method' => 'op_starts',
|
||||
'values' => 1,
|
||||
),
|
||||
'not_starts' => array(
|
||||
'title' => t('Does not start with'),
|
||||
'short' => t('not_begins'),
|
||||
'method' => 'op_not_starts',
|
||||
'values' => 1,
|
||||
),
|
||||
'ends' => array(
|
||||
'title' => t('Ends with'),
|
||||
'short' => t('ends'),
|
||||
'method' => 'op_ends',
|
||||
'values' => 1,
|
||||
),
|
||||
'not_ends' => array(
|
||||
'title' => t('Does not end with'),
|
||||
'short' => t('not_ends'),
|
||||
'method' => 'op_not_ends',
|
||||
'values' => 1,
|
||||
),
|
||||
'not' => array(
|
||||
'title' => t('Does not contain'),
|
||||
'short' => t('!has'),
|
||||
'method' => 'op_not',
|
||||
'values' => 1,
|
||||
),
|
||||
);
|
||||
// if the definition allows for the empty operator, add it.
|
||||
if (!empty($this->definition['allow empty'])) {
|
||||
$operators += array(
|
||||
'empty' => array(
|
||||
'title' => t('Is empty (NULL)'),
|
||||
'method' => 'op_empty',
|
||||
'short' => t('empty'),
|
||||
'values' => 0,
|
||||
),
|
||||
'not empty' => array(
|
||||
'title' => t('Is not empty (NOT NULL)'),
|
||||
'method' => 'op_empty',
|
||||
'short' => t('not empty'),
|
||||
'values' => 0,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return $operators;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build strings from the operators() for 'select' options
|
||||
*/
|
||||
function operator_options($which = 'title') {
|
||||
$options = array();
|
||||
foreach ($this->operators() as $id => $info) {
|
||||
$options[$id] = $info[$which];
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
function admin_summary() {
|
||||
if (!empty($this->options['exposed'])) {
|
||||
return t('exposed');
|
||||
}
|
||||
|
||||
$options = $this->operator_options('short');
|
||||
$output = check_plain($options[$this->operator]);
|
||||
if (in_array($this->operator, $this->operator_values(1))) {
|
||||
$output .= ' ' . check_plain($this->value);
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
function options_form(&$form, &$form_state) {
|
||||
parent::options_form($form, $form_state);
|
||||
$form['case'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Case sensitive'),
|
||||
'#default_value' => $this->options['case'],
|
||||
'#description' => t('Case sensitive filters may be faster. MySQL might ignore case sensitivity.'),
|
||||
);
|
||||
}
|
||||
|
||||
function operator_values($values = 1) {
|
||||
$options = array();
|
||||
foreach ($this->operators() as $id => $info) {
|
||||
if (isset($info['values']) && $info['values'] == $values) {
|
||||
$options[] = $id;
|
||||
}
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide a simple textfield for equality
|
||||
*/
|
||||
function value_form(&$form, &$form_state) {
|
||||
// We have to make some choices when creating this as an exposed
|
||||
// filter form. For example, if the operator is locked and thus
|
||||
// not rendered, we can't render dependencies; instead we only
|
||||
// render the form items we need.
|
||||
$which = 'all';
|
||||
if (!empty($form['operator'])) {
|
||||
$source = ($form['operator']['#type'] == 'radios') ? 'radio:options[operator]' : 'edit-options-operator';
|
||||
}
|
||||
if (!empty($form_state['exposed'])) {
|
||||
$identifier = $this->options['expose']['identifier'];
|
||||
|
||||
if (empty($this->options['expose']['use_operator']) || empty($this->options['expose']['operator'])) {
|
||||
// exposed and locked.
|
||||
$which = in_array($this->operator, $this->operator_values(1)) ? 'value' : 'none';
|
||||
}
|
||||
else {
|
||||
$source = 'edit-' . form_clean_id($this->options['expose']['operator']);
|
||||
}
|
||||
}
|
||||
|
||||
if ($which == 'all' || $which == 'value') {
|
||||
$form['value'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Value'),
|
||||
'#size' => 30,
|
||||
'#default_value' => $this->value,
|
||||
);
|
||||
if (!empty($form_state['exposed']) && !isset($form_state['input'][$identifier])) {
|
||||
$form_state['input'][$identifier] = $this->value;
|
||||
}
|
||||
|
||||
if ($which == 'all') {
|
||||
$form['value'] += array(
|
||||
'#process' => array('views_process_dependency'),
|
||||
'#dependency' => array($source => $this->operator_values(1)),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (!isset($form['value'])) {
|
||||
// Ensure there is something in the 'value'.
|
||||
$form['value'] = array(
|
||||
'#type' => 'value',
|
||||
'#value' => NULL
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function case_transform() {
|
||||
return !empty($this->options['case']) ? '' : 'UPPER';
|
||||
}
|
||||
|
||||
/**
|
||||
* Add this filter to the query.
|
||||
*
|
||||
* Due to the nature of fapi, the value and the operator have an unintended
|
||||
* level of indirection. You will find them in $this->operator
|
||||
* and $this->value respectively.
|
||||
*/
|
||||
function query() {
|
||||
$this->ensure_my_table();
|
||||
$field = "$this->table_alias.$this->real_field";
|
||||
$upper = $this->case_transform();
|
||||
|
||||
$info = $this->operators();
|
||||
if (!empty($info[$this->operator]['method'])) {
|
||||
$this->{$info[$this->operator]['method']}($field, $upper);
|
||||
}
|
||||
}
|
||||
|
||||
function op_equal($field, $upper) {
|
||||
// operator is either = or !=
|
||||
$this->query->add_where($this->options['group'], "$upper($field) $this->operator $upper('%s')", $this->value);
|
||||
}
|
||||
|
||||
function op_contains($field, $upper) {
|
||||
$this->query->add_where($this->options['group'], "$upper($field) LIKE $upper('%%%s%%')", $this->value);
|
||||
}
|
||||
|
||||
function op_word($field, $upper) {
|
||||
$where = array();
|
||||
preg_match_all('/ (-?)("[^"]+"|[^" ]+)/i', ' ' . $this->value, $matches, PREG_SET_ORDER);
|
||||
foreach ($matches as $match) {
|
||||
$phrase = false;
|
||||
// Strip off phrase quotes
|
||||
if ($match[2]{0} == '"') {
|
||||
$match[2] = substr($match[2], 1, -1);
|
||||
$phrase = true;
|
||||
}
|
||||
$words = trim($match[2], ',?!();:-');
|
||||
$words = $phrase ? array($words) : preg_split('/ /', $words, -1, PREG_SPLIT_NO_EMPTY);
|
||||
foreach ($words as $word) {
|
||||
$where[] = "$upper($field) LIKE $upper('%%%s%%')";
|
||||
$values[] = trim($word, " ,!?");
|
||||
}
|
||||
}
|
||||
|
||||
if (!$where) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->operator == 'word') {
|
||||
$where = '(' . implode(' OR ', $where) . ')';
|
||||
}
|
||||
else {
|
||||
$where = implode(' AND ', $where);
|
||||
}
|
||||
// previously this was a call_user_func_array but that's unnecessary
|
||||
// as views will unpack an array that is a single arg.
|
||||
$this->query->add_where($this->options['group'], $where, $values);
|
||||
}
|
||||
|
||||
function op_starts($field, $upper) {
|
||||
$this->query->add_where($this->options['group'], "$upper($field) LIKE $upper('%s%%')", $this->value);
|
||||
}
|
||||
|
||||
function op_not_starts($field, $upper) {
|
||||
$this->query->add_where($this->options['group'], "$upper($field) NOT LIKE $upper('%s%%')", $this->value);
|
||||
}
|
||||
|
||||
function op_ends($field, $upper) {
|
||||
$this->query->add_where($this->options['group'], "$upper($field) LIKE $upper('%%%s')", $this->value);
|
||||
}
|
||||
|
||||
function op_not_ends($field, $upper) {
|
||||
$this->query->add_where($this->options['group'], "$upper($field) NOT LIKE $upper('%%%s')", $this->value);
|
||||
}
|
||||
|
||||
function op_not($field, $upper) {
|
||||
$this->query->add_where($this->options['group'], "$upper($field) NOT LIKE $upper('%%%s%%')", $this->value);
|
||||
}
|
||||
|
||||
function op_empty($field) {
|
||||
if ($this->operator == 'empty') {
|
||||
$operator = "IS NULL";
|
||||
}
|
||||
else {
|
||||
$operator = "IS NOT NULL";
|
||||
}
|
||||
|
||||
$this->query->add_where($this->options['group'], "$field $operator");
|
||||
}
|
||||
|
||||
}
|
152
modules/views/handlers/views_handler_relationship.inc
Normal file
152
modules/views/handlers/views_handler_relationship.inc
Normal file
|
@ -0,0 +1,152 @@
|
|||
<?php
|
||||
/**
|
||||
* @file
|
||||
* Views' relationship handlers.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup views_relationship_handlers Views' relationship handlers
|
||||
* @{
|
||||
* Handlers to tell Views how to create alternate relationships.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Simple relationship handler that allows a new version of the primary table
|
||||
* to be linked in.
|
||||
*
|
||||
* The base relationship handler can only handle a single join. Some relationships
|
||||
* are more complex and might require chains of joins; for those, you must
|
||||
* utilize a custom relationship handler.
|
||||
*
|
||||
* Definition items:
|
||||
* - base: The new base table this relationship will be adding. This does not
|
||||
* have to be a declared base table, but if there are no tables that
|
||||
* utilize this base table, it won't be very effective.
|
||||
* - base field: The field to use in the relationship; if left out this will be
|
||||
* assumed to be the primary field.
|
||||
* - relationship table: The actual table this relationship operates against.
|
||||
* This is analogous to using a 'table' override.
|
||||
* - relationship field: The actual field this relationship operates against.
|
||||
* This is analogous to using a 'real field' override.
|
||||
* - label: The default label to provide for this relationship, which is
|
||||
* shown in parentheses next to any field/sort/filter/argument that uses
|
||||
* the relationship.
|
||||
*/
|
||||
class views_handler_relationship extends views_handler {
|
||||
/**
|
||||
* Init handler to let relationships live on tables other than
|
||||
* the table they operate on.
|
||||
*/
|
||||
function init(&$view, $options) {
|
||||
parent::init($view, $options);
|
||||
if (isset($this->definition['relationship table'])) {
|
||||
$this->table = $this->definition['relationship table'];
|
||||
}
|
||||
if (isset($this->definition['relationship field'])) {
|
||||
$this->field = $this->definition['relationship field'];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get this field's label.
|
||||
*/
|
||||
function label() {
|
||||
if (!isset($this->options['label'])) {
|
||||
return $this->ui_name();
|
||||
}
|
||||
return $this->options['label'];
|
||||
}
|
||||
|
||||
function option_definition() {
|
||||
$options = parent::option_definition();
|
||||
|
||||
$label = !empty($this->definition['label']) ? $this->definition['label'] : $this->definition['field'];
|
||||
$options['label'] = array('default' => $label, 'translatable' => TRUE);
|
||||
$options['required'] = array('default' => FALSE);
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Default options form that provides the label widget that all fields
|
||||
* should have.
|
||||
*/
|
||||
function options_form(&$form, &$form_state) {
|
||||
$form['label'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Label'),
|
||||
'#default_value' => isset($this->options['label']) ? $this->options['label'] : '',
|
||||
'#description' => t('The label for this relationship that will be displayed only administratively.'),
|
||||
);
|
||||
|
||||
$form['required'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Require this relationship'),
|
||||
'#description' => t('If required, items that do not contain this relationship will not appear.'),
|
||||
'#default_value' => !empty($this->options['required']),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called to implement a relationship in a query.
|
||||
*/
|
||||
function query() {
|
||||
// Figure out what base table this relationship brings to the party.
|
||||
$table_data = views_fetch_data($this->definition['base']);
|
||||
$base_field = empty($this->definition['base field']) ? $table_data['table']['base']['field'] : $this->definition['base field'];
|
||||
|
||||
$this->ensure_my_table();
|
||||
|
||||
$def = $this->definition;
|
||||
$def['table'] = $this->definition['base'];
|
||||
$def['field'] = $base_field;
|
||||
$def['left_table'] = $this->table_alias;
|
||||
$def['left_field'] = $this->field;
|
||||
if (!empty($this->options['required'])) {
|
||||
$def['type'] = 'INNER';
|
||||
}
|
||||
|
||||
if (!empty($def['join_handler']) && class_exists($def['join_handler'])) {
|
||||
$join = new $def['join_handler'];
|
||||
}
|
||||
else {
|
||||
$join = new views_join();
|
||||
}
|
||||
|
||||
$join->definition = $def;
|
||||
$join->construct();
|
||||
$join->adjusted = TRUE;
|
||||
|
||||
// use a short alias for this:
|
||||
$alias = $def['table'] . '_' . $this->table;
|
||||
|
||||
$this->alias = $this->query->add_relationship($alias, $join, $this->definition['base'], $this->relationship);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A special handler to take the place of missing or broken handlers.
|
||||
*/
|
||||
class views_handler_relationship_broken extends views_handler_relationship {
|
||||
function ui_name($short = FALSE) {
|
||||
return t('Broken/missing handler');
|
||||
}
|
||||
|
||||
function ensure_my_table() { /* No table to ensure! */ }
|
||||
function query() { /* No query to run */ }
|
||||
function options_form(&$form, &$form_state) {
|
||||
$form['markup'] = array(
|
||||
'#prefix' => '<div class="form-item description">',
|
||||
'#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.'),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the handler is considered 'broken'
|
||||
*/
|
||||
function broken() { return TRUE; }
|
||||
}
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
86
modules/views/handlers/views_handler_sort.inc
Normal file
86
modules/views/handlers/views_handler_sort.inc
Normal file
|
@ -0,0 +1,86 @@
|
|||
<?php
|
||||
/**
|
||||
* @defgroup views_sort_handlers Views' sort handlers
|
||||
* @{
|
||||
* Handlers to tell Views how to sort queries
|
||||
*/
|
||||
|
||||
/**
|
||||
* Base sort handler that has no options and performs a simple sort
|
||||
*/
|
||||
class views_handler_sort extends views_handler {
|
||||
/**
|
||||
* Called to add the sort to a query.
|
||||
*/
|
||||
function query() {
|
||||
$this->ensure_my_table();
|
||||
// Add the field.
|
||||
$this->query->add_orderby($this->table_alias, $this->real_field, $this->options['order']);
|
||||
}
|
||||
|
||||
function option_definition() {
|
||||
$options = parent::option_definition();
|
||||
|
||||
$options['order'] = array('default' => 'ASC');
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display whether or not the sort order is ascending or descending
|
||||
*/
|
||||
function admin_summary() {
|
||||
switch ($this->options['order']) {
|
||||
case 'ASC':
|
||||
case 'asc':
|
||||
default:
|
||||
$type = t('asc');
|
||||
break;
|
||||
case 'DESC';
|
||||
case 'desc';
|
||||
$type = t('desc');
|
||||
break;
|
||||
}
|
||||
return '<span class="views-ascending"><span>' . $type . '</span></span>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Basic options for all sort criteria
|
||||
*/
|
||||
function options_form(&$form, &$form_state) {
|
||||
$form['order'] = array(
|
||||
'#type' => 'radios',
|
||||
'#title' => t('Sort order'),
|
||||
'#options' => array('ASC' => t('Ascending'), 'DESC' => t('Descending')),
|
||||
'#default_value' => $this->options['order'],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A special handler to take the place of missing or broken handlers.
|
||||
*/
|
||||
class views_handler_sort_broken extends views_handler_sort {
|
||||
function ui_name($short = FALSE) {
|
||||
return t('Broken/missing handler');
|
||||
}
|
||||
|
||||
function ensure_my_table() { /* No table to ensure! */ }
|
||||
function query() { /* No query to run */ }
|
||||
function options_form(&$form, &$form_state) {
|
||||
$form['markup'] = array(
|
||||
'#prefix' => '<div class="form-item description">',
|
||||
'#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.'),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the handler is considered 'broken'
|
||||
*/
|
||||
function broken() { return TRUE; }
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
69
modules/views/handlers/views_handler_sort_date.inc
Normal file
69
modules/views/handlers/views_handler_sort_date.inc
Normal file
|
@ -0,0 +1,69 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Basic sort handler for dates.
|
||||
*
|
||||
* This handler enables granularity, which is the ability to make dates
|
||||
* equivalent based upon nearness.
|
||||
*
|
||||
* @ingroup views_sort_handlers
|
||||
*/
|
||||
class views_handler_sort_date extends views_handler_sort {
|
||||
function option_definition() {
|
||||
$options = parent::option_definition();
|
||||
|
||||
$options['granularity'] = array('default' => 'second');
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
function options_form(&$form, &$form_state) {
|
||||
parent::options_form($form, $form_state);
|
||||
|
||||
$form['granularity'] = array(
|
||||
'#type' => 'radios',
|
||||
'#title' => t('Granularity'),
|
||||
'#options' => array(
|
||||
'second' => t('Second'),
|
||||
'minute' => t('Minute'),
|
||||
'hour' => t('Hour'),
|
||||
'day' => t('Day'),
|
||||
'month' => t('Month'),
|
||||
'year' => t('Year'),
|
||||
),
|
||||
'#description' => t('The granularity is the smallest unit to use when determining whether two dates are the same; for example, if the granularity is "Year" then all dates in 1999, regardless of when they fall in 1999, will be considered the same date.'),
|
||||
'#default_value' => $this->options['granularity'],
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called to add the sort to a query.
|
||||
*/
|
||||
function query() {
|
||||
$this->ensure_my_table();
|
||||
switch ($this->options['granularity']) {
|
||||
case 'second':
|
||||
default:
|
||||
$this->query->add_orderby($this->table_alias, $this->real_field, $this->options['order']);
|
||||
return;
|
||||
case 'minute':
|
||||
$formula = views_date_sql_format('YmdHi', "$this->table_alias.$this->real_field");
|
||||
break;
|
||||
case 'hour':
|
||||
$formula = views_date_sql_format('YmdH', "$this->table_alias.$this->real_field");
|
||||
break;
|
||||
case 'day':
|
||||
$formula = views_date_sql_format('Ymd', "$this->table_alias.$this->real_field");
|
||||
break;
|
||||
case 'month':
|
||||
$formula = views_date_sql_format('Ym', "$this->table_alias.$this->real_field");
|
||||
break;
|
||||
case 'year':
|
||||
$formula = views_date_sql_format('Y', "$this->table_alias.$this->real_field");
|
||||
break;
|
||||
}
|
||||
|
||||
// Add the field.
|
||||
$this->query->add_orderby(NULL, $formula, $this->options['order'], $this->table_alias . '_' . $this->field . '_' . $this->options['granularity']);
|
||||
}
|
||||
}
|
47
modules/views/handlers/views_handler_sort_formula.inc
Normal file
47
modules/views/handlers/views_handler_sort_formula.inc
Normal file
|
@ -0,0 +1,47 @@
|
|||
<?php
|
||||
/**
|
||||
* Base sort handler that has no options and performs a simple sort
|
||||
*
|
||||
* Definition items:
|
||||
* - formula: The formula to use to sort on, such as with a random sort.
|
||||
* The formula should be an array, with keys for database
|
||||
* types, and 'default' for non-specified. 'default' is
|
||||
* required, all others ('mysql', 'mysqli' and 'pgsql' are
|
||||
* optional). It is recommended you use 'default' for mysql
|
||||
* and create specific overrides for pgsql when the formulae
|
||||
* differ.
|
||||
*
|
||||
* @ingroup views_sort_handlers
|
||||
*/
|
||||
class views_handler_sort_formula extends views_handler_sort {
|
||||
/**
|
||||
* Constructor to take the formula this sorts on.
|
||||
*/
|
||||
function construct() {
|
||||
$this->formula = $this->definition['formula'];
|
||||
if (is_array($this->formula) && !isset($this->formula['default'])) {
|
||||
$this->error = t('views_handler_sort_formula missing default: @formula', array('@formula' => var_export($this->formula, TRUE)));
|
||||
}
|
||||
parent::construct();
|
||||
}
|
||||
/**
|
||||
* Called to add the sort to a query.
|
||||
*/
|
||||
function query() {
|
||||
if (is_array($this->formula)) {
|
||||
global $db_type;
|
||||
if (isset($this->formula[$db_type])) {
|
||||
$formula = $this->formula[$db_type];
|
||||
}
|
||||
else {
|
||||
$formula = $this->formula['default'];
|
||||
}
|
||||
}
|
||||
else {
|
||||
$formula = $this->formula;
|
||||
}
|
||||
$this->ensure_my_table();
|
||||
// Add the field.
|
||||
$this->query->add_orderby(NULL, $formula, $this->options['order'], $this->table_alias . '_' . $this->field);
|
||||
}
|
||||
}
|
19
modules/views/handlers/views_handler_sort_menu_hierarchy.inc
Normal file
19
modules/views/handlers/views_handler_sort_menu_hierarchy.inc
Normal file
|
@ -0,0 +1,19 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Sort in menu hierarchy order.
|
||||
*
|
||||
* Given a field name of 'p' this produces an ORDER BY on p1, p2, ..., p9.
|
||||
* This is only really useful for the {menu_links} table.
|
||||
*
|
||||
* @ingroup views_sort_handlers
|
||||
*/
|
||||
class views_handler_sort_menu_hierarchy extends views_handler_sort {
|
||||
function query() {
|
||||
$this->ensure_my_table();
|
||||
$max_depth = isset($this->definition['max depth']) ? $this->definition['max depth'] : MENU_MAX_DEPTH;
|
||||
for ($i = 1; $i <= $max_depth; ++$i) {
|
||||
$this->query->add_orderby($this->table_alias, $this->field . $i, $this->options['order']);
|
||||
}
|
||||
}
|
||||
}
|
27
modules/views/handlers/views_handler_sort_random.inc
Normal file
27
modules/views/handlers/views_handler_sort_random.inc
Normal file
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Handle a random sort.
|
||||
*/
|
||||
class views_handler_sort_random extends views_handler_sort {
|
||||
function query() {
|
||||
global $db_type;
|
||||
switch ($db_type) {
|
||||
case 'mysql':
|
||||
case 'mysqli':
|
||||
$formula = 'RAND()';
|
||||
break;
|
||||
case 'pgsql':
|
||||
$formula = 'RANDOM()';
|
||||
break;
|
||||
}
|
||||
if (!empty($formula)) {
|
||||
$this->query->add_orderby(NULL, $formula, $this->options['order'], '_' . $this->field);
|
||||
}
|
||||
}
|
||||
|
||||
function options_form(&$form, &$form_state) {
|
||||
parent::options_form($form, $form_state);
|
||||
$form['order']['#access'] = FALSE;
|
||||
}
|
||||
}
|
Reference in a new issue