You are here

scale.module in Quiz 6.4

The main file for scale.

Sponsored by: Norwegian Centre for Telemedicine Code: falcon

Scale question type for the Quiz module.

Allows the creation of scale questions (ex: likert scale)

File

question_types/scale/scale.module
View source
<?php

/**
 * The main file for scale.
 *
 * Sponsored by: Norwegian Centre for Telemedicine
 * Code: falcon
 *
 * @file
 * Scale question type for the Quiz module.
 *
 * Allows the creation of scale questions (ex: likert scale)
 */

/**
 * Implementation of hook_help().
 */
function scale_help($path, $args) {
  if ($path == 'admin/help#scale') {
    return t('This module provides a scale question type for Quiz. It may be used to construct surveys.');
  }
}

/**
 * Implementation of hook_menu().
 */
function scale_menu() {
  $items['scale/collection/manage'] = array(
    'title' => 'Manage your preset collections',
    'access callback' => 'user_access',
    'access arguments' => array(
      'create quiz',
    ),
    'type' => MENU_SUGGESTED_ITEM,
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'scale_manage_collection_form',
    ),
  );
  return $items;
}

/**
 * Implementation of hook_theme
 */
function scale_theme($existing, $type, $theme, $path) {
  return array(
    'scale_creation_form' => array(
      'arguments' => array(
        'form' => NULL,
      ),
      'path' => drupal_get_path('module', 'scale') . '/theme',
      'file' => 'scale.theme.inc',
    ),
    'scale_response_form' => array(
      'arguments' => array(
        'form' => NULL,
      ),
      'path' => drupal_get_path('module', 'scale') . '/theme',
      'file' => 'scale.theme.inc',
    ),
    'scale_answer_node_view' => array(
      'arguments' => array(
        'alternatives' => NULL,
      ),
      'path' => drupal_get_path('module', 'scale') . '/theme',
      'file' => 'scale.theme.inc',
    ),
    'scale_answering_form' => array(
      'arguments' => array(
        'form' => NULL,
      ),
      'path' => drupal_get_path('module', 'scale') . '/theme',
      'template' => 'scale-answering-form',
    ),
  );
}

/**
 * Implementation of hook_perm()
 */
function scale_perm() {
  return array(
    'Edit global presets',
  );
}

/**
 * Implementation of hook_quiz_question_info().
 */
function scale_quiz_question_info() {
  return array(
    'scale' => array(
      'name' => t('Scale question'),
      'description' => t('Quiz questions that allow a user to choose from a scale.'),
      'question provider' => 'ScaleQuestion',
      'response provider' => 'ScaleResponse',
      'module' => 'quiz_question',
    ),
  );
}

/**
 * Implementation off hook_config
 */
function scale_config() {
  $form['manage'] = array(
    '#type' => 'markup',
    '#value' => l(t('Manage presets'), 'scale/collection/manage'),
  );
  $form['scale_max_num_of_alts'] = array(
    '#type' => 'textfield',
    '#title' => t('Maximum number of alternatives allowed'),
    '#default_value' => variable_get('scale_max_num_of_alts', 10),
  );
  $form['#validate'] = 'scale_config_validate';
  return $form;
}

/**
 * Validate the scale config form values
 */
function scale_config_validate($form, $form_state) {
  if (!_quiz_is_int($form_state['values']['scale_max_num_of_alts'], 2, 50)) {
    form_set_error('scale_max_num_of_alts', t('The number of alternatives must be between 2 and 50'));
  }
}

/**
 * Implementation of hook_autoload_info().
 */
function scale_autoload_info() {
  return array(
    'ScaleQuestion' => array(
      'file' => 'scale.classes.inc',
    ),
    'ScaleResponse' => array(
      'file' => 'scale.classes.inc',
    ),
  );
}

/**
 * Implementation of hook user.
 */
function scale_user($op, &$edit, &$account, $category = NULL) {
  switch ($op) {
    case 'delete':

      //Remove the users presets if they aren't in use.
      $sql = 'SELECT id
              FROM {quiz_scale_answer_collection} ac
              JOIN {quiz_scale_user} u ON(ac.id = u.answer_collection_id)
              WHERE uid = %d
              AND ac.for_all = 0
              AND ac.id NOT IN
                (SELECT answer_collection_id
                 FROM {quiz_scale_node_properties})
              AND ac.id NOT IN
                (SELECT answer_collection_id
                 FROM {quiz_scale_user}
                 WHERE NOT uid = %d)';
      $res = db_query($sql, $account->uid, $account->uid);
      while ($res_o = db_fetch_object($res)) {
        $sql = 'DELETE FROM {quiz_scale_answer}
            WHERE answer_collection_id = %d';
        db_query($sql, $res_o->id);
        $sql = 'DELETE FROM {quiz_scale_answer_collection}
            WHERE id = %d';
        db_query($sql, $res_o->id);
        $sql = 'DELETE FROM {quiz_scale_user}
            WHERE uid = %d';
        db_query($sql, $account->uid);
      }
      break;
  }
}

