You are here

botcha_form.controller.inc in BOTCHA Spam Prevention 7.2

Same filename and directory in other branches
  1. 6.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() {
    unset($this->recipebook);

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

  /**
   * @todo BotchaForm getRecipebook Description.
   * @return BotchaRecipebook
   */
  public function getRecipebook() {
    if (empty($this->recipebook)) {
      $rbs = 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')) {

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

      // Get placement in form and insert in form.
      // @todo BotchaRecipebook isApplicable 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',
        ),
      ),
    );
  }

  // @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 = Botcha::getForm($form_id, FALSE)
      ->getRecipebook();
    $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'),
      '#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 BotchaForm {

  // @todo Refactor this since it is duplication.
  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,
      )),
    );
    return $botcha_element;
  }
  public function save() {
    Botcha::unsetForm($this);

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

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

}

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.