You are here

botcha_form.controller.inc in BOTCHA Spam Prevention 6.2

Same filename and directory in other branches
  1. 7.2 controller/botcha_form.controller.inc

Controller layer of the BotchaForm objects.

File

controller/botcha_form.controller.inc
View source
<?php

/**
 * @file
 * Controller layer of the BotchaForm objects.
 */

/**
 * Special class to abstract operations with form_id. Casual usage is getting
 * all recipe books by form_id. It could be done by adding one more method to
 * Botcha (such as "getRecipebookByFormId") but in long-time perspective
 * it is counter-intuitive to extend our model by this way.
 * The way it is done here is as follows:
 * Botcha::getForm($form_id)
 *   ->getRecipebook();
 * It looks like additional layer of abstraction after DatabaseAbstractionLayer.
 * It helps us to get necessary data - while we don't have to repeat ourselves
 * in many places, writing queries to the database. All logic is hidden under
 * this simple interface: getForm, getRecipebook, getRecipe.
 */
abstract class BotchaFormAbstract {
  protected $recipebook;
  protected function __construct($form_id) {
    $this->id = $form_id;
  }

  /**
   * @todo BotchaForm getForm Description.
   * @param string $form_id
   * @param boolean $create
   *   Determines should we construct new form or return NULL if it does not exist.
   * @return BotchaForm
   */
  public static function getForm($form_id, $create = TRUE) {
    $none = TRUE;

    // Respect form exceptions (done by forbidden_forms recipe book).

    //if (!in_array($form_id, array('user_login', 'user_login_block', 'update_script_selection_form'))) {
    $form = BotchaFormModel::getForm($form_id);
    if ($form || $create) {
      $none = FALSE;
    }

    //}
    $botcha_form = $none ? new BotchaFormNone($form_id) : new BotchaForm($form_id);
    return $botcha_form;
  }
  public function setRecipebook($rbid) {
    $this->recipebook = $rbid;

    // Save changed state.
    Botcha::setForm($this);
    return $this;
  }
  function unsetRecipebook() {

    // @todo Refactor unsetting recipebook. The constant is here because we need to differ the case when the recipe book is not set at all and the case when it is set to none.
    // @see getRecipebook()
    $this->recipebook = 'none';

    // Save changed state.
    Botcha::setForm($this);
    return $this;
  }

  /**
   * @todo BotchaForm getRecipebook Description.
   * @return BotchaRecipebook
   */
  public function getRecipebook() {
    if (!isset($this->recipebook)) {
      $rbs = array_keys(BotchaModel::getRecipebooksForms(array(
        'mode' => 'recipebook',
        'forms' => $this->id,
      )));

      // In fact there is not more than 1 item.
      $this->recipebook = !empty($rbs) ? current($rbs) : 'none';
    }
    return Botcha::getRecipebook($this->recipebook, FALSE);
  }
  public function isEnabled() {
    $form_id = $this->id;
    $isEnabled = variable_get("botcha_enabled_{$form_id}", 0);
    return $isEnabled;
  }
  public function setEnabled($enabled) {
    $form_id = $this->id;

    // Cast to boolean first.
    $enabled = (bool) $enabled;

    // Cast to integer.
    $enabled = (int) $enabled;
    variable_set("botcha_enabled_{$form_id}", $enabled);
    return $this;
  }
  public function addAdminLinks(&$form) {
    $form_id = $form['form_id']['#value'];
    if (variable_get('botcha_administration_mode', FALSE) && user_access('administer BOTCHA settings') && (arg(0) != 'admin' || variable_get('botcha_allow_on_admin_pages', FALSE) || $form_id == 'user_register') && $form_id != 'update_script_selection_form') {

      // Add BOTCHA administration tools.
      $botcha_element = $this
        ->createAdminLinksFieldset($form_id);

      // Get placement in form and insert in form.
      // @todo Make away with a dependency from botcha.inc.
      $botcha_placement = _botcha_get_botcha_placement($form_id, $form);
      _botcha_insert_botcha_element($form, $botcha_placement, $botcha_element);
    }
  }
  protected function createAdminLinksFieldset($form_id) {

    // For administrators: show BOTCHA info and offer link to configure it.
    return array(
      '#type' => 'fieldset',
      '#title' => t('BOTCHA'),
      '#collapsible' => TRUE,
      '#collapsed' => TRUE,
      // @todo Abstract it.

      //'#attributes' => array('class' => array('botcha-admin-links')),
      '#attributes' => array(
        'class' => 'botcha-admin-links',
      ),
    );
  }