/**
 * Form for changing and deleting the current users preset answer collections.
 *
 * Users with the Edit global presets permissions can also add new global
 * presets here.
 *
 * @param $form_state
 * @return form
 */
function scale_manage_collection_form(&$form_state) {
  global $user;
  $edit_globals_access = user_access('Edit global presets');

  // We create an instance of ScaleQuestion. We want to use some of its methods.
  $scale_question = new ScaleQuestion(new stdClass());
  $collections = $scale_question
    ->getPresetCollections($edit_globals_access);

  // If user is allowed to edit global answer collections he is also allowed to add new global presets
  if ($edit_globals_access) {
    $new_col = new stdClass();
    $new_col->for_all = 1;
    $new_col->name = t('New global collection(available to all users)');
    $collections['new'] = $new_col;
  }
  $form = array();
  if (count($collections) == 0) {
    $form['no_col'] = array(
      '#value' => t('You don\'t have any preset collections'),
    );
    return $form;
  }

  // Populate the form
  foreach ($collections as $col_id => $obj) {
    $form["collection{$col_id}"] = array(
      '#type' => 'fieldset',
      '#title' => $collections[$col_id]->name,
      '#collapsible' => TRUE,
      '#collapsed' => TRUE,
    );
    $alternatives = $collections[$col_id]->alternatives;
    for ($i = 0; $i < variable_get('scale_max_num_of_alts', 10); $i++) {
      $form["collection{$col_id}"]["alternative{$i}"] = array(
        '#title' => t('Alternative !i', array(
          '!i' => $i + 1,
        )),
        '#size' => 60,
        '#maxlength' => 256,
        '#type' => 'textfield',
        '#default_value' => $alternatives[$i],
        '#required' => $i < 2 && $col_id != 'new',
      );
    }
    if ($col_id != 'new') {
      if ($edit_globals_access) {
        $form["collection{$col_id}"]["for_all"] = array(
          '#type' => 'checkbox',
          '#title' => t("Available to all users"),
          '#default_value' => $collections[$col_id]->for_all,
        );
      }
      $form["collection{$col_id}"]["to-do"] = array(
        '#type' => 'radios',
        '#title' => t("What will you do?"),
        '#default_value' => '0',
        '#options' => array(
          t('Save changes, do not change questions using this preset'),
          t('Save changes, and change your own questions who uses this preset'),
          t('Delete this preset(This will not affect existing questions)'),
        ),
      );
    }
    else {
      $form["collection{$col_id}"]["to-do"] = array(
        '#type' => 'value',
        '#value' => 3,
      );
      $form["collection{$col_id}"]["for_all"] = array(
        '#type' => 'value',
        '#value' => 1,
      );
    }
  }
  $form['process'] = array(
    '#type' => 'submit',
    '#value' => t('Submit'),
  );
  $form['#submit'][] = 'scale_collection_form_submit';
  if ($edit_globals_access) {
    $form['#validate'][] = 'scale_collection_form_validate';
  }
  $form['#tree'] = TRUE;
  return $form;
}

/**
 * Handles the scale collection form.
 *
 * @param $form
 * @param $form_state
 */
