poll.module
<?php
function poll_help($path, $arg) {
switch ($path) {
case 'admin/help#poll':
$output = '';
$output .= '<h3>' . t('About') . '</h3>';
$output .= '<p>' . t('The Poll module can be used to create simple surveys or questionnaires which display the cumulative results. A poll is a good way to receive feedback from site users and community members. For more information, see the online handbook entry for the <a href="@poll">Poll module</a>.', array('@poll' => 'http://drupal.org/handbook/modules/poll/')) . '</p>';
$output .= '<h3>' . t('Uses') . '</h3>';
$output .= '<dl>';
$output .= '<dt>' . t('Creating a poll') . '</dt>';
$output .= '<dd>' . t('Users can create a poll by clicking on Poll on the <a href="@add-content">Add content</a> page, and entering the question being posed, as well as the potential choices (and beginning vote counts for each choice). The status (closed or active) and duration (length of time the poll remains active for new votes) can also be specified.', array('@add-content' => url('node/add'))) . '</dd>';
$output .= '<dt>' . t('Viewing polls') . '</dt>';
$output .= '<dd>' . t('You can visit the <a href="@poll">Polls</a> page to view all current polls, or alternately enable the <em>Most recent poll</em> block on the <a href="@blocks">Blocks administration page</a>. To vote in, or view the results of a specific poll, you can click on the poll itself.', array('@poll' => url('poll'), '@blocks' => url('admin/structure/block'))) . '</dd>';
$output .= '</dl>';
return $output;
}
}
function poll_init() {
drupal_add_css(drupal_get_path('module', 'poll') . '/poll.css');
}
function poll_theme() {
return array(
'poll_vote' => array(
'template' => 'poll-vote',
'render element' => 'form',
),
'poll_choices' => array(
'render element' => 'form',
),
'poll_results' => array(
'template' => 'poll-results',
'variables' => array('raw_title' => NULL, 'results' => NULL, 'votes' => NULL, 'raw_links' => NULL, 'block' => NULL, 'nid' => NULL, 'vote' => NULL),
),
'poll_bar' => array(
'template' => 'poll-bar',
'variables' => array('title' => NULL, 'votes' => NULL, 'total_votes' => NULL, 'vote' => NULL, 'block' => NULL),
),
);
}
function poll_permission() {
$perms = array(
'vote on polls' => array(
'title' => t('Vote on polls'),
),
'cancel own vote' => array(
'title' => t('Cancel and change own votes'),
),
'inspect all votes' => array(
'title' => t('View voting results'),
),
);
return $perms;
}
function poll_menu() {
$items['poll'] = array(
'title' => 'Polls',
'page callback' => 'poll_page',
'access arguments' => array('access content'),
'type' => MENU_SUGGESTED_ITEM,
'file' => 'poll.pages.inc',
);
$items['node/%node/votes'] = array(
'title' => 'Votes',
'page callback' => 'poll_votes',
'page arguments' => array(1),
'access callback' => '_poll_menu_access',
'access arguments' => array(1, 'inspect all votes', FALSE),
'weight' => 3,
'type' => MENU_LOCAL_TASK,
'file' => 'poll.pages.inc',
);
$items['node/%node/results'] = array(
'title' => 'Results',
'page callback' => 'poll_results',
'page arguments' => array(1),
'access callback' => '_poll_menu_access',
'access arguments' => array(1, 'access content', TRUE),
'weight' => 3,
'type' => MENU_LOCAL_TASK,
'file' => 'poll.pages.inc',
);
return $items;
}
function _poll_menu_access($node, $perm, $inspect_allowvotes) {
return user_access($perm) && ($node->type == 'poll') && ($node->allowvotes || !$inspect_allowvotes);
}
function poll_block_info() {
if (user_access('access content')) {
$blocks['recent']['info'] = t('Most recent poll');
return $blocks;
}
}
function poll_block_view($delta = '') {
if (user_access('access content')) {
$select = db_select('node', 'n');
$select->join('poll', 'p', 'p.nid = n.nid');
$select->fields('n', array('nid'))
->condition('n.status', 1)
->condition('p.active', 1)
->orderBy('n.created', 'DESC')
->range(0, 1)
->addTag('node_access');
$record = $select->execute()->fetchObject();
if ($record) {
$poll = node_load($record->nid);
if ($poll->nid) {
$poll = poll_block_latest_poll_view($poll);
$block['subject'] = t('Poll');
$block['content'] = $poll->content;
return $block;
}
}
}
}
function poll_cron() {
$nids = db_query('SELECT p.nid FROM {poll} p INNER JOIN {node} n ON p.nid = n.nid WHERE (n.created + p.runtime) < :request_time AND p.active = :active AND p.runtime <> :runtime', array(':request_time' => REQUEST_TIME, ':active' => 1, ':runtime' => 0))->fetchCol();
if (!empty($nids)) {
db_update('poll')
->fields(array('active' => 0))
->condition('nid', $nids, 'IN')
->execute();
}
}
function poll_node_info() {
return array(
'poll' => array(
'name' => t('Poll'),
'base' => 'poll',
'description' => t('A <em>poll</em> is a question with a set of possible responses. A <em>poll</em>, once created, automatically provides a simple running count of the number of votes received for each response.'),
'title_label' => t('Question'),
'has_body' => FALSE,
)
);
}
function poll_field_extra_fields($bundle) {
$extra = array();
if ($bundle == 'poll') {
$extra['choice_wrapper'] = array(
'label' => t('Poll choices'),
'description' => t('Poll module choices.'),
'weight' => -4,
);
$extra['settings'] = array(
'label' => t('Poll settings'),
'description' => t('Poll module settings.'),
'weight' => -3,
);
}
return $extra;
}
function poll_form($node, &$form_state) {
global $user;
$admin = user_access('administer nodes') || user_access('edit any poll content') || (user_access('edit own poll content') && $user->uid == $node->uid);
$type = node_type_get_type($node);
$form_state['cache'] = TRUE;
if (isset($form_state['choice_count'])) {
$choice_count = $form_state['choice_count'];
}
else {
$choice_count = max(2, empty($node->choice) ? 2 : count($node->choice));
}
$form['choice_wrapper'] = array(
'#tree' => FALSE,
'#weight' => -4,
'#prefix' => '<div class="clearfix" id="poll-choice-wrapper">',
'#suffix' => '</div>',
);
$form['choice_wrapper']['choice'] = array(
'#prefix' => '<div id="poll-choices">',
'#suffix' => '</div>',
'#theme' => 'poll_choices',
);
$delta = 0;
$weight = 0;
if (isset($node->choice)) {
$delta = count($node->choice);
$weight = -$delta;
foreach ($node->choice as $chid => $choice) {
$key = 'chid:' . $chid;
$form['choice_wrapper']['choice'][$key] = _poll_choice_form($key, $choice['chid'], $choice['chtext'], $choice['chvotes'], $choice['weight'], $choice_count);
$weight = ($choice['weight'] > $weight) ? $choice['weight'] : $weight;
}
}
$existing_delta = $delta;
for ($delta; $delta < $choice_count; $delta++) {
$key = 'new:' . ($delta - $existing_delta);
$form['choice_wrapper']['choice'][$key] = _poll_choice_form($key, NULL, '', 0, $weight, $choice_count);
}
$form['choice_wrapper']['poll_more'] = array(
'#type' => 'submit',
'#value' => t('More choices'),
'#description' => t("If the amount of boxes above isn't enough, click here to add more choices."),
'#weight' => 1,
'#submit' => array('poll_more_choices_submit'), '#ajax' => array(
'callback' => 'poll_choice_js',
'wrapper' => 'poll-choices',
'method' => 'replace',
'effect' => 'fade',
),
);
$duration = array(
86400, 2 * 86400, 3 * 86400, 4 * 86400, 5 * 86400, 6 * 86400,
604800, 2 * 604800, 3 * 604800,
2592000, 2 * 2592000, 3 * 2592000, 6 * 2592000, 9 * 2592000,
31536000,
);
$duration = array(0 => t('Unlimited')) + drupal_map_assoc($duration, 'format_interval');
$active = array(0 => t('Closed'), 1 => t('Active'));
$form['settings'] = array(
'#type' => 'fieldset',
'#collapsible' => TRUE,
'#title' => t('Poll settings'),
'#weight' => -3,
'#access' => $admin,
);
$form['settings']['active'] = array(
'#type' => 'radios',
'#title' => t('Poll status'),
'#default_value' => isset($node->active) ? $node->active : 1,
'#options' => $active,
'#description' => t('When a poll is closed, visitors can no longer vote for it.'),
'#access' => $admin,
);
$form['settings']['runtime'] = array(
'#type' => 'select',
'#title' => t('Poll duration'),
'#default_value' => isset($node->runtime) ? $node->runtime : 0,
'#options' => $duration,
'#description' => t('After this period, the poll will be closed automatically.'),
);
return $form;
}
function poll_more_choices_submit($form, &$form_state) {
include_once DRUPAL_ROOT . '/' . drupal_get_path('module', 'node') . '/node.pages.inc';
node_form_submit_build_node($form, $form_state);
if ($form_state['values']['poll_more']) {
$n = $_GET['q'] == 'system/ajax' ? 1 : 5;
$form_state['choice_count'] = count($form_state['values']['choice']) + $n;
}
}
function _poll_choice_form($key, $chid = NULL, $value = '', $votes = 0, $weight = 0, $size = 10) {
$admin = user_access('administer nodes');
$form = array(
'#tree' => TRUE,
);
$form['chid'] = array(
'#type' => 'value',
'#value' => $chid,
'#parents' => array('choice', $key, 'chid'),
);
$form['chtext'] = array(
'#type' => 'textfield',
'#default_value' => $value,
'#parents' => array('choice', $key, 'chtext'),
);
$form['chvotes'] = array(
'#type' => 'textfield',
'#default_value' => $votes,
'#size' => 5,
'#maxlength' => 7,
'#parents' => array('choice', $key, 'chvotes'),
'#access' => user_access('administer nodes'),
);
$form['weight'] = array(
'#type' => 'weight',
'#default_value' => $weight,
'#delta' => $size,
'#parents' => array('choice', $key, 'weight'),
);
return $form;
}
function poll_choice_js($form, $form_state) {
return $form['choice_wrapper']['choice'];
}
function poll_node_form_submit(&$form, &$form_state) {
$form_state['values']['choice'] = array_values($form_state['values']['choice']);
$form_state['values']['teaser'] = poll_teaser((object)$form_state['values']);
}
function poll_validate($node, $form) {
if (isset($node->title)) {
$realchoices = 0;
$node->choice = array_values($node->choice);
foreach ($node->choice as $i => $choice) {
if ($choice['chtext'] != '') {
$realchoices++;
}
if (isset($choice['chvotes']) && $choice['chvotes'] < 0) {
form_set_error("choice][$i][chvotes", t('Negative values are not allowed.'));
}
}
if ($realchoices < 2) {
form_set_error("choice][$realchoices][chtext", t('You must fill in at least two choices.'));
}
}
}
function poll_node_prepare_translation($node) {
if ($node->type == 'poll') {
$node->choice = $node->translation_source->choice;
}
}
function poll_load($nodes) {
global $user;
foreach ($nodes as $node) {
$poll = db_query("SELECT runtime, active FROM {poll} WHERE nid = :nid", array(':nid' => $node->nid))->fetchObject();
$poll->choice = db_select('poll_choice', 'c')
->addTag('translatable')
->fields('c', array('chid', 'chtext', 'chvotes', 'weight'))
->condition('c.nid', $node->nid)
->orderBy('weight')
->execute()->fetchAllAssoc('chid', PDO::FETCH_ASSOC);
$poll->allowvotes = FALSE;
if (user_access('vote on polls') && $poll->active) {
if ($user->uid) {
$result = db_query('SELECT chid FROM {poll_vote} WHERE nid = :nid AND uid = :uid', array(':nid' => $node->nid, ':uid' => $user->uid))->fetchObject();
}
else {
$result = db_query("SELECT chid FROM {poll_vote} WHERE nid = :nid AND hostname = :hostname", array(':nid' => $node->nid, ':hostname' => ip_address()))->fetchObject();
}
if ($result) {
$poll->vote = $result->chid;
}
else {
$poll->vote = -1;
$poll->allowvotes = TRUE;
}
}
foreach ($poll as $key => $value) {
$nodes[$node->nid]->$key = $value;
}
}
}
function poll_insert($node) {
if (!user_access('administer nodes')) {
foreach ($node->choice as $i => $choice) {
$node->choice[$i]['chvotes'] = 0;
}
$node->active = 1;
}
db_insert('poll')
->fields(array(
'nid' => $node->nid,
'runtime' => $node->runtime,
'active' => $node->active,
))
->execute();
foreach ($node->choice as $choice) {
if ($choice['chtext'] != '') {
db_insert('poll_choice')
->fields(array(
'nid' => $node->nid,
'chtext' => $choice['chtext'],
'chvotes' => $choice['chvotes'],
'weight' => $choice['weight'],
))
->execute();
}
}
}
function poll_update($node) {
db_update('poll')
->fields(array(
'runtime' => $node->runtime,
'active' => $node->active,
))
->condition('nid', $node->nid)
->execute();
foreach ($node->choice as $key => $choice) {
if (!empty($choice['chtext'])) {
db_merge('poll_choice')
->key(array('chid' => $choice['chid']))
->fields(array(
'nid' => $node->nid,
'chtext' => $choice['chtext'],
'chvotes' => (int) $choice['chvotes'],
'weight' => $choice['weight'],
))
->updateExcept('nid')
->execute();
}
else {
db_delete('poll_vote')
->condition('nid', $node->nid)
->condition('chid', $key)
->execute();
}
}
}
function poll_delete($node) {
db_delete('poll')
->condition('nid', $node->nid)
->execute();
db_delete('poll_choice')
->condition('nid', $node->nid)
->execute();
db_delete('poll_vote')
->condition('nid', $node->nid)
->execute();
}
function poll_block_latest_poll_view($node) {
global $user;
$output = '';
$node = clone $node;
unset($node->content);
$node->readmore = FALSE;
$node->teaser = '';
$links = array();
$links[] = array('title' => t('Older polls'), 'href' => 'poll', 'attributes' => array('title' => t('View the list of polls on this site.')));
if ($node->allowvotes) {
$links[] = array('title' => t('Results'), 'href' => 'node/' . $node->nid . '/results', 'attributes' => array('title' => t('View the current poll results.')));
}
$node->links = $links;
if (!empty($node->allowvotes)) {
$node->content['poll_view_voting'] = drupal_get_form('poll_view_voting', $node, TRUE);
}
else {
$node->content['poll_view_results'] = array('#markup' => poll_view_results($node, TRUE, TRUE));
}
return $node;
}
function poll_view($node, $build_mode = 'full') {
global $user;
$output = '';
if (!empty($node->allowvotes) && empty($node->show_results)) {
$node->content['poll_view_voting'] = drupal_get_form('poll_view_voting', $node);
}
else {
$node->content['poll_view_results'] = array('#markup' => poll_view_results($node, $build_mode));
}
return $node;
}
function poll_teaser($node) {
$teaser = NULL;
if (is_array($node->choice)) {
foreach ($node->choice as $k => $choice) {
if ($choice['chtext'] != '') {
$teaser .= '* ' . check_plain($choice['chtext']) . "\n";
}
}
}
return $teaser;
}
function poll_view_voting($form, &$form_state, $node, $block = FALSE) {
if ($node->choice) {
$list = array();
foreach ($node->choice as $i => $choice) {
$list[$i] = check_plain($choice['chtext']);
}
$form['choice'] = array(
'#type' => 'radios',
'#default_value' => -1,
'#options' => $list,
);
}
$form['vote'] = array(
'#type' => 'submit',
'#value' => t('Vote'),
'#submit' => array('poll_vote'),
);
$form['#node'] = $node;
$form['#block'] = $block;
$form_state['cache'] = TRUE;
$form['#theme'] = 'poll_vote';
return $form;
}
function poll_view_voting_validate($form, &$form_state) {
if ($form_state['values']['choice'] == -1) {
form_set_error( 'choice', t('Your vote could not be recorded because you did not select any of the choices.'));
}
}
function poll_vote($form, &$form_state) {
$node = $form['#node'];
$choice = $form_state['values']['choice'];
global $user;
db_insert('poll_vote')
->fields(array(
'nid' => $node->nid,
'chid' => $choice,
'uid' => $user->uid,
'hostname' => $user->uid ? ip_address() : '',
))
->execute();
db_update('poll_choice')
->expression('chvotes', 'chvotes + 1')
->condition('chid', $choice)
->execute();
cache_clear_all();
drupal_set_message(t('Your vote was recorded.'));
}
function template_preprocess_poll_vote(&$variables) {
$form = $variables['form'];
$variables['choice'] = drupal_render($form['choice']);
$variables['title'] = check_plain($form['#node']->title[LANGUAGE_NONE][0]['value']);
$variables['vote'] = drupal_render($form['vote']);
$variables['rest'] = drupal_render_children($form);
$variables['block'] = $form['#block'];
if ($variables['block']) {
$variables['template_files'][] = 'poll-vote-block';
}
}
function poll_view_results($node, $build_mode, $block = FALSE) {
$total_votes = 0;
$max_votes = 0;
foreach ($node->choice as $choice) {
if (isset($choice['chvotes'])) {
$total_votes += $choice['chvotes'];
$max_votes = max($max_votes, $choice['chvotes']);
}
}
$poll_results = '';
foreach ($node->choice as $i => $choice) {
if (!empty($choice['chtext'])) {
$chvotes = isset($choice['chvotes']) ? $choice['chvotes'] : NULL;
$poll_results .= theme('poll_bar', array('title' => $choice['chtext'], 'votes' => $chvotes, 'total_votes' => $total_votes, 'vote' => isset($node->vote) && $node->vote == $i, 'block' => $block));
}
}
return theme('poll_results', array('raw_title' => $node->title[LANGUAGE_NONE][0]['value'], 'results' => $poll_results, 'votes' => $total_votes, 'raw_links' => isset($node->links) ? $node->links : array(), 'block' => $block, 'nid' => $node->nid, 'vote' => isset($node->vote) ? $node->vote : NULL));
}
function theme_poll_choices($variables) {
$form = $variables['form'];
drupal_add_tabledrag('poll-choice-table', 'order', 'sibling', 'poll-weight');
$delta = 0;
$rows = array();
$headers = array(
'',
t('Choice'),
t('Vote count'),
t('Weight'),
);
foreach (element_children($form) as $key) {
$delta++;
$form[$key]['weight']['#attributes']['class'] = array('poll-weight');
$row = array(
'data' => array(
array('class' => array('choice-flag')),
drupal_render($form[$key]['chtext']),
drupal_render($form[$key]['chvotes']),
drupal_render($form[$key]['weight']),
),
'class' => array('draggable'),
);
if (!empty($form[$key]['#attributes']['class'])) {
$row['class'] = array_merge($row['class'], $form[$key]['#attributes']['class']);
}
$rows[] = $row;
}
$output = theme('table', array('header' => $headers, 'rows' => $rows, 'attributes' => array('id' => 'poll-choice-table')));
$output .= drupal_render_children($form);
return $output;
}
function template_preprocess_poll_results(&$variables) {
$variables['links'] = theme('links', array('links' => $variables['raw_links']));
if (isset($variables['vote']) && $variables['vote'] > -1 && user_access('cancel own vote')) {
$variables['cancel_form'] = drupal_render(drupal_get_form('poll_cancel_form', $variables['nid']));
}
$variables['title'] = check_plain($variables['raw_title']);
if ($variables['block']) {
$variables['template_files'][] = 'poll-results-block';
}
}
function template_preprocess_poll_bar(&$variables) {
if ($variables['block']) {
$variables['template_files'][] = 'poll-bar-block';
}
$variables['title'] = check_plain($variables['title']);
$variables['percentage'] = round($variables['votes'] * 100 / max($variables['total_votes'], 1));
}
function poll_cancel_form($form, &$form_state, $nid) {
$form_state['cache'] = TRUE;
$form['#nid'] = $nid;
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Cancel your vote'),
'#submit' => array('poll_cancel')
);
return $form;
}
function poll_cancel($form, &$form_state) {
global $user;
$node = node_load($form['#nid']);
db_delete('poll_vote')
->condition('nid', $node->nid)
->condition($user->uid ? 'uid' : 'hostname', $user->uid ? $user->uid : ip_address())
->execute();
db_update('poll_choice')
->expression('chvotes', 'chvotes - 1')
->condition('chid', $node->vote)
->execute();
drupal_set_message(t('Your vote was cancelled.'));
}
function poll_user_cancel($edit, $account, $method) {
switch ($method) {
case 'user_cancel_reassign':
db_update('poll_vote')
->fields(array('uid' => 0))
->condition('uid', $account->uid)
->execute();
break;
case 'user_cancel_delete':
db_delete('poll_vote')
->condition('uid', $account->uid)
->execute();
break;
}
}