cmf.module in Content Management Filter 7
Same filename and directory in other branches
@brief Content management filter module file
This file contains all the common functions used by the module.
File
cmf.moduleView source
<?php
/**
* @file
* @brief Content management filter module file
*
* This file contains all the common functions used by the module.
*/
/**
* Adding a new filter:
*
* Add an entry to function cmf_filters. Read the docs at the top of that function.
* If special form processing is needed (not likely), add it to function cmf_filter_form.
* Add handling to cmf_filter_form_refine, if needed (not likely: submit/validate preferred).
* Make sure all the database columns are present in cmf_perform_query.
*
* @TODO: Is it now possible to provide a hook to other contribs?
*/
/**
* Implementation of hook_help().
*/
function cmf_help($path, $arg) {
switch ($path) {
case "admin/help#cmf":
return '<p>' . t('This module adds an easier way for administrators to filter the content on a Drupal site for administration purposes.') . '</p>' . '<p>' . t('It is an improvement over the content page in the administration area of Drupal. It can show on the same page nodes and comments and adds new filters like role and author.') . '</p>';
}
}
/**
* Implementation of hook_perm().
*/
function cmf_perm() {
return array(
'filter and manage site content',
'view user content list',
);
}
/**
* Implementation of hook_menu().
*/
function cmf_menu() {
$items = array();
$items['admin/content/filter'] = array(
'title' => 'Content Management Filter',
'description' => 'All-in-one advanced filter and management of your site content.',
'page callback' => 'cmf_admin_content_page',
'access arguments' => array(
'filter and manage site content',
),
);
$items['user/%user/cmf'] = array(
'title' => 'CMF',
'description' => 'User-specific content management filter',
'page callback' => 'cmf_admin_content_page',
'page arguments' => array(
1,
),
'access arguments' => array(
'view user content list',
),
'type' => MENU_LOCAL_TASK,
);
$items['cmf/userauto'] = array(
'title' => 'User autocomplete',
'page callback' => '_cmf_user_autocomplete',
'access callback' => 'user_access',
'access callback' => '_cmf_userspace_perms',
'access arguments' => array(
'filter and manage site content',
'view user content list',
),
'type' => MENU_CALLBACK,
);
return $items;
}
/**
* Check user permissions to see menu item under example.com/user/UID/cmf
*
* @param access strings
* @param access strings
* @return boolean
*/
function _cmf_userspace_perms($manage_access, $view_access) {
return user_access($manage_access) || user_access($view_access);
}
/**
* List node administration filters that can be applied.
*
* @param $user
* (object) if a user profile page then user object (defaults to false).
*
* @return array with filter properties.
* Any property starting with '#' goes directly into the filter form.
* '#options' is also used in function cmf_filter_form_submit.
* 'title' is the text that will show on the filter form.
* 'single_use' (bool) determines if the filter will be disabled if it is already in use.
* 'whole_value' "before" if the value is complete and shown before "is",
* "after" if the value is complete and shown after "is",
* "no" if it is a portion ("contains"), such as a substring.
* 'disable' is a list of other filters to remove if this one is selected.
* 'where' sets a simple WHERE clause for the query (with substitution).
* 'join' sets a simple JOIN clause for the query (with substitution).
* 'query_build' provides a funtion for more complex query clauses.
* If validation and/or submission handling is needed, use the #element_validate and #submit elements.
* Submit handlers must set the return value in $form_state['values'] array.
*
* NOTE: for the 'where' clause some node fields are translated to comment-equivalent
* field names if appropriate. See function cmf_perform_query for 'comment' and 'both.'
*/
function cmf_filters($user = FALSE) {
// Make the array static so it is built only once per page load.
static $filters;
if (isset($filters)) {
return $filters;
}
$filters = array();
// Regular filters.
$filters['status'] = array(
'title' => t('node status'),
'single_use' => FALSE,
'whole_value' => 'before',
'query_build' => '_cmf_status_query_build',
'#type' => 'select',
'#options' => array(
'status-1' => t('published'),
'status-0' => t('not published'),
'promote-1' => t('promoted'),
'promote-0' => t('not promoted'),
'sticky-1' => t('sticky'),
'sticky-0' => t('not sticky'),
),
);
$filters['type'] = array(
'title' => t('node type'),
'single_use' => TRUE,
'whole_value' => 'before',
'where' => "n.type = '%s'",
'#type' => 'select',
'#options' => node_type_get_names(),
);
//-- workflow filter
if (module_exists('workflow') && function_exists('workflow_load_all')) {
$filters['workflow_state'] = array(
'title' => t('workflow state'),
'single_use' => FALSE,
'whole_value' => 'before',
'query_build' => '_cmf_workflow_query_build',
'#type' => 'select',
'#options' => cmf_get_workflows(),
);
}
// The taxonomy filter.
if (module_exists('taxonomy')) {
$filters['category'] = array(
'title' => t('category'),
'single_use' => FALSE,
'whole_value' => 'before',
'query_build' => '_cmf_category_query_build',
'#type' => 'select',
'#options' => taxonomy_form_all(TRUE),
);
}
// Cmf filters.
$filters['title'] = array(
'title' => t('title/subject'),
'single_use' => FALSE,
'whole_value' => 'no',
'where' => "LOWER(n.title) LIKE LOWER('%%%s%%')",
'#type' => 'textfield',
'#element_validate' => array(
'_cmf_contains_validate',
),
);
$filters['body_contains'] = array(
'title' => t('body'),
'single_use' => FALSE,
'whole_value' => 'no',
'where' => "LOWER(r.body) LIKE LOWER('%%%s%%')",
'#type' => 'textfield',
'#element_validate' => array(
'_cmf_contains_validate',
),
);
$filters['created_after'] = array(
'title' => t('created after'),
'single_use' => TRUE,
'whole_value' => 'after',
'where' => "n.created >= %d",
'#type' => 'date',
'#element_validate' => array(
'date_validate',
'_cmf_date_validate',
),
'#submit' => array(
'cmf_date_handler',
),
'#default_value' => array(
'year' => date('Y'),
'month' => 1,
'day' => 1,
),
'#prefix' => '<div class="date-inline">',
'#suffix' => '</div>',
);
$filters['created_before'] = array(
'title' => t('created before'),
'single_use' => TRUE,
'whole_value' => 'after',
'where' => "n.created <= %d",
'#type' => 'date',
'#element_validate' => array(
'date_validate',
'_cmf_date_validate',
),
'#submit' => array(
'cmf_date_handler',
),
'#default_value' => array(
'year' => date('Y'),
'month' => 12,
'day' => 31,
),
'#prefix' => '<div class="date-inline">',
'#suffix' => '</div>',
);
if (module_exists('locale')) {
$lang_codes = array(
'' => t('Neutral'),
) + locale_language_list('name');
$filters['language'] = array(
'title' => t('language'),
'single_use' => TRUE,
'whole_value' => 'before',
'where' => "n.language ='%s'",
'#type' => 'select',
'#options' => $lang_codes,
);
}
// Don't show these on a user page.
if (!_cmf_valid_user($user)) {
$filters['user'] = array(
'title' => t('user list'),
'single_use' => TRUE,
'whole_value' => 'before',
'disable' => array(
'users',
'role',
'blocked',
),
'where' => "u.uid = %d",
'#type' => 'select',
'#options' => cmf_get_users('names'),
);
$filters['users'] = array(
'title' => t('user name'),
'single_use' => TRUE,
'whole_value' => 'before',
'disable' => array(
'user',
'role',
'blocked',
),
'where' => "u.name = '%s'",
'#type' => 'textfield',
'#submit' => array(
'cmf_users_handler',
),
'#autocomplete_path' => 'cmf/userauto',
);
$filters['role'] = array(
'title' => t('user role'),
'single_use' => TRUE,
'whole_value' => 'before',
'where' => "u.uid = ur.uid AND ur.rid = %d",
'join' => "INNER JOIN {users_roles} ur ON u.uid = ur.uid",
'#type' => 'select',
'#options' => cmf_get_roles('names'),
);
$filters['blocked'] = array(
'title' => t('user status'),
'single_use' => TRUE,
'whole_value' => 'before',
'where' => "u.status = %d AND u.uid != 0",
'#type' => 'select',
'#options' => array(
1 => t('active'),
0 => t('blocked'),
),
);
}
drupal_alter('cmf_filters', $filters);
return $filters;
}
/**
* Called when user goes to example.com/admin/content/filter
*
* @return the HTML generated from the $form data structure
*/
function cmf_admin_content_page($user = NULL) {
if (!isset($_SESSION['cmf_content_kind'])) {
$_SESSION['cmf_content_kind'] = 'node';
}
$output = drupal_get_form('cmf_filter_form', $user);
// Call the form first, to allow for the form_values array to be populated.
switch ($_SESSION['cmf_content_kind']) {
case 'node':
if (isset($_POST['operation']) && $_POST['operation'] == 'delete' && $_POST['nodes']) {
return drupal_get_form('node_multiple_delete_confirm', $_POST['nodes']);
}
else {
$output .= drupal_get_form('cmf_admin_nodes_form', $user);
}
break;
case 'comment':
if ($_POST['operation'] == 'delete' && $_POST['comments']) {
// The next line is because of http://drupal.org/node/521354.
module_load_include('inc', 'comment', 'comment.admin');
return drupal_get_form('comment_multiple_delete_confirm');
}
else {
$output .= drupal_get_form('cmf_admin_comments_form', $user);
}
break;
case 'both':
$output .= drupal_get_form('cmf_admin_both_form', $user);
}
return $output;
}
/**
* FILTERS
*/
/**
* Defines the form for content administration filters.
*
* @ingroup forms
*
* @param (optional) true if the filter to be built serves the user profile page
* @return array with forms properties
*/
function cmf_filter_form(&$form_state, $user = NULL) {
$session =& $_SESSION['cmf_overview_filter'];
$session = is_array($session) ? $session : array();
$filters = cmf_filters($user);
drupal_add_css(drupal_get_path('module', 'cmf') . '/cmf.css');
drupal_add_js(drupal_get_path('module', 'cmf') . '/cmf.jquery.js');
$form['#user_page_user'] = $user;
// General settings display (max rows & content kind).
$form['general'] = array(
'#type' => 'fieldset',
'#title' => t('General Settings'),
'#collapsible' => TRUE,
'#collapsed' => TRUE,
);
$form['general']['max-rows'] = array(
'#type' => 'textfield',
'#title' => t('Max rows'),
'#size' => 5,
'#default_value' => isset($_SESSION['cmf_max_rows']) ? $_SESSION['cmf_max_rows'] : 50,
'#prefix' => '<div class="container-inline">',
'#suffix' => '</div>',
);
$form['general']['show_nid'] = array(
'#type' => 'radios',
'#title' => t('Show node ID'),
'#options' => array(
0 => t('No'),
1 => t('Yes'),
),
'#default_value' => isset($_SESSION['cmf_show_nid']) ? $_SESSION['cmf_show_nid'] : 0,
'#prefix' => '<div class="container-inline"><div class="cmf-radios">',
'#suffix' => '</div></div><div class="clear-block"></div>',
);
$form['general']['kind'] = array(
'#type' => 'select',
'#title' => t('Content'),
'#options' => array(
'node' => t('node'),
'comment' => t('comment'),
'both' => t('both'),
),
'#default_value' => isset($_SESSION['cmf_content_kind']) ? $_SESSION['cmf_content_kind'] : 'node',
'#prefix' => '<div class="container-inline">',
);
$form['general']['buttons']['apply'] = array(
'#type' => 'submit',
'#value' => t('Apply'),
'#submit' => array(
'cmf_filter_form_apply',
),
'#suffix' => '</div>',
);
$i = 0;
$form['filters'] = array(
'#type' => 'fieldset',
'#title' => t('Show only items where'),
'#theme' => 'node_filters',
);
foreach ($session as $filter) {
list($type, $value) = $filter;
// Special handling by type of filter.
switch ($type) {
case 'category':
// Load term name from DB rather than search and parse options array.
$value = taxonomy_get_term($value);
$value = $value->name;
break;
case 'body_contains':
case 'title':
// Add quotes.
$value = "'" . $value . "'";
break;
case 'created_after':
case 'created_before':
// Format as human date.
$fmt = variable_get('date_format_short', variable_get('date_format_short_custom', 'Y M j'));
$fmt = trim(str_replace(array(
'H',
'i',
':',
), '', $fmt));
$value = format_date($value, 'custom', $fmt, 0);
break;
default:
if (isset($filters[$type]['#options'])) {
$value = $filters[$type]['#options'][$value];
}
}
// Add applicable filter verbiage. Note '@' and '%' do check_plain.
$trans_strings = array(
'%filter_name' => $filters[$type]['title'],
'%filter_value' => $value,
);
if ($i++) {
$and = '<em>' . t('and') . '</em> ';
}
else {
$and = NULL;
}
switch ($filters[$type]['whole_value']) {
case 'after':
$form['filters']['current'][] = array(
'#value' => $and . t('is %filter_name %filter_value', $trans_strings),
);
break;
case 'before':
$form['filters']['current'][] = array(
'#value' => $and . t('%filter_name is %filter_value', $trans_strings),
);
break;
case 'no':
$form['filters']['current'][] = array(
'#value' => $and . t('%filter_name contains %filter_value', $trans_strings),
);
break;
}
// Remove mutually exclusive filters.
if (isset($filters[$type]['disable'])) {
foreach ($filters[$type]['disable'] as $exclude) {
unset($filters[$exclude]);
}
}
// Remove the single use option if it is already being filtered on.
if ($type == 'status') {
// drupal_set_message('okay, what do I get rid of? '. print_r($filter,true));
// dsm(print_r($filters['status'],true));
// Strip current value, then unset both values.
$status = drupal_substr($filter[1], 0, -1);
unset($filters['status']['#options'][$status . '0'], $filters['status']['#options'][$status . '1']);
}
if ($filters[$type]['single_use']) {
unset($filters[$type]);
}
}
// Prepare form fields for filters.
foreach ($filters as $key => $filter) {
$names[$key] = $filter['title'];
// Normal form field handling.
$form['filters']['status'][$key] = array();
foreach ($filter as $element => $value) {
// If the filter element name begins with '#' then it is for the form.
if (drupal_substr($element, 0, 1) == '#') {
$form['filters']['status'][$key][$element] = $value;
}
}
// Special form field handling.
// Uncomment the 'switch', add handling case adding to the current form field array.
// The stuff here is for an example and can be removed.
/* switch ($key) {
case 'created_before':
$form['filters']['status'][$key] += array(
'#default_value' => array('year' => date('Y'), 'month' => 12, 'day' =>31),
);
break;
case 'created_after':
$form['filters']['status'][$key] += array(
'#default_value' => array('year' => date('Y'), 'month' => 1, 'day' =>1),
);
break;
} /* */
}
// Building radio buttons.
$keyz = array_keys($names);
$form['filters']['filter'] = array(
'#type' => 'radios',
'#options' => $names,
'#default_value' => $keyz[0],
'#attributes' => array(
'class' => 'multiselect',
),
);
// Building buttons depending on the filter state.
$form['filters']['buttons']['submit'] = array(
'#type' => 'submit',
'#value' => count($session) ? t('Refine') : t('Filter'),
'#submit' => array(
'cmf_filter_form_refine',
),
);
if (count($session)) {
$form['filters']['buttons']['undo'] = array(
'#type' => 'submit',
'#submit' => array(
'cmf_filter_form_undo',
),
'#value' => t('Undo'),
);
$form['filters']['buttons']['reset'] = array(
'#type' => 'submit',
'#submit' => array(
'cmf_filter_form_reset',
),
'#value' => t('Reset'),
);
}
return $form;
}
/**
* Handle post-validation form submission.
*
* @ingroup forms
*
* @param the ID of the passed form
* @param array with the form properties values
*/
function cmf_filter_form_refine($form, &$form_state) {
$filters = cmf_filters();
if (isset($form_state['values']['filter'])) {
$filter = $form_state['values']['filter'];
// Convert AJAX search value to select box value.
// If a filter has specified a submit function, call it. (Only allow one value.)
if (isset($filters[$filter]['#submit'])) {
$form_state['values'][$filter] = call_user_func($filters[$filter]['#submit'][0], $form, $form_state);
}
// Repeating this allows submit handlers (e.g. users) to alter the filter name.
$filter = $form_state['values']['filter'];
// Flatten the options array to accommodate hierarchical/nested options.
// If there are no options, fake it.
if (isset($filters[$filter]['#options'])) {
$flat_options = form_options_flatten($filters[$filter]['#options']);
}
else {
$flat_options = array(
$form_state['values'][$filter] => 1,
);
}
// If the option is selected or there are no options, set the session value.
if (isset($flat_options[$form_state['values'][$filter]])) {
$_SESSION['cmf_overview_filter'][] = array(
$filter,
$form_state['values'][$filter],
);
}
}
}
/**
* Submit handler for 'Undo' button.
*/
function cmf_filter_form_undo($form, &$form_state) {
array_pop($_SESSION['cmf_overview_filter']);
}
/**
* Submit handler for 'Reset' button.
*/
function cmf_filter_form_reset($form, &$form_state) {
$_SESSION['cmf_overview_filter'] = array();
}
/**
* Submit handler for 'Apply' button.
*/
function cmf_filter_form_apply($form, &$form_state) {
$_SESSION['cmf_max_rows'] = $form_state['values']['max-rows'];
$_SESSION['cmf_show_nid'] = $form_state['values']['show_nid'];
$_SESSION['cmf_content_kind'] = $form_state['values']['kind'];
$user = $form['#user_page_user'];
if (_cmf_valid_user($user)) {
$form_state['redirect'] = 'user/' . $user->uid . '/cmf';
}
else {
$form_state['redirect'] = 'admin/content/filter';
}
}
function _cmf_valid_user($user) {
if (!empty($user->uid)) {
return TRUE;
}
else {
return FALSE;
}
}
/**
* Validation handler for filter doing "contains".
*/
function _cmf_contains_validate($form) {
// Make sure this was triggered by the selected filter.
if ($form['#name'] == $form['#post']['filter']) {
// Strip blanks to see if the field is empty.
$value = trim($form['#value']);
if (empty($value)) {
form_error($form, t('%name text value may not be empty.', array(
'%name' => $form['#name'],
)));
}
}
}
/**
* Validation handler for filter doing "dates".
*/
function _cmf_date_validate($form) {
// Make sure this was triggered by the selected filter.
if ($form['#name'] != $form['#post']['filter']) {
return;
}
// Determine correct time values depending on the filter name.
if (strpos($form['#name'], 'before') === FALSE) {
$entered_date = mktime(0, 0, 0, (int) $form['#value']['month'], (int) $form['#value']['day'], (int) $form['#value']['year'], 1);
}
else {
$entered_date = mktime(11, 59, 59, (int) $form['#value']['month'], (int) $form['#value']['day'], (int) $form['#value']['year'], 1);
}
// drupal_set_message('_cmf_date_validate, filter='.$form['#post']['filter'].', name='.$form['#name'].' '.print_r($form['#value'], true).', calc='.format_date($entered_date));
// drupal_set_message('current filters='.print_r($_SESSION['cmf_overview_filter'], true));
if (empty($entered_date)) {
form_error($form, t('%name date value may not be empty.', array(
'%name' => $form['#name'],
)));
}
}
/**
* Submit handler for 'users' filter.
* Ignore the Coder flag - it is a false positive.
*/
function cmf_users_handler($form, &$form_state) {
$name = $form_state['values']['users'];
// Get uid to put in 'user' filter value.
$form_state['values']['user'] = db_result(db_query('SELECT uid FROM {users} WHERE name = "%s"', $name));
// Switch filter type to user.
$form_state['values']['filter'] = 'user';
return $name;
}
/**
* Submit handler for date filters.
* Ignore the Coder flag - it is a false positive.
*/
function cmf_date_handler($form, &$form_state) {
$filter = $form_state['values']['filter'];
return gmmktime(0, 0, 0, $form_state['values'][$filter]['month'], $form_state['values'][$filter]['day'], $form_state['values'][$filter]['year']);
}
/**
* Theme cmf administration filter form.
*
* @themable
*/
function theme_cmf_filter_form($form) {
return '<div id="cmf_header">' . drupal_render($form['general']) . '</div>' . '<div id="node-admin-filter">' . drupal_render($form['filters']) . '</div>' . drupal_render($form);
}
/**
* QUERIES
*/
/**
* Build the variable parts of the query to be performed regarding the filter status.
*
* @return associative array with WHERE JOIN query parts and respective arguments
*/
function cmf_build_filter_query() {
$filters = cmf_filters();
// Build query
$where = $args = array();
$join = '';
foreach ($_SESSION['cmf_overview_filter'] as $index => $filter) {
list($key, $value) = $filter;
// Does the filter have query_build function?
if (isset($filters[$key]['query_build'])) {
$result = call_user_func($filters[$key]['query_build'], $key, $value, $index);
if (isset($result['where'])) {
$where[] = $result['where'];
}
if (isset($result['join'])) {
$join .= $result['join'] . ' ';
}
if (isset($result['value'])) {
$value = $result['value'];
}
}
else {
// Does the filter have where and/or joins specified?
if (isset($filters[$key]['where'])) {
$where[] = $filters[$key]['where'];
}
if (isset($filters[$key]['join'])) {
$join .= $filters[$key]['join'] . ' ';
}
}
$args[] = $value;
}
$where = count($where) ? 'WHERE ' . implode(' AND ', $where) : '';
return array(
'where' => $where,
'join' => $join,
'args' => $args,
);
}
/**
* Query_build function for category field.
*/
function _cmf_category_query_build($key, $value, $index) {
$table = "tn{$index}";
return array(
'where' => "{$table}.tid = %d",
'join' => "INNER JOIN {term_node} {$table} ON n.nid = {$table}.nid ",
'value' => $value,
);
}
/**
* Query_build function for status field.
*/
function _cmf_status_query_build($key, $value, $index) {
// Note: no exploitable hole as $key/$value have already been checked when submitted.
list($key, $value) = explode('-', $value, 2);
if ($key == 'sticky') {
// This allows sticky-encoded weighting (like Weight module) to also work.
return array(
'where' => 'n.' . $key . ' ' . ($value == 1 ? '>' : '<') . ' %d',
'value' => 1 - $value,
);
}
else {
return array(
'where' => 'n.' . $key . ' = %d',
'value' => $value,
);
}
}
/**
* Build the header of the result table.
*
* @param $user_page_user
* if we are on a user page, the user that page belongs to, not the current user
*
* @return array respecting tablesort_sql()
*/
function cmf_build_header($user_page_user = NULL) {
$header = array();
if (user_access('filter and manage site content')) {
$header[] = theme('table_select_header_cell');
}
if ($_SESSION['cmf_show_nid']) {
$header[] = array(
'data' => t('ID'),
'field' => 'nid',
);
}
switch ($_SESSION['cmf_content_kind']) {
case 'node':
$header[] = array(
'data' => t('Title'),
'field' => 'title',
);
$header[] = array(
'data' => t('Kind'),
);
$header[] = array(
'data' => t('Node Type'),
'field' => 'type',
);
if (!_cmf_valid_user($user_page_user)) {
$header[] = array(
'data' => t('Author'),
'field' => 'username',
);
}
$header[] = array(
'data' => t('Status'),
'field' => 'status',
);
$header[] = array(
'data' => t('Time'),
'field' => 'created',
'sort' => 'desc',
);
if (module_exists('locale')) {
$header[] = array(
'data' => t('Language'),
'field' => 'language',
);
}
break;
case 'comment':
$header[] = array(
'data' => t('Subject'),
'field' => 'subject',
);
$header[] = array(
'data' => t('Kind'),
);
$header[] = array(
'data' => t('Node Type'),
'field' => 'type',
);
if (!_cmf_valid_user($user_page_user)) {
$header[] = array(
'data' => t('Author'),
'field' => 'username',
);
}
$header[] = array(
'data' => t('Status'),
'field' => 'status',
);
$header[] = array(
'data' => t('Time'),
'field' => 'created',
'sort' => 'desc',
);
break;
case 'both':
$header[] = array(
'data' => t('Title') . '/' . t('Subject'),
'field' => 'title',
);
$header[] = array(
'data' => t('Kind'),
);
$header[] = array(
'data' => t('Node Type'),
'field' => 'type',
);
if (!_cmf_valid_user($user_page_user)) {
$header[] = array(
'data' => t('Author'),
'field' => 'username',
);
}
$header[] = array(
'data' => t('Node Status'),
'field' => 'status',
);
$header[] = array(
'data' => t('Time'),
'field' => 'created',
'sort' => 'desc',
);
if (module_exists('locale')) {
$header[] = array(
'data' => t('Language'),
'field' => 'language',
);
}
break;
}
if (user_access('filter and manage site content')) {
$header[] = array(
'data' => t('Operations'),
);
}
return $header;
}
/**
* Perform adjusted query.
*
* @param $user_page_user
* if we are on a user page, the user that page belongs to, not the current user
*
*
* @param array respecting tablesort_sql()
* @return result of permormed query
*/
function cmf_perform_query($header, $kind = NULL, $user_page_user = NULL) {
$filter = cmf_build_filter_query();
if (is_null($kind)) {
$kind = $_SESSION['cmf_content_kind'];
}
$where = ' ' . $filter['where'];
if (_cmf_valid_user($user_page_user)) {
$where .= ' AND u.uid = ' . $user_page_user->uid;
}
$cwhere = str_replace(array(
'n.title',
'n.uid',
'r.body',
), array(
'c.subject',
'c.uid',
'c.comment',
), $where);
switch ($kind) {
case 'node':
return pager_query('SELECT n.nid, n.title, n.type, n.status, n.created, ' . 'n.changed, n.promote, n.sticky, n.moderate, n.language, ' . 'u.name AS username, u.uid, r.body ' . 'FROM {node} n ' . 'JOIN {node_revisions} r ON r.vid = n.vid ' . 'INNER JOIN {users} u ON n.uid = u.uid ' . $filter['join'] . $where . tablesort_sql($header), isset($_SESSION['cmf_max_rows']) ? $_SESSION['cmf_max_rows'] : 50, 0, NULL, $filter['args']);
break;
case 'comment':
return pager_query('SELECT c.cid, c.subject, c.nid, c.comment, c.timestamp AS created, ' . 'c.status, c.name, c.homepage, u.name AS username, u.uid, n.type, c.comment AS body ' . 'FROM {comments} c ' . 'INNER JOIN {node} n ON c.nid = n.nid ' . 'INNER JOIN {users} u ON u.uid = c.uid ' . $filter['join'] . $cwhere . tablesort_sql($header), isset($_SESSION['cmf_max_rows']) ? $_SESSION['cmf_max_rows'] : 50, 0, NULL, $filter['args']);
break;
case 'both':
$args = array_merge($filter['args'], $filter['args']);
$count_query = 'SELECT (' . 'SELECT COUNT(*) FROM {node} n ' . 'JOIN {node_revisions} r ON r.vid = n.vid ' . 'INNER JOIN {users} u ON n.uid = u.uid ' . $filter['join'] . $where . ') + (' . 'SELECT COUNT(*) FROM {comments} c INNER JOIN {node} n ON c.nid = n.nid ' . 'INNER JOIN {users} u ON u.uid = c.uid ' . $filter['join'] . $cwhere . ') AS count';
return pager_query('SELECT 0 AS cid, n.nid, n.title, NULL AS comment, n.type, n.status, n.created, ' . 'n.changed, n.promote, n.sticky, n.moderate, n.language, ' . 'u.name AS username, u.uid, r.body ' . 'FROM {node} n ' . 'JOIN {node_revisions} r ON r.vid = n.vid ' . 'INNER JOIN {users} u ON n.uid = u.uid ' . $filter['join'] . $where . ' UNION SELECT c.cid, c.nid, c.subject AS title, c.comment, n.type, c.status, c.timestamp AS created, ' . '0 AS changed, 0 AS promote, 0 AS sticky, 0 AS moderate, "" AS language, ' . 'u.name AS username, u.uid, c.comment AS body ' . ' FROM {comments} c INNER JOIN {node} n ON c.nid = n.nid INNER JOIN {users} u ON u.uid = c.uid ' . $filter['join'] . $cwhere . tablesort_sql($header), isset($_SESSION['cmf_max_rows']) ? $_SESSION['cmf_max_rows'] : 50, 0, $count_query, $args);
break;
}
}
/**
* RESULTS
*/
module_load_include('inc', 'cmf', '/node');
module_load_include('inc', 'cmf', '/comment');
module_load_include('inc', 'cmf', '/both');
/*
* AUX
*/
/**
* Builds a list of available users.
*
* @param the format in which to return the list
* @return array of all available users
*/
function cmf_get_users($op) {
switch ($op) {
case 'names':
$result = db_query('SELECT uid, name FROM {users} WHERE uid <> 0 ORDER BY name');
break;
}
$users = array();
$users[0] = variable_get('anonymous', t('anonymous'));
while ($account = db_fetch_object($result)) {
$users[$account->uid] = $account->name;
}
return $users;
}
/**
* Menu callback; Retrieve a JSON object containing autocomplete suggestions for existing users.
*/
function _cmf_user_autocomplete($string = '') {
$matches = array();
if ($string) {
$result = db_query("SELECT name FROM {users} WHERE LOWER(name) LIKE LOWER('%s%%')", $string);
while ($account = db_fetch_object($result)) {
$matches[$account->name] = check_plain($account->name);
}
}
drupal_json($matches);
}
/**
* Builds a list of available roles
*
* @param the format in which to return the list
* @return array of all available roles
*/
function cmf_get_roles($op) {
switch ($op) {
case 'names':
$result = db_query('SELECT rid, name FROM {role} ORDER BY name');
break;
}
$roles = array();
while ($role = db_fetch_object($result)) {
$roles[$role->rid] = $role->name;
}
return $roles;
}
/**
* Get the html code of an image
*
* @param the pretended image
* @return html tag img
*/
function _cmf_get_img($action, $title) {
$path = base_path() . drupal_get_path('module', 'cmf') . '/images/' . $action . '.png';
if ($title == NULL) {
$html = '<img src="' . $path . '" alt="untitled image" />';
}
else {
$html = '<img src="' . $path . '" title="' . $title . '" alt="' . $title . '" />';
}
return $html;
}
/**
* Theme (node) type cell on table result.
*
* @ingroup themable
*
* @param 0 or node type key
* @return formated (node) type
*/
function theme_cmf_type($type) {
return db_result(db_query('SELECT name FROM {node_type} WHERE type = "%s"', $type));
}
/**
* Implementation of hook_theme().
*
* @ingroup themable
*/
function cmf_theme() {
return array(
'cmf_filter_form' => array(
'arguments' => array(
'form' => NULL,
),
),
'cmf_user' => array(
'arguments' => array(
'uid' => NULL,
),
),
'cmf_type' => array(
'arguments' => array(
'type' => NULL,
),
),
'cmf_admin_nodes_form' => array(
'file' => 'node.inc',
'arguments' => array(
'form' => NULL,
),
),
'cmf_admin_comments_form' => array(
'file' => 'comment.inc',
'arguments' => array(
'form' => NULL,
),
),
'cmf_admin_both_form' => array(
'file' => 'both.inc',
'arguments' => array(
'form' => NULL,
),
),
);
}
/**
* Theme user cell on table result.
*
* @ingroup themable
*
* @param user ID
* @return clickable username with status
*/
function theme_cmf_user($uid) {
if ($uid == 0) {
return variable_get('anonymous', t('anonymous'));
}
$result = db_query('SELECT name, status FROM {users} WHERE uid = %d', $uid);
$user = db_fetch_array($result);
$url_alias = _cmf_get_user_path($uid);
$display = $user['status'] ? $user['name'] : _cmf_get_img('blocked', t('blocked')) . ' ' . $user['name'];
if (user_access('access user profiles')) {
$url = $url_alias ? $url_alias : 'user/' . $uid;
$output = l($display, $url, array(
'html' => TRUE,
));
}
else {
$output = $display;
}
return $output;
}
/**
* Get the alias path to a user profile
*
* @param user ID
* @return the relative URL of the user profile
*/
function _cmf_get_user_path($uid) {
return db_result(db_query("\n SELECT dst\n FROM {url_alias}\n WHERE src = '%s';", 'user/' . $uid));
}
/**
* Get the term for a forum node
*
* @param node ID
* @return the name and forum description
*/
function _cmf_get_forum($nid) {
$path = array();
$node = node_load($nid);
$parents = taxonomy_get_parents_all($node->tid);
foreach ($parents as $parent) {
$path[] = $parent->name;
}
return implode(' > ', array_reverse($path));
}
function cmf_get_workflows() {
if (!module_exists('workflow')) {
return;
}
if (!function_exists('workflow_load_all')) {
return;
}
$workflows = workflow_load_all();
$states = array();
if (is_array($workflows)) {
foreach ($workflows as $workflow) {
if (is_array($workflow->states)) {
foreach ($workflow->states as $state) {
$states[$state->name] = $workflow->label . " : " . $state->label;
}
}
}
}
return $states;
}
/**
* Query_build function for workflow
*/
function _cmf_workflow_query_build($key, $value, $index) {
if (!module_exists('workflow')) {
return;
}
if (!function_exists('workflow_load_all')) {
return;
}
$table = "workflow_node";
return array(
'where' => "{$table}.state_name = '%s'",
'join' => "INNER JOIN {$table} {$table} ON n.nid = {$table}.nid ",
'value' => $value,
);
}
/**
* Implementation of hook_form_alter().
*/
function cmf_form_alter(&$form, $form_state, $form_id) {
switch ($form_id) {
// When CMF is only showing nodes or only showing comments, the deletion is handled by
// re-using the multiple delete functions provided by node module and comment module.
case 'node_multiple_delete_confirm':
case 'comment_multiple_delete_confirm':
// The target page after deleting is set in the corresponding submit function so we need
// to add another submit function which will be executed after that one, to change the
// redirect value to our page.
$form['#submit'][] = '_cmf_redirect_to_cmf';
// The cancel link will have been defined to return to admin/content/node (or admin/content/comment)
// so we need to change it here to return to admin/content/filter instead.
$form['actions']['cancel']['#value'] = l(t('Cancel'), 'admin/content/filter');
break;
default:
}
}
/**
* Additional node deletion 'submit' function.
*/
function _cmf_redirect_to_cmf($form, &$form_state) {
// Set the final destination after deleting node(s) or comments(s).
// Could have used a GOTO here, but safer to set redirect.
$form_state['redirect'] = 'admin/content/filter';
}
Functions
Name![]() |
Description |
---|---|
cmf_admin_content_page | Called when user goes to example.com/admin/content/filter |
cmf_build_filter_query | Build the variable parts of the query to be performed regarding the filter status. |
cmf_build_header | Build the header of the result table. |
cmf_date_handler | Submit handler for date filters. Ignore the Coder flag - it is a false positive. |
cmf_filters | List node administration filters that can be applied. |
cmf_filter_form | Defines the form for content administration filters. |
cmf_filter_form_apply | Submit handler for 'Apply' button. |
cmf_filter_form_refine | Handle post-validation form submission. |
cmf_filter_form_reset | Submit handler for 'Reset' button. |
cmf_filter_form_undo | Submit handler for 'Undo' button. |
cmf_form_alter | Implementation of hook_form_alter(). |
cmf_get_roles | Builds a list of available roles |
cmf_get_users | Builds a list of available users. |
cmf_get_workflows | |
cmf_help | Implementation of hook_help(). |
cmf_menu | Implementation of hook_menu(). |
cmf_perform_query | Perform adjusted query. |
cmf_perm | Implementation of hook_perm(). |
cmf_theme | Implementation of hook_theme(). |
cmf_users_handler | Submit handler for 'users' filter. Ignore the Coder flag - it is a false positive. |
theme_cmf_filter_form | Theme cmf administration filter form. |
theme_cmf_type | Theme (node) type cell on table result. |
theme_cmf_user | Theme user cell on table result. |
_cmf_category_query_build | Query_build function for category field. |
_cmf_contains_validate | Validation handler for filter doing "contains". |
_cmf_date_validate | Validation handler for filter doing "dates". |
_cmf_get_forum | Get the term for a forum node |
_cmf_get_img | Get the html code of an image |
_cmf_get_user_path | Get the alias path to a user profile |
_cmf_redirect_to_cmf | Additional node deletion 'submit' function. |
_cmf_status_query_build | Query_build function for status field. |
_cmf_userspace_perms | Check user permissions to see menu item under example.com/user/UID/cmf |
_cmf_user_autocomplete | Menu callback; Retrieve a JSON object containing autocomplete suggestions for existing users. |
_cmf_valid_user | |
_cmf_workflow_query_build | Query_build function for workflow |