Numberguess en Drupal

HAY ALGUNOS ejecicios básicos que me gusta practicar cuando aprendo un framework. Aunque los tutoriales hagan otros, más reales o útiles, estos me siguen pareciendo un buen punto de partida.

El primer ejercicio es Hola Mundo. Hacer aparecer el tradicional saludo "¡Hola Mundo!".

El siguiente ejercicio es Hola Tú. Recojer un nombre, por ejemplo "Antonio" y hacer aparecer el saludo "¡Hola Antonio!".

Luego está Numberguess, un poco más exigente en el manejo de formularios.

Hola Mundo

En Drupal no es obvio cómo hacer el Hola Mundo. Pero luego de un tiempo experimentando con el Drupal básico, uno puede encontrar que es posible definir un bloque y hacer aparecer el mensaje allí.

Pero eso es en un bloque, ¿y si quisiera que fuera en una página, con un url propio?

Para ese caso, se define un módulo. Eso ya es entrar en el terreno del Drupal intermedio. Hay que aprender el protocolo para definir módulos. Y, principalmente, lo que son los hooks.

El código a continuación juega tambien con los hooks de permiso, administración y bloques, por eso tiene más funciones que las necesarias para mostrar simplemente el mensaje.

helloworld.info
; $Id$
name = HelloWorld
description = Say Hello World!
core = 6.x
package = Hello

helloworld.module
<?php
// $Id$

/**
 * Implementation of hook_help
 */
function helloworld_help($path, $arg) {
  $output = '';
  switch ($path) {
    case 'admin/help#helloworld':
      $output = '<p>' . t('Say Hello World!') . '</p>';
      break;
  }
  return $output;
}

/**
 * Implementation of hook_perm()
 */
function helloworld_perm() {
  return array('access helloworld content');
}

/**
 * Implementation of hook_block()
 */
function helloworld_block($op='list', $delta=0, $edit=array()) {
  $block = array();
 
  if ($op=='list') {
   
    $block[0]['info'] = t('HelloWorld');

  }
  elseif ($op=='view') {
   
    $block['subject'] = t('HelloWorld');   
    $block['content'] = _helloworld_content();
   
  }

  return $block;
}

/**
 * Implementation of hook_menu()
 */
function helloworld_menu() {
  $items = array();
 
  $items['helloworld'] = array(
    'title' => 'Hello World',
    'page callback' => 'helloworld_page',
    'access arguments' => array('access helloworld content'),
    'type' => MENU_NORMAL_ITEM,
  );
 
  $items['admin/settings/helloworld'] = array(
    'title' => 'HelloWorld',
    'description' => t('Configuración del módulo HelloWorld'),
    'page callback' => 'drupal_get_form',
    'page arguments' => array('helloworld_admin'),
    'access arguments' => array('access administration pages'),
    'type' => MENU_NORMAL_ITEM,
  );
 
  return $items;
}

/**
 * For page content
 */
function helloworld_page() {
  return _helloworld_content();
}

/**
 * Admin setting form
 */
function helloworld_admin() {
  $form = array();

  $form['helloworld_greeting'] = array(
    '#type' => 'textfield',
    '#title' => t('Saludo'),
    '#default_value' => variable_get('helloworld_greeting', 'Hello World!'),
    '#size' => 60,
    '#maxlength' => 60,
    '#description' => t("Saludo que se mostrará en el bloque."),
    '#required' => TRUE,
  );

  return system_settings_form($form);
}

// PRIVATE

/**
 * Return content
 */
function _helloworld_content() {
  $greeting = variable_get('helloworld_greeting', 'Hello World!');
 
  $content = '<div id="helloworld_block"><div class="greeting">' .
    $greeting . '</div></div>';
   
  return $content;
}

Hola Tú

Luego de hacer el módulo para Hola Mundo, avanzar al caso Hola Tú resultó más difícil de lo que pensaba. Tuve antes que estudiar algo del Form API (FAPI) de Drupal.

helloyou.info
; $Id;
name = Hello You
description = Say Hello to you
core = 6.x
package = Hello

helloyou.module
<?php
// $Id$

/**
 * @file
 * Hello for name
 */

/**
 * Implements hook_menu().
 */
function helloyou_menu() {
  $items = array();
 
  $items['helloyou'] = array(
    'title' => 'Hello You',
    'description' => 'Hello You form',
    'page callback' => 'helloyou_page',
    'access arguments' => array('access content'),
  );
 
  return $items;
}

/**
 * Menu callback
 */
function helloyou_page() {
    $output = t('What is your name?');
    $output .= drupal_get_form('helloyou_nameform');
    return $output;
}

/**
 * Define the form
 */
function helloyou_nameform(&$form_state = NULL) {
  $form['name'] = array(
    '#type' => 'textfield',
    '#title' => t('Name'),
        '#default_value' => isset($form_state['storage']['name'])?$form_state['storage']['name']:'',
    '#description' => t('Please enter your name'),
  );
  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Submit'),
  );
  return $form;
}

