Creando un sistema de notas – Parte 1

En este tutorial aprenderemos a crear un sistema de notas utilizando tecnologías web. Para empezar, veremos la planificación del proyecto y la creación de todos los archivos por parte del servidor (PHP y MySQL).

Esta entrada es la número 1 en una serie de entradas de 2 partes. A continuación puedes ver las demás entradas:

Para llevar a cabo este tutorial, es necesario un conocimiento avanzado de PHP (Programación Orientada a Objetos, Métodos Estáticos y la librería MySQLi), asumiendo que se tenga conocimiento de las demás tecnologías empleadas.

Planificación

Comencemos organizando nuestras ideas. Primero de todo, vamos a crear un sistema de notas, las cuales serán almacenadas en una base de datos. De aquí sacamos dos conclusiones:

  1. Necesitaremos un lenguaje del lado del servidor para acceder a nuestras notas.
  2. Para no estar recargando la página continuamente y simular el acceso directo a la base de datos, implementaremos AJAX mediante la librería jQuery.

En esta primera parte del tutorial, nos dedicaremos exclusivamente al PHP y MySQL.

Organización de ficheros

Necesitaremos:

  • Tres archivos PHP: la configuración, la librería y el archivo que recibirá las peticiones AJAX.
  • Un archivo HTML.
  • Dos archivos CSS: nuestros estilos y un reset.
  • Cuatro archivos JavaScript: las librerías jQuery y jQuery UI (de la cual utilizaremos el componente de sortable), el plugin jQuery TMPL para almacenar la maquetación que utilizaremos posteriormente en la misma página y nuestro script.js que pondrá en funcionamiento todo lo anterior.

Nuestros ficheros quedarán pues organizados de la siguiente manera:

css/
	/reset.css
	/style.css
js/
	/jquery.js
	/jquery-ui.js
	/jquery.tmpl.js
	/script.js
img/
ajax.php
config.php
core.php
index.html

La teoría

Los usuarios llamarán al archivo index.html, y este, cargará script.js que realizará una petición al archivo ajax.php, el cual obtendrá las notas de la base de datos y las devolvera a modo de cadena JSON.

De igual manera, cuando añadamos, editemos, eliminemos… una nota, se realizará una petición al archivo ajax.php, que ejecutará la acción y devolverá el resultado.

La acción se especificará mediante GET, mientras que los datos irán como POST.

Preparando la base de datos

En nuestro servidor, entraremos dentro de la base de datos que deseemos y ejecutaremos el siguiente código:

CREATE TABLE `notes` (
  `id` int(8) NOT NULL AUTO_INCREMENT,
  `position` int(8) NOT NULL,
  `text` text COLLATE utf8_unicode_ci NOT NULL,
  `date` int(10) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=90 ;

Esto creará una nueva tabla llamada notes.

CampoExplicación
idContiene el número de indentificación de la nota. Se incrementará automáticamente.
positionContiene la posición actual de la nota.
textContiene el texto de la nota.
dateFecha de creación de la nota en formato timestamp.

Creando nuestros scripts

config.php

Comenzaremos nuestro sistema definiendo algunas variables de configuración, entre ellas los datos de acceso a la base de datos y el formato de las fechas.

<?php
// Errores.
error_reporting( 0 );

// Base de datos.
$hostname		=	'';
$username		=	'';
$password		=	'';
$database		=	'';

// Formato de las fechas.
$date_format	=	'E\l j/m/y \a \l\a\s h:i A';
?>

core.php

En este archivo incluiremos todas las funciones que utilizaremos posteriormente en ajax.php. Empezaremos creando un objeto que contendrá las funciones del manejo de notas.

final class Notes
{
	// Prevenimos la instanciación.
	private function __construct() {}

	// Funciones
}

En su interior añadiremos las funciones principales del manejo de notas. $id correspondrá al identificador de la nota, $text a su contenido, $date a la fecha y $positions al array que jQuery UI nos devuelve al ordenar una nota.

/**
 * Añade una nueva nota.
 */
public static function add( $text )
{
	global $mysqli;

	// Obtenemos la posición de la última nota.
	if ( $query = $mysqli->query( 'SELECT MAX(position) FROM notes' ) )
	{
		$row = $query->fetch_row();
		// La posición de la nueva nota.
		$position = $row[0] + 1;

		// Insertamos la nota nueva.
		if ( $stmt = $mysqli->prepare( 'INSERT INTO notes (text, date, position) VALUES (?, ?, ?)' ) )
		{
			$date = time();
			$stmt->bind_param( 'sii', $text, $date, $position );
			$stmt->execute();

			echo self::serialized_return( $mysqli->insert_id, $text, $date );
		}
		else
		{
			show_error( 'Error al intentar añadir la nota.' );
		}
	}
	else
	{
		show_error( 'Error al intentar añadir la nota.' );
	}
}

/**
 * Ordena las notas actuales.
 */
public static function rearrange( $positions )
{
	global $mysqli;

	// Creamos la consulta, WHEN id THEN posición+1
	foreach ( $positions as $position => $id )
		$sql .= ' WHEN ' . (int)$id . ' THEN ' . ( (int)$position + 1 );

	// La ejecutamos.
	if ( $stmt = $mysqli->prepare( 'UPDATE notes SET position = CASE id ' . $sql . ' END' ) )
	{
		$stmt->execute();
		show_success( 'Las notas fueron ordenadas correctamente.' );
	}
	else
	{
		show_error( 'Error al intentar ordenar las notas.' );
	}	
}

/**
 * Elimina una nota.
 */
public static function delete( $id )
{
	global $mysqli;

	// Eliminamos la nota.
	if ( $stmt = $mysqli->prepare( 'DELETE FROM notes WHERE id = ?' ) )
	{
		$stmt->bind_param( 'i', $id );
		$stmt->execute();
		show_success( 'La nota se eliminó correctamente.' );
	}
	else
	{
		show_error( 'Error la intentar eliminar la nota.' );
	}	
}

/**
 * Edita una nota.
 */
public static function edit( $id, $text, $date )
{
	global $mysqli;

	// Editamos la nota.
	if ( $stmt = $mysqli->prepare( 'UPDATE notes SET text = ?, date = ? WHERE id = ?' ) )
	{
		$stmt->bind_param( 'sii', $text, $date, $id );
		$stmt->execute();
		show_success( 'La nota fue editada correctamente.' );
	}
	else
	{
		show_error( 'Error la intentar editar la nota.' );
	}	
}

Ahora añadiremos las dos funciones secundarias, que devolveran los datos de las notas como un array o como una cadena JSON.

/**
 * Devuelve los datos de la nota como un array asociativo.
 */
public static function unserialized_return( $id, $text, $date )
{
	return array(
		'id'	=>	$id,
		'text'	=>	$text,
		'date'	=>	date( $GLOBALS['date_format'], $date )
	);
}

/**
 * Devuelve los datos de una nota como JSON.
 */
public static function serialized_return( $id, $text, $date )
{
	return json_encode( array( self::unserialized_return( $id, $text, $date ) ) );
}

Para finalizar con nuestro archivo, añadiremos las funciones show_error() y show_success(), las cuales nos ayudarán a la hora de manejar errores o mensajes de éxito.

/**
 * Imprime un error en pantalla.
 */
function show_error( $message, $code = 500 )
{
	$errors = array(
		500	=> 'Internal Server Error'
	);

	header( "HTTP/1.1 {$code} {$errors[$code]}" );
	exit( $message );
}

/**
 * Imprime un mensaje de suceso.
 */
function show_success( $message )
{
	echo '{"success":"' . $message . '"}';
}

ajax.php

Este archivo se encargará de recojer las peticiones de nuestro sistema. La acción a realizar se recojerá desde la variable $_GET['action'] y los datos de las notas mediante POST.

<?php
// Comprobar si la página se cargo con AJAX.
if ( strtolower( $_SERVER['HTTP_X_REQUESTED_WITH'] ) != 'xmlhttprequest' )
{
	die( 'No acceda a esta p&aacute;gina directamente desde su navegador.' );
}

// Tipo de archivo: JSON.
header( 'Content-type: application/json' );

// Incluimos otros archivos.
require_once 'config.php';
require_once 'core.php';

// Realizamos la conexión con la base de datos.
$mysqli = new mysqli( $hostname, $username, $password, $database );
if ( $mysqli->connect_errno )
{
	show_error( 'Error de conexión.' );
}
// Codificación de caracteres.
$mysqli->set_charset( 'utf8' );

// Comparamos la variable action en la URL con las diferentes acciones.
switch ( $_GET['action'] )
{
	// Obtener todas las notas.
	case 'getAll' :
		if ( $query = $mysqli->query( 'SELECT * FROM notes ORDER BY position ASC' ) )
		{
			$arr = array();
			while ( $row = $query->fetch_assoc() )
			{
				$arr[] = Notes::unserialized_return( $row['id'], $row['text'], $row['date'] );
			}
			echo json_encode( $arr );
		}
		break;

	// Reorganizar.
	case 'rearrange' :
		Notes::rearrange( $_POST['positions'] );
		break;

	// Añadir.
	case 'add' :
		Notes::add( '¡Aquí está su nueva nota! Puede eliminarla o editarla utilizando los botones a la izquierda.' );
		break;

	// Eliminar.
	case 'delete' :
		Notes::delete( $_POST['id'] );
		break;

	// Editar.
	case 'edit' :
		Notes::edit( $_POST['id'], $_POST['text'], $_POST['date'] );
		break;

	// No se especificó ninguna de las acciones anteriores.
	default :
		show_error( 'La acción especificada no es correcta.' );
		break;
}
?>

Continuará

Y con estos últimos fragmentos de código terminamos la primera parte del tutorial. La página está lista para recibir las peticiones. En la parte dos veremos todo lo relativo al lado del cliente. ¡Nos vemos!

comments powered by Disqus