function scale_collection_form_submit($form, &$form_state) {
  global $user;
  $changed = 0;
  $deleted = 0;
  foreach ($form_state['values'] as $key => $alternatives) {
    if ($col_id = _scale_get_col_id($key)) {
      $s_q = new ScaleQuestion(new stdClass());
      $s_q
        ->initUtil($col_id);
      switch ($alternatives['to-do']) {

        // @todo: Rename to-do to $op
        case 0:

        //Save, but don't change
        case 1:

          //Save and change existing questions
          $new_col_id = $s_q
            ->saveAnswerCollection(FALSE, $alternatives, 1);
          if (isset($alternatives['for_all'])) {
            _scale_set_for_all($new_col_id, $alternatives['for_all']);
          }
          if ($new_col_id == $col_id) {
            break;
          }
          $changed++;

          // We save the changes, but don't change existing questions
          if ($alternatives['to-do'] == 0) {

            // The old version of the collection shall not be a preset anymore
            _scale_unpreset_collection($col_id, $user->uid);

            // If the old version of the collection doesn't belong to any questions it is safe to delete it.
            $s_q
              ->deleteCollectionIfNotUsed($col_id);
            if (isset($alternatives['for_all'])) {
              _scale_set_for_all($new_col_id, $alternatives['for_all']);
            }
          }
          elseif ($alternatives['to-do'] == 1) {

            // Update all the users questions where the collection is used
            $sql = 'UPDATE {quiz_scale_node_properties}
                    SET answer_collection_id = %d
                    WHERE answer_collection_id = %d
                    AND nid IN(
                      SELECT nid
                      FROM {node}
                      WHERE uid = %d
                    )';
            db_query($sql, $new_col_id, $col_id, $user->uid);
            db_query('DELETE FROM {quiz_scale_user} WHERE answer_collection_id = %d AND uid = %d', $col_id, $user->uid);
            $s_q
              ->deleteCollectionIfNotUsed($col_id);
          }
          break;
        case 2:

          //Delete
          $got_deleted = $s_q
            ->deleteCollectionIfNotUsed($col_id);
          if (!$got_deleted) {
            _scale_unpreset_collection($col_id, $user->uid);
          }
          $deleted++;
          break;
        case 3:

          //New
          if (drupal_strlen($alternatives['alternative0']) > 0) {
            $new_col_id = $s_q
              ->saveAnswerCollection(FALSE, $alternatives, 1);
            _scale_set_for_all($new_col_id, $alternatives['for_all']);
            drupal_set_message(t('New preset has been added'));
          }
          break;
      }
    }
  }
  if ($changed > 0) {
    drupal_set_message(t('!changed presets have been changed.', array(
      '!changed' => $changed,
    )));
  }
  if ($deleted > 0) {
    drupal_set_message(t('!deleted presets have been deleted.', array(
      '!deleted' => $deleted,
    )));
  }
}

/**
 * Validates the scale collection form
 */
function scale_collection_form_validate($form, &$form_state) {

  // If the user is trying to create a new collection
  if (drupal_strlen($form_state['values']['collectionnew']['alternative0']) > 0) {

    // If the new collection don't have two alternatives
    if (drupal_strlen($form_state['values']['collectionnew']['alternative1']) == 0) {

      // This can't be replaced by adding #required to the form elements. If we did so we would always have to
      // create a new collection when we press submit
      form_set_error('collectionnew][alternative1', t('New preset must have atleast two alternatives.'));
    }
  }
}

/**
 * Searches a string for the answer collection id
 *
 * @param $string
 * @return answer collection id
 */
function _scale_get_col_id($string) {
  $res = array();
  $success = preg_match('/^collection([0-9]{1,}|new)$/', $string, $res);
  return $success > 0 ? $res[1] : FALSE;
}

/**
 * Make sure an answer collection isn't a preset for a given user.
 *
 * @param $col_id
 *  Answer_collection_id
 * @param $user_id
 */
function _scale_unpreset_collection($col_id, $user_id) {
  $sql = 'DELETE FROM {quiz_scale_user}
          WHERE answer_collection_id = %d AND uid = %d';
  db_query($sql, $col_id, $user_id);
  if (user_access('Edit global presets')) {
    $sql = 'UPDATE {quiz_scale_answer_collection}
            SET for_all = 0';
    db_query($sql);
  }
}

/**
 * Make an answer collection (un)available for all question creators.
 *
 * @param $new_col_id
 *  Answer collection id
 * @param $for_all
 *  0 if not for all,
 *  1 if for all
 */
function _scale_set_for_all($new_col_id, $for_all) {
  $sql = 'UPDATE {quiz_scale_answer_collection}
          SET for_all = %d
          WHERE id = %d';
  db_query($sql, $for_all, $new_col_id);
}

Functions

Namesort descending Description
scale_autoload_info Implementation of hook_autoload_info().
scale_collection_form_submit Handles the scale collection form.
scale_collection_form_validate Validates the scale collection form
scale_config Implementation off hook_config
scale_config_validate Validate the scale config form values
scale_help Implementation of hook_help().
scale_manage_collection_form Form for changing and deleting the current users preset answer collections.
scale_menu Implementation of hook_menu().
scale_perm Implementation of hook_perm()
scale_quiz_question_info Implementation of hook_quiz_question_info().
scale_theme Implementation of hook_theme
scale_user Implementation of hook user.
_scale_get_col_id Searches a string for the answer collection id
_scale_set_for_all Make an answer collection (un)available for all question creators.
_scale_unpreset_collection Make sure an answer collection isn't a preset for a given user.