/**
 * Validate
 */
function helloyou_nameform_validate($form, &$form_state) {
    if ( trim($form_state['values']['name']) == '' ) {
        drupal_set_message(t('Are you anonymous?'));
        $form_state['storage']['name'] = 'Anonymous';
        $form_state['rebuild'] = TRUE;
    }
    else {
        unset($form_state['storage']['name']);
    }
}

/**
 * Submit
 */
function helloyou_nameform_submit($form, &$form_state) {
    $name = $form_state['values']['name'];
    drupal_set_message(t('Hello %name!', array('%name'=>$name)));
}

Numberguess

El siguiente ejercicio fué hacer Numberguess. Es un juego en donde la computadora genera un número entre 1 y 100 y el jugador trata de adivinarlo. A cada intento la computadora dice 'muy alto' o 'muy abajo', hasta que eventualmente se acierta. La idea es hacerlo en el menor número de intentos.

Resolver Numberguess me ha ayudado a entender varias cosas del FAPI. Ojalá este artículo pueda servir de ayuda a alguien.

numberguess.info
; $Id$
name = Numberguess
description = Numberguess game
core = 6.x
package = Hello

numberguess.module
<?php

/**
 * @file
 * Numberguess game
 */

/**
 * Implementation of hook_menu()
 */
function numberguess_menu() {
    $items = array();
  
    $items['numberguess'] = array(
        'title' => 'Numberguess',
        'description' => 'Numberguess game',
        'page callback' => 'drupal_get_form',
        'page arguments' => array('numberguess_multiform'),
        'type' => MENU_NORMAL_ITEM,
        'access arguments' => array('access content'),
    );
  
    return $items;
}

function numberguess_multiform(&$form_state = NULL) {
    $form = array();
    // if win, not form
    if (isset($form_state['storage']['win'])) {
        return $form;
    }
    // if guess ko
    if (isset($form_state['storage']['guess'])) {
        $n = (int)$form_state['storage']['n'] + 1;
        $x = (int)$form_state['storage']['x'];
        $guess = (int)$form_state['storage']['guess'];
        if ($guess < $x) {
            $description = 'Greater than ' . $guess;
        }
        else {
            $description = 'Lower than ' . $guess;
        }
    }
    // if validation error
    elseif (isset($form_state['post']['guess'])) {
        $n = (int)$form_state['post']['n'];
        $x = (int)$form_state['post']['x'];
    }
    // 1st time
    else {
        $n = 1;
        $x = rand(1, 100);
    }
  
    // the base form
    $form['help'] = array(
        '#value' => 'What integer between 1 and 100 I think?',
    );
    $form['x'] = array(
        '#type' => 'hidden',
    );
    $form['n'] = array(
        '#type' => 'hidden',
    );
    $form['guess'] = array(
        '#type' => 'textfield',
    );
    $form['submit'] = array(
        '#type' => 'submit',
        '#value' => 'submit',
    );
  
    // the variable parts
    $form['n']['#value'] = $n;
    $form['x']['#value'] = $x;
    $form['guess']['#title'] = 'Guess ' . $n;
    $form['guess']['#description'] = $description;
  
    return $form;
}

function numberguess_multiform_validate($form, &$form_state) {
    $guess = $form_state['values']['guess'];
    if (!is_numeric($guess)) {
        form_set_error('guess', t('Must be a number'));
    }
    elseif ((int)$guess != $guess) {
        form_set_error('guess', t('Must be an integer'));
    }
    elseif ($guess < 1 || $guess > 100) {
        form_set_error('guess', t('Must be between 1 and 100'));
    }
}

function numberguess_multiform_submit($form, &$form_state) {
    $x = (int)$form_state['values']['x'];
    $n = (int)$form_state['values']['n'];
    $guess = (int)$form_state['values']['guess'];
    $form_state['storage']['x'] = $x;
    $form_state['storage']['n'] = $n;
    $form_state['storage']['guess'] = $guess;
  
    if ($guess < $x) {
        drupal_set_message(t('Too lower, try again'));
        return;
    }
    elseif ($guess > $x) {
        drupal_set_message(t('Too greater, try again'));
        return;
    }
    else {
        drupal_set_message(t('Congratulations. You win after ' . $n . ' times'));
        $form_state['storage']['win'] = 1;
        return;
    }
}



Extra
Puede leer un poco más sobre el mapeo de acciones en: http://www.scribd.com/doc/35307481/Programando-con-Drupal-Mapeo-de-acciones

Comentarios

Entradas populares de este blog

Debug con Xdebug y Aptana (y Notepad++)

Drupal sí, drupal no

CSS3 para mejorar el breadcrumb de un tema Zen