  // @todo ?Should we separate BotchaForm and BotchaFormAbstract?
  public function save() {

    // Save our form to cache.
    Botcha::setForm($this);

    // Save form to DB.
    BotchaFormModel::save($this);

    // Clean session to fetch new values.
    Botcha::clean();
    return $this;
  }
  public function delete() {

    // Save our form to cache.
    Botcha::unsetForm($this);

    // Save form to DB.
    BotchaFormModel::delete($this);

    // Clean session to fetch new values.
    Botcha::clean();
  }

}
class BotchaForm extends BotchaFormAbstract {
  protected function createAdminLinksFieldset($form_id) {
    $botcha_element = parent::createAdminLinksFieldset($form_id);
    $recipebook = $this
      ->getRecipebook();
    if ($recipebook instanceof BotchaRecipebookNone) {
      $botcha_element = parent::createAdminLinksFieldset($form_id);
      $botcha_element['#title'] = t('BOTCHA: no protection enabled');
      $botcha_element['add_botcha'] = array(
        // @todo Abstract it.

        //'#markup' => l(t('Add BOTCHA protection on form'), Botcha::BOTCHA_ADMIN_PATH . "/form/add", array('query' => array_merge(drupal_get_destination(), array('botcha_form_id' => $form_id)), 'html' => TRUE)),
        '#value' => l(t('Add BOTCHA protection on form'), Botcha::BOTCHA_ADMIN_PATH . "/form/add", array(
          'query' => drupal_get_destination() . "&botcha_form_id={$form_id}",
          'html' => TRUE,
        )),
      );
    }
    else {
      $botcha_element['#title'] = t('BOTCHA: protection enabled (@recipebook recipe book)', array(
        '@recipebook' => $recipebook->id,
      ));
      $botcha_element['#description'] = t('Untrusted users will have form %form_id protected by BOTCHA (!recipebook_settings, !general_settings).', array(
        '%form_id' => $form_id,
        '!recipebook_settings' => l(t('Recipe book settings'), Botcha::BOTCHA_ADMIN_PATH . "/recipebook/{$recipebook->id}"),
        '!general_settings' => l(t('General BOTCHA settings'), Botcha::BOTCHA_ADMIN_PATH),
      ));
      $botcha_element['protection'] = array(
        '#type' => 'item',
        '#title' => t('Enabled protection'),
        // @todo Abstract it.

        //'#markup' => t('Form is protected by "@recipebook" recipe book (!edit, !disable)', array(
        '#value' => t('Form is protected by "@recipebook" recipe book (!edit, !disable)', array(
          '@recipebook' => $recipebook->id,
          '!edit' => l(t('edit'), Botcha::BOTCHA_ADMIN_PATH . "/form/{$form_id}", array(
            'query' => drupal_get_destination(),
            'html' => TRUE,
          )),
          '!disable' => l(t('disable'), Botcha::BOTCHA_ADMIN_PATH . "/form/{$form_id}/disable", array(
            'query' => drupal_get_destination(),
            'html' => TRUE,
          )),
        )),
      );
    }
    return $botcha_element;
  }

}

/**
 * Dummy class, created for data consistency and for interface unifying.
 * When there is no form, this class is used as a handler.
 * It has no logic at all - by design.
 */
class BotchaFormNone extends BotchaFormAbstract {
  public function __construct($form_id = NULL) {
    $this->id = !empty($form_id) ? $form_id : 'none';
  }
  public function getRecipebook() {
    return new BotchaRecipebookNone();
  }
  public function addAdminLinks(&$form) {
    $form_id = $form['form_id']['#value'];

    // Apply only to allowed forms.
    // @todo Move it to new abstraction: form exceptions.
    if (!in_array($form_id, array(
      'update_script_selection_form',
      'user_login',
      'user_login_block',
    ))) {
      parent::addAdminLinks($form);
    }
  }
  protected function createAdminLinksFieldset($form_id) {
    $botcha_element = parent::createAdminLinksFieldset($form_id);
    $botcha_element['#title'] = t('BOTCHA: no protection enabled');
    $botcha_element['add_botcha'] = array(
      // @todo Abstract it.

      //'#markup' => l(t('Add BOTCHA protection on form'), Botcha::BOTCHA_ADMIN_PATH . "/form/add", array('query' => array_merge(drupal_get_destination(), array('botcha_form_id' => $form_id)), 'html' => TRUE)),
      '#value' => l(t('Add BOTCHA protection on form'), Botcha::BOTCHA_ADMIN_PATH . "/form/add", array(
        'query' => drupal_get_destination() . "&botcha_form_id={$form_id}",
        'html' => TRUE,
      )),
    );
    return $botcha_element;
  }
  public function save() {
    Botcha::unsetForm($this);

    // Save form to DB.
    BotchaFormModel::save($this);

    // Clean session to fetch new values.
    Botcha::clean();
    return $this;
  }

}

Classes

Namesort descending Description
BotchaForm
BotchaFormAbstract Special class to abstract operations with form_id. Casual usage is getting all recipe books by form_id. It could be done by adding one more method to Botcha (such as "getRecipebookByFormId") but in long-time perspective it is…
BotchaFormNone Dummy class, created for data consistency and for interface unifying. When there is no form, this class is used as a handler. It has no logic at all - by design.