Después de un tiempo, retomamos la publicación de artículos sobre Desarrollo Web con PHP y MySQL. Este artículo es uno de los mejores que he encontrado, porque si bien trata de algo interesante como es la creación de un blog, busca ser una introducción amena y sencilla a la programación orientada a objetos. Aún así, para la perfecta comprensión del presente tutorial asumimos que el lector tiene conocimientos básicos de PHP, MySQL, XHTML y también, Javascript/jQuery.
Al final de artículo pueden ver una demostración y descargar el código fuente...
Parte 1.- Creando la Base de Datos
Antes de dirigirnos a nuestro cliente MySQL y empezar a crear nuestras tablas, debemos establecer lo que queremos en nuestro blog. Evidentemente, los items que nuestro blog necesita (en cada post) son un título, el post, un autor y la fecha en que fue publicado.
Ahora, podríamos hacer que nuestra tabla guarde toda esta información. Pero, que una tabla maneje toda la información de nuestro blog no sería eficiente. Por ejemplo, podría almacenar el nombre del autor en la misma tabla que la de los posts del blog, pero ¿no les gustaría almacenar también el correo electrónico del autor? Si la respuesta es sí, pues añadir otro campo a nuestra tabla “blog_posts ”sería la solución obvia.
El problema viene cuando en el camino se desea cambiar la dirección de correo de ese autor. Ahora tenemos que cambiarlo para cada post que hemos creado.
Entonces, ¿qué podemos hacer? Lo mejor es crear una tabla llamada “People” y en ella almacenaremos toda la información que necesitemos del autor (como las direcciones de correo electrónico, URL, su nombre y su número de identificación exclusivo). Luego, en nuestra tabla blog posts apuntaremos al número de identificación exclusivo del autor. Este ID es una clave exclusiva y externa a la tabla, pero que nos servirá para establecer una relación entre la tabla blog_post y la tabla People.
Otra cosa que queremos que nuestro blog tenga es una etiqueta para cada post. Una vez más, si queremos que nuestra base de datos sea eficiente, hay que crear una tabla separada para nuestros tags.
Ahora bien, el problema con utilizar la relación uno a uno con la tabla tags, es que algunas veces los post tienen más de un tag; entonces, lo que debemos realizar es una relación uno-a-varios. Para realizar esto, debemos crear una tabla adicional, que llamaremos “blog_post_tags” y que llevará dos claves foráneas, una será el ID de los posts y la otra será la ID de los tags, con la que que la tabla “blog_post” se asociará. De esta manera, podemos asignar un mayor número de etiquetas a un post del blog; pero donde no podremos recuperar la información de la etiqueta específica con una simple consulta MySQL.
Ahora que hemos esbozado lo que queremos en nuestra base de datos, vamos a crearla. En el tutorial usaremos phpMyAdmin ya que es el cliente MySQL más utilizado. Hay algunas convenciones sobre la creación de bases de datos, tablas y nombres de los campos. A mí personalmente me gusta crearlas todas en minúsculas (en inglés) y ponerles guiones bajos en lugar de espacios.
Nota: Si usted no utiliza PHP y MySQL en su sistema o servidor, puede descargar e instalar Apache, PHP y MySQL, utilizando MAMP para Mac y WAMP para PC. Son muy buenos.
Como primer paso vamos a crear nuestra base de datos, la llamaremos “nettuts_blog”.
A continuación, crearemos nuestras tablas, la primera será “blog_posts”.
“blog_posts” tendrá 5 campos "id", "title", "post", "author_id", y "date_posted". "id" será utilizado como clave primaria y con el atributo auto-increment. Con esto generaremos una clave única para id. Cada vez que añadamos un post se irá incrementando el número id de cada post.
Ahora necesitamos determinar el tipo de variable de cada campo. El campo id será int, pequeño y numérico, únicamente puede ser un número y tendrá un límite de 11 dígitos. El campo “title” será varchar, con un máximo de 255 caracteres. El campo “post” será de tipo “text” y no tendrá un límite máximo de caracteres, porque los post suelen ser muy largos. “autor_id” será del mismo tipo que el campo “id”, pero no lo estableceremos como clave primaria ni como auto increment, y finalmente el campo “date_posted” será del tipo date.
Nuestra siguiente tabla será “people”. No la estamos llamando “authors” porque aún no sabemos qué permisos tendrán los usuarios registrados del blog. Algunos dejarán comentarios a los posts y por ello, no pueden ser considerados como autores.
“people” contendrá cinco campos: “id”, "first_name", "last_name", "url", e "email".
“id” será un campo int, primary key y auto increment, de la misma manera en que lo hicimos con el id de “blog_posts”. "first_name", "last_name", "url", y "email" serán todos del tipo varchar con un número máximo de 255 caracteres.
Nuestra siguiente tabla será “tags” y por ahora contendrá únicamente dos campos: “id” y “name”. En futuros tutoriales iremos ampliando esta tabla, haciéndola más compleja, añadiéndole una descripción, pero para este tutorial no será necesario. Como dijimos antes, “id” será establecido como int, primary key y auto increment. “name” será del tipo varchar y tendrá un máximo de 255 caracteres.
Y nuestra última tabla será “blog_post_tags”, y contendrá dos campos: “blog_post_id” y “tag_id”. Ambos serán del tipo int con un máximo de 11 caracteres. Como comprenderán, no estableceremos ninguna clave primaria para esta tabla. Esto se debe a que nunca vamos a recibir datos a esta tabla a menos que nos la pida un post específico o todos los post de una tag ID específica.
Parte 2.- Creando nuestros objetos en PHP
Antes de empezar a ver nuestro código PHP necesitamos crear nuestros archivos y carpetas, para este tutorial tendremos nuestro index.php en el directorio raíz y luego incluiremos carpetas donde almacenar nuestras hojas de estilo CSS, nuestros archivos JavaScript, el fichero includes.php que hará referencia a nuestros objetos y a la conexión MySQL, y blogspot.php que contendrá nuestro objeto BlogPost.
Ahora que tenemos lista nuestra base de datos, necesitamos crear los objetos en PHP que recuperen la data para nosotros. Objetos en programación son la manera de agrupar atributos (o variables) y métodos, todos relacionados a una misma cosa. Los objetos nos ayudan a organizar nuestros programas de una manera más eficiente Antes de dar el salto a los objetos para nuestro blog, permítanme solamente crear un simple objeto, a fin de ilustrar lo que son en términos de la “vida real”.
Nuestro objeto será llamado “Bicicleta”; ahora bien, son dos tipos de cosas las que cada objeto tiene, propiedades y métodos. Las Propiedades definen el objeto y los métodos son lo que el objeto hace. Por ejemplo, nuestro objeto Bicicleta tendrá propiedades como el “tamaño”, “número de llantas”, etc. Para los métodos podríamos tener algo así como el “Pedal”.
Regresando a nuestro blog, sólo necesitamos un objeto , al cual llamaremos “BlogPost”. BlogPost tendrá seis propiedades: id, el título, post, el autor, las etiquetas y la fecha de publicación. Por lo que podemos hacerlo en PHP.
Para definir un objeto en PHP, lo definimos como una “clase”. Una clase es la estructura de cada objeto, o como la wikipedia lo describe, “En la programación orientada a objetos, una clase es un lenguaje de programación que se utiliza como un plan detallado para crear un objeto concreto. Este plan detallado incluye atributos y métodos que todos los objetos creados comparten (http://en.wikipedia.org/wiki/Concrete_class). Ahora pasemos a abrir nuestra página blogspost.php y definir nuestro primer objeto.
Nota: En cada sección del tutorial, iré abriendo y cerrando las etiquetas PHP, para que puedan incluirlas directamente al inicio o final de cada documento.
class BlogPost
{
}
En nuestra clase necesitamos definer nuestras propiedades. Para hacer esto, necesitamos crear variables pero como públicas (“public”). Sólo una pequeña anotación, si estamos utilizando PHP4 necesitaremos usar “var” en vez de “public”.
<?php
class BlogPost
{
public $id;
public $title;
public $post;
public $author;
public $tags;
public $datePosted;
}
?>
Ahora que tenemos todas nuestras propiedades definidas, vamos a definir nuestro primer método. Los métodos también se describen como funciones, pero la principal diferencia es que un método es una función dentro de un objeto. Por lo tanto, todos los métodos son también funciones, pero no todas las funciones son métodos.
Nuestro primer método será lo que se llama un constructor (“constructor”), este método es automáticamente llamado cada vez que realicemos una instancia de nuestro objeto BlogPost.
El uso común de un constructor es que con él podemos crear un nuevo objeto y definir sus propiedades rápidamente.
Entonces, lo que queremos hacer es crear una nueva función llamada __construct() y le pasaremos 5 valores: id, title, post, author id y date posted. A cada nombre de variable nosotros le colocaremos en su inicio la palabra “in”, para poder entender en nuestras funciones cuales variables son incluidas.
<?php
class BlogPost
{
public $id;
public $title;
public $post;
public $author;
public $tags;
public $datePosted;
function __construct($inId, $inTitle, $inPost, $inAuthorId,$inDatePosted)
{
}
}
?>
El problema aquí es que, con este código actual, cada vez que creemos una nueva instancia de BlogPost necesitaremos suministrar todas esas variables. Pero ¿qué pasaría si lo que queremos es hacer una nueva entrada en el blog y no hemos definido todavía esas variables?
Para solucionar esto, tenemos que "sobrecargar" (overload) los argumentos en favor de nuestra función de manera que si queremos llamar a la función y no suministrar uno de los argumentos, se ajuste automáticamente al valor predeterminado.
<?php
function __construct($inId=null, $inTitle=null, $inPost=null,$inPostFull=null, $inAuthorId=null, $inDatePosted=null)
{
}
?>
Como pueden ver, todo lo que hacemos para cumplir nuestra tarea es predefinir cada argumento con el valor "null". Ahora dentro de nuestro constructor, tenemos que establecer cada una de nuestras variables transmitiendo sus valores. Para hacer esto, necesitamos almacenarlo en nuestro objeto. Esto podemos hacerlo utilizando la palabra clave “this”. A diferencia de muchos lenguajes de programación para acceder a una propiedad en PHP usaremos "->", mientras que en la mayoría de los lenguajes (JavaScript, ASP.NET) se utiliza ".".
<?php
function __construct($inId=null, $inTitle=null, $inPost=null,$inPostFull=null, $inAuthorId=null, $inDatePosted=null)
{
$this->id = $inId;
$this->title = $inTitle;
$this->post = $inPost;
}
?>
Esto funciona para id, title y post. Pero ¿qué pasa con los demás? Para date, vamos a necesitar reformatear los datos que obtuvimos de MySQL, a fin de hacerlo más legible. Eso se realiza fácilmente. Sólo necesitamos realizar un explode (también conocido como división en otros lenguajes de programación) y luego volver a unirlo. MySQL nos proporciona la fecha en este formato aaaa-mm-dd, por lo que si realizamos un explode utilizando a "-" como separador obtendremos tres valores. El primero será el año, el siguiente el mes, y el último será el día. Ahora todo lo que hacemos es agruparlo en el formato que queramos. Me quedo con mm/dd/yyyy.
<?php
$splitDate = explode("-", $inDatePosted);
$this->datePosted = $splitDate[1] . "/" . $splitDate[2] . "/" .$splitDate[0];
?>
Para conocer al autor, todo lo que tenemos que hacer es preguntarle a nuestra base de datos sobre la persona con el número de identificación de nuestro autor. Podemos hacer esto con una consulta básica MySQL.
<?php
$query = mysql_query("SELECT first_name, last_name FROM People WHERE id = " . $inAuthorId);
$row = mysql_fetch_assoc($query);
$this->author = $row["first_name"] . " " . $row["last_name"];
?>
Left Join
Ahora, las etiquetas serán ligeramente más difíciles. Vamos a necesitar dialogar con la base de datos, por lo que necesitamos crear una consulta MySQL. No hay por qué preocuparse por la conexión a la base de datos ahora mismo, ya que la definiremos fuera de esta clase.
Por ahora todo lo que tenemos es el ID de los posts del blog; el cual lo podemos comparar con los tags del post en nuestra tabla blog_post_tags; así obtendríamos la ID de la etiqueta; sin embargo, para obtener el nombre de la etiqueta tendríamos que hacer otra consulta. Esto no es bueno; si queremos ser eficientes, tenemos que hacerlo todo en tan sólo una consulta!
Para ello vamos a hacer lo que se llama un Left Join, esto significa que vamos a seleccionar los datos de otra tabla, pero sólo cuando coincida con los datos de la "izquierda" o nuestros otros datos seleccionados. Así que primero vamos a obtener únicamente todas las IDs de las etiquetas que se asocian con nuestro ID del post en la tabla blog_post_tags.
<?php
$query = mysql_query("SELECT * FROM blog_post_tags WHERE blog_post_tags.blog_post_id = " . $inId);
?>
Ahora añadiremos a nuestro left join y haremos una consulta que únicamente nos retorne los datos de la tabla tags:
<?php
$query = mysql_query("SELECT tags.* FROM blog_post_tags LEFT JOIN (tags) ON (blog_post_tags.tag_id = tags.id) WHERE blog_post_tags.blog_post_id = " . $inId);
?>
Así pues, la consulta seleccionará todo lo que contengan las tablas tags y blog_posts_tags, donde blog_post_tags.blog_post_id será igual al valor provisto por nosotros en la consulta y estará acompañado de la información de cada tag en la misma fila.
Ahora lo que vamos a hacer es procesar los datos en PHP con un simple bucle while. Vamos a crear dos matrices (arrays) que tengan nuestros datos: Una para el nombre de la etiqueta y la otra para la id de la etiqueta. También haremos un string con todos nuestros tags.
En primer lugar necesitamos establecer nuestro “No Tags”, por si no retorna ningún dato de nuestra consulta MySQL. Caso contrario, devolverá los nombres de la etiqueta.
<?php
$postTags = "No Tags";
$tagArray = array();
$tagIDArray = array();
while($row = mysql_fetch_assoc($query)
{
array_push($tagArray, $row["name"]);
array_push($tagIDArray, $row["id"]);
}
?>
Ahora vamos a verificar si la matriz tiene una longitud mayor a cero (no queremos procesar todo nuestro código si no vamos a obtener algún resultado). Luego, para unir cada etiqueta en nuestro array de nombres de etiquetas, vamos a concatenar un string de las etiquetas. Vamos a utilizar la sencilla declaración if else.
<?php
if (sizeof($tagArray) > 0)
{
foreach ($tagArray as $tag)
{
if ($postTags == "No Tags")
{
$postTags = $tag;
}
else
{
$postTags = $postTags . ", " . $tag;
}
}
}
$this->tags = $postTags;
?>
Como habrás notado, no hemos utilizado la matriz con el tag ID. Vamos a dejar esto por ahora y volveremos a ello más tarde. Sólo queremos poner nuestro blog en marcha.
El último paso de nuestra clase es comprobar que las variables tengan un valor; de lo contrario habría un error (se modificaría la propiedad actual del objeto a nada). Aquí esta toda la clase BlogPost con el añadido último:
<?php
class BlogPost
{
public $id;
public $title;
public $post;
public $author;
public $tags;
public $datePosted;
function __construct($inId=null, $inTitle=null, $inPost=null,$inPostFull=null, $inAuthorId=null, $inDatePosted=null)
{
if (!empty($inId))
{
$this->id = $inId;
}
if (!empty($inTitle))
{
$this->title = $inTitle;
}
if (!empty($inPost))
{
$this->post = $inPost;
}
if (!empty($inDatePosted))
{
$splitDate = explode("-", $inDatePosted);
$this->datePosted = $splitDate[1] . "/" . $splitDate[2] . "/" . $splitDate[0];
}
if (!empty($inAuthorId))
{
$query = mysql_query("SELECT first_name, last_name FROM people WHERE id = " . $inAuthorId);
$row = mysql_fetch_assoc($query);
$this->author = $row["first_name"] . " " .$row["last_name"];
}
$postTags = "No Tags";
if (!empty($inId))
{
$query = mysql_query("SELECT tags.* FROM blog_post_tags LEFT JOIN (tags) ON (blog_post_tags.tag_id = tags.id) WHERE blog_post_tags.blog_post_id = " . $inId);
$tagArray = array();
$tagIDArray = array();
while($row = mysql_fetch_assoc($query))
{
array_push($tagArray, $row["name"]);
array_push($tagIDArray, $row["id"]);
}
if (sizeof($tagArray) > 0)
{
foreach ($tagArray as $tag)
{
if ($postTags == "No Tags")
{
$postTags = $tag;
}
else
{
$postTags = $postTags . ", " . $tag;
}
}
}
}
$this->tags = $postTags;
}
}
?>
Ahora que nuestro clase esta completa, hemos acabado con lo más duro! Ahora todo lo que tenemos que hacer es establecer la conexión con la base de datos y mostrar el HTML de nuestros posts!
Parte 3.- Obtención de los datos de MySQL y visualización con PHP
Antes de hacer algo, tenemos que crear nuestro archivo includes.php para hacer una referencia a nuestro objeto BlogPost y conectarse a nuestra base de datos MySQL. En primer lugar, incluiremos nuestro objeto con una simple declaración include:
<?php
include 'blogpost.php';
?>
Ahora añadiremos nuestra conexión a la base de datos:
<?php
$connection = mysql_connect("localhost", "username","password") or die ("<p class='error'>Sorry, we were unable to connect to the database server.</p>");
$database = "nettuts_blog";
mysql_select_db($database, $connection) or die ("<p class='error'>Sorry, we were unable to connect to the database.</p>");
?>
Como paso siguiente, necesitamos recuperar nuestros posts de la base de datos. Para esto, vamos a crear una función con dos argumentos. Ambas tendrán valores por defecto, por lo que podremos llamar a la función con 0, 1 o 2 argumentos.
<?php
function GetBlogPosts($inId=null, $inTagId=null)
{
}
?>
Dentro de nuestra función, necesitamos comprobar los argumentos que pasaremos y crear nuestra consulta MySQL acorde a ellos.
<?php
function GetBlogPosts($inId=null, $inTagId =null)
{
if (!empty($inId))
{
}
else if (!empty($inTagId))
{
}
else
{
}
}
?>
Así pues, lo que estamos haciendo aquí es preguntarnos si cada uno de los argumentos no están vacíos. Ahora vamos a escribir una consulta en función de las variables que tenemos. Si lo que tenemos es el ID de un post, obtendremos la información de ese post únicamente; si lo que hemos pasado a la función es un inTagId lo que obtendremos serán todos los post que tienen ese tag; y en caso contrario, por defecto obtendremos todos los post guardados en nuestra base de datos.
<?php
if (!empty($inId))
{
$query = mysql_query("SELECT * FROM blog_posts WHERE id = ". $inId . " ORDER BY id DESC");
}
else if (!empty($inTagId))
{
$query = mysql_query("SELECT blog_posts.* FROM blog_post_tags LEFT JOIN (blog_posts) ON (blog_post_tags.postID = blog_posts.id) WHERE blog_post_tags.tagID =" . $tagID . " ORDER BY blog_posts.id DESC");
}
else
{
$query = mysql_query("SELECT * FROM blog_posts ORDER BY id DESC");
}
?>
El paso siguiente es procesar los datos devueltos por cada consulta, crear los objetos y añadirlos a un array de retorno.
<?php
$postArray = array();
while ($row = mysql_fetch_assoc($query))
{
$myPost = new BlogPost($row["id"], $row['title'],$row['post'], $row['postfull'], $row['firstname'] . " " .$row['lastname'], $row['dateposted']);
array_push($postArray, $myPost);
}
return $postArray;
?>
Aquí está el código del fichero includes.php completo:
<?php
include 'blogpost.php';
$connection = mysql_connect('localhost', 'username','password') or die ("<p class='error'>Sorry, we were unable to connect to the database server.</p>");
$database = "nettuts_blog";
mysql_select_db($database, $connection) or die ("<p class='error'>Sorry, we were unable to connect to the database.</p>");
function GetBlogPosts($inId=null, $inTagId =null)
{
if (!empty($inId))
{
$query = mysql_query("SELECT * FROM blog_posts WHERE id = " . $inId . " ORDER BY id DESC");
}
else if (!empty($inTagId))
{
$query = mysql_query("SELECT blog_posts.* FROM blog_post_tags LEFT JOIN (blog_posts) ON (blog_post_tags.postID = blog_posts.id) WHERE blog_post_tags.tagID =" . $tagID . " ORDER BY blog_posts.id DESC");
}
else
{
$query = mysql_query("SELECT * FROM blog_posts ORDER BY id DESC");
}
$postArray = array();
while ($row = mysql_fetch_assoc($query))
{
$myPost = new BlogPost($row["id"], $row['title'],$row['post'], $row['postfull'], $row["author_id"],$row['dateposted']);
array_push($postArray, $myPost);
}
return $postArray;
}
?>
Ahora nos podemos dirigir a mostrar nuestros datos. Déjenme abrir nuestro fichero index.php e iniciar una página HTML básica. Dentro de nuestro body crearemos una div “main” que contendrá nuestro blog. Colocaremos el título de nuestro post y luego un segundo div dentro de main que se llame "blogPosts".
<div id="main">
<h1>My Simple Blog</h1>
<div id="blogPosts">
</div>
</div>
Dentro de nuestro div blogPosts, pondremos un poco de PHP que muestre nuestros posts. Primero incluiremos nuestro fichero includes.php y luego llamaremos a la función GetBlogPosts sin pasarle ningún argumento, así obtendremos todos los posts de nuestro blog dentro de un array llamado blogPosts.
<?php
include 'includes/includes.php';
$blogPosts = GetBlogPosts();
?>
Ahora, usaremos un bucle foreach para mostrar nuestros posts. Lo que hace un bucle foreach es tomar un array y ejecutar un trozo de código por cada ítem que el array contenga. Así podemos ahorrar código con una tarea repetitiva.
<?php
foreach ($blogPosts as $post)
{
}
?>
Dentro del bucle, usaremos la variable $post como el array actual, y como $blogPost es un array del objeto BlogPost, podemos simplemente utilizar "->" para acceder a cada propiedad que queramos. Déjenme empezar por escoger el título de cada post y añadirle la etiqueta , como ejemplo.
<?php
foreach ($blogPosts as $post)
{
echo $post->title . "<br/>";
}
?>
Si vamos a nuestra base de datos e insertamos algunos datos falsos, y luego abrimos nuestro fichero index.php en el navegador, obtendremos algo como esto:
Vamos a estructurar nuestros posts en HTML. Cada post estará dentro de un div con una clase "post". Luego, tendremos el título dentro de una etiqueta H1 y el post dentro de etiquetas .
<?php
foreach ($blogPosts as $post)
{
echo "<div class='post'>";
echo "<h2>" . $post->title . "</h2>";
echo "<p>" . $post->post . "</p>";
echo "</div>";
}
?>
Luego, vamos a añadirle al final de cada post el autor del post, la fecha de publicación y los tags del post. Toda esta información la pondremos dentro de una etiqueta span con la clase “footer”.
<?php
foreach ($blogPosts as $post)
{
echo "<div class='post'>";
echo "<h1>" . $post->title . "</h1>";
echo "<p>" . $post->post . "</h1>";
echo "<span class='footer'>Posted By: " . $post->author ." Posted On: " . $post->datePosted . " Tags: " . $post->tags ."</span>";
echo "</div>";
}
?>
Ahora, veamos nuevamente nuestro fichero index.php en el navegador:
Todo funciona muy bien! A continuación, déjenme añadirle algo de estilo.
No hay comentarios:
Publicar un comentario