Skip to content
Snippets Groups Projects
poll.module 14.4 KiB
Newer Older
  • Learn to ignore specific revisions
  • Dries Buytaert's avatar
     
    Dries Buytaert committed
    /**
     * @file
     * Enables your site to capture votes on different topics in the form of multiple
     * choice questions.
     */
    
    
    /**
     * Implementation of hook_help().
     */
    function poll_help($section) {
    
    Steven Wittens's avatar
    Steven Wittens committed
      switch ($section) {
        case 'admin/help#poll':
    
    Steven Wittens's avatar
    Steven Wittens committed
          <p>Users with the correct <a href=\"%permissions\">permissions</a> can create and/or vote on polls.</p>
          <ul>
          <li>To create a poll a user needs the \"create polls\" permission.</li>
          <li>To vote on a poll question a user must have the \"vote on polls\" permission.</li>
          <li>To view the results one needs the \"access content\" permission.</li>
          <li>To administer polls you need the \"administer nodes\" permission.</li>
          </ul>
    
          <p>Creating a poll is much like creating any other node. Click \"create poll\" in your user box. The title of the poll should be the question, then enter the answers and the \"base\" vote counts. You can also choose the time period over which the vote will run.</p><p>The <a href=\"%poll\">Poll</a> item in the navigation links will take you to a page where you can see all the current polls, vote on them (if you haven't already) and view the results.</p>", array("%permissions" => url("admin/access/permissions"), "%poll" => url("poll")));
    
    Dries Buytaert's avatar
     
    Dries Buytaert committed
        case 'admin/modules#description':
    
          return t("Allows your site to capture votes on different topics in the form of multiple choice questions.");
    
    Steven Wittens's avatar
    Steven Wittens committed
        case 'node/add#poll':
    
          return t("A poll is a multiple-choice question which visitors can vote on.");
    
    function poll_access($op, $node) {
    
    Steven Wittens's avatar
    Steven Wittens committed
      if ($op == 'create') {
        return user_access('create polls');
    
    Dries Buytaert's avatar
     
    Dries Buytaert committed
      }
    
    /**
     * Implementation of hook_block().
     *
     * Generates a block containing the latest poll.
     */
    
    Steven Wittens's avatar
    Steven Wittens committed
    function poll_block($op = 'list', $delta = 0) {
      if (user_access('access content')) {
        if ($op == 'list') {
          $blocks[0]['info'] = t('Most recent poll');
    
    Dries Buytaert's avatar
     
    Dries Buytaert committed
          return $blocks;
        }
    
          $sql = db_rewrite_sql("SELECT MAX(n.created) FROM {node} n INNER JOIN {poll} p ON p.nid = n.nid WHERE n.status = 1 AND p.active = 1 AND n.moderate = 0");
    
    Dries Buytaert's avatar
     
    Dries Buytaert committed
          $timestamp = db_result(db_query($sql));
    
    Dries Buytaert's avatar
     
    Dries Buytaert committed
          if ($timestamp) {
    
    Steven Wittens's avatar
    Steven Wittens committed
            $poll = node_load(array('type' => 'poll', 'created' => $timestamp, 'moderate' => 0, 'status' => 1));
    
    
    Dries Buytaert's avatar
     
    Dries Buytaert committed
            if ($poll->nid) {
    
              // poll_view() dumps the output into $poll->body.
    
    Dries Buytaert's avatar
     
    Dries Buytaert committed
            }
    
    Dries Buytaert's avatar
     
    Dries Buytaert committed
          }
    
    Steven Wittens's avatar
    Steven Wittens committed
          $block['subject'] = t('Poll');
          $block['content'] = $poll->body;
    
    Dries Buytaert's avatar
     
    Dries Buytaert committed
          return $block;
    
    /**
     * Implementation of hook_cron().
     *
     * Closes polls that have exceeded their allowed runtime.
     */
    
    function poll_cron() {
    
      $result = db_query('SELECT p.nid FROM {poll} p INNER JOIN {node} n ON p.nid = n.nid WHERE (n.created + p.runtime) < '. time() .' AND p.active = 1 AND p.runtime != 0');
    
    Dries Buytaert's avatar
     
    Dries Buytaert committed
      while ($poll = db_fetch_object($result)) {
    
        db_query("UPDATE {poll} SET active = 0 WHERE nid = %d", $poll->nid);
    
    Dries Buytaert's avatar
     
    Dries Buytaert committed
      }
    
    function poll_delete($node) {
    
      db_query("DELETE FROM {poll} WHERE nid = %d", $node->nid);
    
    Dries Buytaert's avatar
     
    Dries Buytaert committed
      db_query("DELETE FROM {poll_choices} WHERE nid = %d", $node->nid);
    
    
      node_validate_title($node,t('You have to specify a question.'));
    
    
      if (isset($node->title)) {
        // Check for at least two options and validate amount of votes:
    
    Steven Wittens's avatar
    Steven Wittens committed
        $realchoices = 0;
    
        // Renumber fields
        $node->choice = array_values($node->choice);
    
    Steven Wittens's avatar
    Steven Wittens committed
        foreach ($node->choice as $i => $choice) {
          if ($choice['chtext'] != '') {
            $realchoices++;
    
    Steven Wittens's avatar
    Steven Wittens committed
          if ($choice['chvotes'] < 0) {
    
    Dries Buytaert's avatar
     
    Dries Buytaert committed
            form_set_error("choice][$i][chvotes", t('Negative values are not allowed.'));
    
    Dries Buytaert's avatar
     
    Dries Buytaert committed
    
    
    Steven Wittens's avatar
    Steven Wittens committed
        if ($realchoices < 2) {
    
    Dries Buytaert's avatar
     
    Dries Buytaert committed
          form_set_error("choice][$realchoices][chtext", t('You must fill in at least two choices.'));
    
    Dries Buytaert's avatar
     
    Dries Buytaert committed
    function poll_form(&$node) {
    
    Steven Wittens's avatar
    Steven Wittens committed
      $admin = user_access('administer nodes');
    
      $output = form_textfield(t('Question'), 'title', $node->title, 60, 128, NULL, NULL, TRUE);
    
    
    Steven Wittens's avatar
    Steven Wittens committed
      if (function_exists('taxonomy_node_form')) {
    
        $output .= implode('', taxonomy_node_form('poll', $node));
    
    Steven Wittens's avatar
    Steven Wittens committed
      }
    
    Steven Wittens's avatar
    Steven Wittens committed
      if (!isset($node->choices)) {
        $node->choices = max(2, count($node->choice) ? count($node->choice) : 5);
      }
    
    Dries Buytaert's avatar
     
    Dries Buytaert committed
    
    
    Steven Wittens's avatar
    Steven Wittens committed
      if ($node->morechoices) {
        $node->choices *= 2;
    
    Steven Wittens's avatar
    Steven Wittens committed
      $output .= '<div class="poll-form">';
    
    Dries Buytaert's avatar
     
    Dries Buytaert committed
    
    
    Steven Wittens's avatar
    Steven Wittens committed
      // Poll choices
    
    Dries Buytaert's avatar
     
    Dries Buytaert committed
      $opts = drupal_map_assoc(range(2, $node->choices * 2 + 5));
    
      for ($a = 0; $a < $node->choices; $a++) {
    
        $group1 .= form_textfield(t('Choice %n', array('%n' => ($a + 1))), "choice][$a][chtext", $node->choice[$a]['chtext'], 60, 127);
    
        if ($admin) {
    
          $group1 .= form_textfield(t('Votes for choice %n', array('%n' => ($a + 1))), "choice][$a][chvotes", (int)$node->choice[$a]['chvotes'], 5, 7);
    
    Steven Wittens's avatar
    Steven Wittens committed
      $group1 .= form_hidden('choices', $node->choices);
      $group1 .= form_checkbox(t('Need more choices'), 'morechoices', 1, 0, t("If the amount of boxes above isn't enough, check this box and click the Preview button below to add some more."));
      $output .= form_group(t('Choices'), $group1);
    
    Dries Buytaert's avatar
     
    Dries Buytaert committed
    
    
    Dries Buytaert's avatar
     
    Dries Buytaert committed
    
    
    Steven Wittens's avatar
    Steven Wittens committed
      // Poll attributes
    
      $_duration = array(0 => t('Unlimited')) + drupal_map_assoc(array(86400, 172800, 345600, 604800, 1209600, 2419200, 4838400, 9676800, 31536000), "format_interval");
    
    Steven Wittens's avatar
    Steven Wittens committed
      $_active = array(0 => t('Closed'), 1 => t('Active'));
    
    Dries Buytaert's avatar
     
    Dries Buytaert committed
    
    
    Steven Wittens's avatar
    Steven Wittens committed
      if ($admin) {
        $group2 .= form_radios(t('Poll status'), 'active', isset($node->active) ? $node->active : 1, $_active, t('When a poll is closed, visitors can no longer vote for it.'));
    
    Dries Buytaert's avatar
     
    Dries Buytaert committed
      }
    
    Steven Wittens's avatar
    Steven Wittens committed
      $group2 .= form_select(t('Poll duration'), 'runtime', $node->runtime ? $node->runtime : 0, $_duration, t('After this period, the poll will be closed automatically.'));
    
    Dries Buytaert's avatar
     
    Dries Buytaert committed
    
      $output .= form_group(t('Settings'), $group2);
    
    Steven Wittens's avatar
    Steven Wittens committed
      $output .= '</div>';
    
    Dries Buytaert's avatar
     
    Dries Buytaert committed
    
      return $output;
    
    function poll_insert($node) {
    
    Steven Wittens's avatar
    Steven Wittens committed
      if (!user_access('administer nodes')) {
    
        // Make sure all votes are 0 initially
    
    Steven Wittens's avatar
    Steven Wittens committed
        foreach ($node->choice as $i => $choice) {
          $node->choice[$i]['chvotes'] = 0;
        }
    
        $node->active = 1;
      }
    
      db_query("INSERT INTO {poll} (nid, runtime, polled, active) VALUES (%d, %d, '', %d)", $node->nid, $node->runtime, $node->active);
    
    Dries Buytaert's avatar
     
    Dries Buytaert committed
    
    
    Steven Wittens's avatar
    Steven Wittens committed
      foreach ($node->choice as $choice) {
        if ($choice['chtext'] != '') {
          db_query("INSERT INTO {poll_choices} (nid, chtext, chvotes, chorder) VALUES (%d, '%s', %d, %d)", $node->nid, $choice['chtext'], $choice['chvotes'], $i++);
    
    Dries Buytaert's avatar
     
    Dries Buytaert committed
    /**
     * Implementation of hook_menu().
     */
    
    Dries Buytaert's avatar
     
    Dries Buytaert committed
    function poll_menu($may_cache) {
    
    Dries Buytaert's avatar
     
    Dries Buytaert committed
      $items = array();
    
    Dries Buytaert's avatar
     
    Dries Buytaert committed
    
      if ($may_cache) {
        $items[] = array('path' => 'node/add/poll', 'title' => t('poll'),
          'access' => user_access('create polls'));
        $items[] = array('path' => 'poll', 'title' => t('polls'),
          'callback' => 'poll_page',
          'access' => user_access('access content'),
          'type' => MENU_SUGGESTED_ITEM);
    
        $items[] = array('path' => 'poll/vote',
          'title' => t('vote'),
          'callback' => 'poll_vote',
          'access' => user_access('vote on polls'),
          'type' => MENU_CALLBACK);
      }
      else {
        if (arg(0) == 'node' && is_numeric(arg(1))) {
    
          $node = node_load(arg(1));
    
    Dries Buytaert's avatar
     
    Dries Buytaert committed
    
          if ($node->type == 'poll' && $node->allowvotes) {
            $items[] = array('path' => 'node/'. arg(1) .'/results',
              'title' => t('results'),
              'callback' => 'poll_results',
              'access' => user_access('access content'),
              'weight' => 3,
              'type' => MENU_LOCAL_TASK);
          }
    
    Dries Buytaert's avatar
     
    Dries Buytaert committed
    
    
    Dries Buytaert's avatar
     
    Dries Buytaert committed
      return $items;
    }
    
    
    Steven Wittens's avatar
    Steven Wittens committed
    /**
     * Determine an adjusted user id, to allow for basic tracking of anonymous
     * users (IP-based).
     */
    function poll_uid() {
      global $user;
      if ($user->uid) {
         // Pad the UID with underscores to allow a simple strstr() search
        $id = '_'. $user->uid .'_';
      }
      else {
        $id = $_SERVER['REMOTE_ADDR'];
      }
      return $id;
    }
    
    
    function poll_load($node) {
      // Load the appropriate choices into the $node object
    
      $poll = db_fetch_object(db_query("SELECT runtime, polled, active FROM {poll} WHERE nid = %d", $node->nid));
    
    Dries Buytaert's avatar
     
    Dries Buytaert committed
    
    
      $result = db_query("SELECT chtext, chvotes, chorder FROM {poll_choices} WHERE nid = %d ORDER BY chorder", $node->nid);
    
    Steven Wittens's avatar
    Steven Wittens committed
      while ($choice = db_fetch_array($result)) {
        $poll->choice[$choice['chorder']] = $choice;
    
    Steven Wittens's avatar
    Steven Wittens committed
      // Determine whether or not this user is allowed to vote
      $poll->allowvotes = false;
      if (user_access('vote on polls')) {
    
        if (!strstr($poll->polled, poll_uid())) {
    
    Steven Wittens's avatar
    Steven Wittens committed
          $poll->allowvotes = $poll->active;
        }
      }
    
    Dries Buytaert's avatar
     
    Dries Buytaert committed
    
    
     * Implementation of hook_node_info().
    
      return array('poll' => array('name' => t("poll"), 'base' => 'poll'));
    
    Steven Wittens's avatar
    Steven Wittens committed
    function poll_page() {
    
    Steven Wittens's avatar
    Steven Wittens committed
      // List all polls
    
      $sql = "SELECT n.nid, n.title, p.active, n.created, SUM(c.chvotes) AS votes FROM {node} n INNER JOIN {poll} p ON n.nid = p.nid INNER JOIN {poll_choices} c ON n.nid = c.nid WHERE n.status = 1 AND n.moderate = 0 GROUP BY n.nid, n.title, p.active, n.created ORDER BY n.created DESC";
    
    Dries Buytaert's avatar
     
    Dries Buytaert committed
      $result = pager_query($sql, 15);
    
    Steven Wittens's avatar
    Steven Wittens committed
      $output = '<ul>';
    
    Steven Wittens's avatar
    Steven Wittens committed
      while ($node = db_fetch_object($result)) {
    
    Dries Buytaert's avatar
     
    Dries Buytaert committed
        $output .= '<li>'. l($node->title, "node/$node->nid") .' - '. format_plural($node->votes, '1 vote', '%count votes') .' - '. ($node->active ? t('open') : t('closed')) .'</li>';
    
    Steven Wittens's avatar
    Steven Wittens committed
      }
    
    Steven Wittens's avatar
    Steven Wittens committed
      $output .= '</ul>';
      $output .= theme("pager", NULL, 15);
    
    Dries Buytaert's avatar
     
    Dries Buytaert committed
      return $output;
    
    Steven Wittens's avatar
    Steven Wittens committed
    }
    
    
    function poll_perm() {
    
    Steven Wittens's avatar
    Steven Wittens committed
      return array('create polls', 'vote on polls');
    
    Dries Buytaert's avatar
     
    Dries Buytaert committed
    
    
    /**
     * Creates a simple teaser that lists all the choices.
     */
    
    function poll_teaser($node) {
    
    Dries Buytaert's avatar
    Dries Buytaert committed
      if (is_array($node->choice)) {
    
    Steven Wittens's avatar
    Steven Wittens committed
        foreach ($node->choice as $k => $choice) {
          $teaser .= '* '. $choice['chtext'] .'\n';
    
    Steven Wittens's avatar
    Steven Wittens committed
    /**
    
    Steven Wittens's avatar
    Steven Wittens committed
     */
    
    Dries Buytaert's avatar
    Dries Buytaert committed
    function poll_view_voting(&$node, $teaser, $page, $block) {
    
    Dries Buytaert's avatar
     
    Dries Buytaert committed
      $output = '<div class="poll">';
    
    Dries Buytaert's avatar
     
    Dries Buytaert committed
    
    
    Dries Buytaert's avatar
     
    Dries Buytaert committed
      $form = '<div class="vote-form">';
    
    Steven Wittens's avatar
    Steven Wittens committed
      $form .= '<div class="choices">';
    
    Dries Buytaert's avatar
     
    Dries Buytaert committed
      if ($node->choice) {
    
    Steven Wittens's avatar
    Steven Wittens committed
        $list = array();
        foreach ($node->choice as $i => $choice) {
    
          $list[$i] = check_plain($choice['chtext']);
    
        $form .= form_radios($page ? '' : check_plain($node->title), 'choice', -1, $list);
    
    Dries Buytaert's avatar
     
    Dries Buytaert committed
      }
    
    Steven Wittens's avatar
    Steven Wittens committed
      $form .= '</div>';
      $form .= form_hidden('nid', $node->nid);
      $form .= form_submit(t('Vote'), 'vote') .'</div>';
    
    
      $output .= form($form, 'post', url('poll/vote/'. $node->nid));
    
    Steven Wittens's avatar
    Steven Wittens committed
      $output .= '</div>';
    
    
      return $output;
    }
    
    
    /**
     * Generates a graphical representation of the results of a poll.
     */
    
    Dries Buytaert's avatar
    Dries Buytaert committed
    function poll_view_results(&$node, $teaser, $page, $block) {
    
      // Display the results
    
    Dries Buytaert's avatar
     
    Dries Buytaert committed
    
    
      // Count the votes and find the maximum
    
    Steven Wittens's avatar
    Steven Wittens committed
      foreach ($node->choice as $choice) {
        $votestotal += $choice['chvotes'];
        $votesmax = max($votesmax, $choice['chvotes']);
    
    Dries Buytaert's avatar
     
    Dries Buytaert committed
      // Output the divs for the text, bars and percentages
    
    Steven Wittens's avatar
    Steven Wittens committed
      $output .= '<div class="poll">';
      if ($block) {
    
        $output .= '<div class="title">'. check_plain($node->title) .'</div>';
    
    Steven Wittens's avatar
    Steven Wittens committed
      }
      foreach ($node->choice as $i => $choice) {
        if ($choice['chtext'] != '') {
          $percentage = round($choice['chvotes'] * 100 / max($votestotal, 1));
    
          $output .= '<div class="text">'. check_plain($choice['chtext']) .'</div>';
    
    Steven Wittens's avatar
    Steven Wittens committed
          $output .= '<div class="bar">';
          $output .= '<div style="width: '. $percentage .'%;" class="foreground"></div>';
          $output .= '</div>';
          $output .= '<div class="percent">'. $percentage .'%'. (!$block ? ' ('. format_plural($choice['chvotes'], '1 vote', '%count votes') .')' : '') .'</div>';
    
    Steven Wittens's avatar
    Steven Wittens committed
      $output .= '<div class="total">'. t('Total votes') .": $votestotal</div>";
    
    Dries Buytaert's avatar
     
    Dries Buytaert committed
    
    
    Steven Wittens's avatar
    Steven Wittens committed
      $output .= '</div>';
    
    
      return $output;
    }
    
    
    /**
     * Callback for the 'results' tab for polls you can vote on
     */
    function poll_results() {
    
      if ($node = node_load(arg(1))) {
    
        drupal_set_title(check_plain($node->title));
    
    Dries Buytaert's avatar
     
    Dries Buytaert committed
        return node_show($node, 0);
    
      }
      else {
        drupal_not_found();
      }
    }
    
    /**
     * Callback for processing a vote
     */
    function poll_vote(&$node) {
      $nid = arg(2);
    
      if ($node = node_load($nid)) {
    
        $edit = $_POST['edit'];
        $choice = $edit['choice'];
        $vote = $_POST['vote'];
    
    Steven Wittens's avatar
    Steven Wittens committed
    
        if (isset($choice) && isset($node->choice[$choice])) {
          if ($node->allowvotes) {
            $id = poll_uid();
    
            $node->polled = $node->polled ? ($node->polled .' '. $id) : $id;
    
            db_query("UPDATE {poll} SET polled = '%s' WHERE nid = %d", $node->polled, $node->nid);
    
    Steven Wittens's avatar
    Steven Wittens committed
            db_query("UPDATE {poll_choices} SET chvotes = chvotes + 1 WHERE nid = %d AND chorder = %d", $node->nid, $choice);
            $node->allowvotes = false;
            $node->choice[$choice]['chvotes']++;
    
    Dries Buytaert's avatar
     
    Dries Buytaert committed
            drupal_set_message(t('Your vote was recorded.'));
    
    Steven Wittens's avatar
    Steven Wittens committed
          }
          else {
    
    Dries Buytaert's avatar
     
    Dries Buytaert committed
            drupal_set_message(t("You're not allowed to vote on this poll."), 'error');
    
    Steven Wittens's avatar
    Steven Wittens committed
          }
        }
        else {
    
    Dries Buytaert's avatar
     
    Dries Buytaert committed
          drupal_set_message(t("You didn't specify a valid poll choice."), 'error');
    
    Steven Wittens's avatar
    Steven Wittens committed
        }
    
    
        drupal_goto('node/'. $nid);
      }
      else {
        drupal_not_found();
    
    /**
     * Implementation of hook_view().
     *
     * @param $block
     *   An extra parameter that adapts the hook to display a block-ready
     *   rendering of the poll.
     */
    
    Dries Buytaert's avatar
     
    Dries Buytaert committed
    function poll_view(&$node, $teaser = FALSE, $page = FALSE, $block = FALSE) {
    
    Dries Buytaert's avatar
     
    Dries Buytaert committed
      global $user;
    
    Dries Buytaert's avatar
     
    Dries Buytaert committed
      $output = '';
    
      if ($node->allowvotes && ($block || arg(2) != 'results')) {
    
    Dries Buytaert's avatar
    Dries Buytaert committed
        $output .= poll_view_voting($node, $teaser, $page, $block);
    
    Steven Wittens's avatar
    Steven Wittens committed
      }
      else {
    
    Dries Buytaert's avatar
    Dries Buytaert committed
        $output .= poll_view_results($node, $teaser, $page, $block);
    
    Steven Wittens's avatar
    Steven Wittens committed
      }
    
    Steven Wittens's avatar
    Steven Wittens committed
      // Special display for side-block
    
      if ($block) {
    
    Steven Wittens's avatar
    Steven Wittens committed
        // No 'read more' link
        $node->body = $node->teaser = '';
    
    Dries Buytaert's avatar
    Dries Buytaert committed
        $links = module_invoke_all('link', 'node', $node, 1);
    
    Steven Wittens's avatar
    Steven Wittens committed
        $links[] = l(t('older polls'), 'poll', array('title' => t('View the list of polls on this site.')));
    
        if ($node->allowvotes && $block) {
          $links[] = l(t('results'), 'node/'. $node->nid .'/results', array('title' => t('View the current poll results.')));
        }
    
    Steven Wittens's avatar
    Steven Wittens committed
        $output .= '<div class="links">'. theme("links", $links) .'</div>';
    
      }
    
      $node->body = $node->teaser = $output;
    
    function poll_update($node) {
    
    Steven Wittens's avatar
    Steven Wittens committed
      db_query('UPDATE {poll} SET runtime = %d, active = %d WHERE nid = %d', $node->runtime, $node->active, $node->nid);
    
    Steven Wittens's avatar
    Steven Wittens committed
      db_query('DELETE FROM {poll_choices} WHERE nid = %d', $node->nid);
      foreach ($node->choice as $choice) {
        $chvotes = (int)$choice['chvotes'];
        $chtext = $choice['chtext'];
    
    Steven Wittens's avatar
    Steven Wittens committed
        if ($chtext != '') {
          db_query("INSERT INTO {poll_choices} (nid, chtext, chvotes, chorder) VALUES (%d, '%s', %d, %d)", $node->nid, $chtext, $chvotes, $i++);