domingo, 26 de febrero de 2012

Creación del mensil

En esta oportunidad voy a empezar a crear el código para que se muestre el mensil correspondiente a la fecha seleccionada.

Pero antes, algunas correcciones previas

En la línea 14 de la versión 0.1 de index.php, dice:
echo "<h3>".traducir(date('l d \d\e F \d\e Y',$_GET['fechaactual']))."</h3>";
Cambiando date('l d \d\e F...') por date('l j \d\e F...') se consigue que los números de día menores a 10 se muestren sin el cero de la izquierda.
También agregué la secuencia de caracteres de nueva línea (\n) en lugares específicos de las cadenas de código html, con el solo fin de que cuando se vea el código de la página desde el navegador, éste se muestre más prolijo y no todo de corrido.
Finalmente, borré las líneas 13 y 17 de la versión 0.1 de index.php, que lo que hacían era, respectivamente, abrir y cerrar una caja div para centrar la fecha del día seleccionado. Voy a dejar lo relacionado con la presentación para hacerlo más adelante, con hojas de estilo (CSS) externas.

El mensil

Ahora sí, vamos con el código para crear el mensil que incluye al día seleccionado.
El siguiente es el código que escribí luego de la línea 16 de la versión 0.1 de index.php:

echo "\n<table>\n";
echo "<tr><th colspan='7'>".ucfirst(traducir(date('F \d\e Y',$_GET['fechaactual'])))."</th></tr>\n";
echo "<tr><th>Do</th><th>Lu</th><th>Ma</th><th>Mi</th><th>Ju</th><th>Vi</th><th>Sa</th></tr>\n";
echo "<tr>";
$primerDiaMes=mktime(0,0,0,date("m",$_GET['fechaactual']), '1',date("Y",$_GET['fechaactual']));
for  ($i=1;$i<=date('w',$primerDiaMes);$i++)
 { echo "<td></td>"; }
$restoPrimeraSemana=8-$i;
for ($a=1;$a<=$restoPrimeraSemana;$a++)
   {echo "<td>".$a."</td>";}
echo "</tr>\n<tr>";
$diasDelMes=date('t',$primerDiaMes);
$i=($i*-1) + 9;
$y=1;
for ($i;$i<=$diasDelMes;$i++)
 { echo "<td>".$i."</td>";
  if (($y%7=="0") && ($i==$diasDelMes)) { }
  elseif (($y%7=="0") && ($i<$diasDelMes)) { echo "</tr>\n<tr>"; }
  $y++; 
  }
$y--;
$i--;
if (($y%7!="0") && ($i==$diasDelMes)) {
  $ultimoDiaMes=mktime(0,0,0,date("m",$_GET['fechaactual']), $diasDelMes,date("Y",$_GET['fechaactual']));
  $restoUltimaSemana= (date('w',$ultimoDiaMes) * -1) + 6;
  for  ($i=1;$i<=$restoUltimaSemana;$i++)
    { echo "<td></td>"; }
  }
echo "</tr>\n";
echo "</table>\n";


Aquí va la explicación del código:
  • La línea 1 abre la tabla. La etiqueta <table> queda rodeada por dos secuencias de caracteres de nueva línea (\n). De ahora en más, se verá varias veces, en las ocurrencias de código html, esta secuencia, con el solo fin de obtener un código más prolijo.
  • Con el código de la línea 2:
    • Se abre la primera fila (<tr>).
    • Se abre una celda de cabecera que ocupa 7 columnas de ancho (<th colspan='7'>).
    • Con la función date se obtiene el mes y el año ('F \d\e Y') de la fecha que se está consultando ($GET_['fechaactual']).
      Con la función traducir (anteriormente creada e incluida desde funciones.php) se traduce al español el nombre del mes.
      Con la función ucfirst se cambia la primera letra del mes a mayúsculas.
      Finalmente, se cierra la celda y la fila.
  • En la línea 3 se imprime el código html para crear la segunda fila, son sus 7 celdas de cabecera, con la primeras letras de cada día de la semana en cada una.
Al hacer una tabla con una semana por fila y siendo el domingo el primer día de la semana, un mes puede constar de 4 filas (solo en el caso de un mes de febrero no bisiesto cuyo primer día sea domingo), 5 filas (en una mayoría absoluta de los casos o de 6 filas).
  • La línea 4 abre la tercera fila (la primera fila -semana- del mes propiamente dicho).
  • En la línea 5 se define la variable $primerDiaMes, conteniendo el tiempo unix (mktime) del primer día ('1') del mes (date("m",$_GET['fechaactual'])) y año (date("Y",$_GET['fechaactual'])) seleccionados.
  • Las líneas 6 y 7 son un bucle for, que define un contador $i con valor "1", al que le va agregando uno ($i++) mientras $i sea menor o igual a date('w',$primerDiaMes) (o sea, el día de la semana correspondiente al primer día del mes, representado por "0" para el domingo, "1" para el lunes y así hasta "6" para el sábado). Por cada vez que la condición sea válida en el bucle, se imprime una celda vacía (<td></td>).
    O sea, si el primer día del mes es un domingo, el valor de date('w',$primerDiaMes) será "0" y como el contador $i comienza en "1", no se cumle la condición $i<=date('w',$primerDiaMes) y, por lo tanto, no se genera ninguna celda vacía.
    Por otra parte, si, por ejemplo, el primer día del mes es un jueves, el valor de date('w',$primerDiaMes) será "4" y como el contador $i comienza en "1", la condición $i<=date('w',$primerDiaMes) se dará 4 veces y, por ende, generará 4 celdas vacías (correspondientes al domingo, lunes, martes y miércoles de la primera semana).
  • En la línea 8 se define la variable $restoPrimeraSemana, cuyo conteniendo es el resultado de la resta 8-$i. El valor de esta variable se corresponderá con la cantidad de días en la primera semana del mes. Siguiendo con los ejemplos del punto anterior, si el primer día del mes es domingo, el valor de $i seguirá siendo "1", tal cual se definió en un principio, ya que la condición del bucle de la linea 6 no se cumplió y no le modificó el valor a $i. Entonces, el valor de $restoPrimeraSemana será "7" (el resultado de 8-1); esto es, la primera semana del mes tiene 7 días.
    Ahora, si el mes empieza en jueves, el valor de $i será "5" (ya que por cada una de las 4 veces que se cumplió la condición establecida en la línea 6, se le sumó "1" al valor original de $i) y el valor de $restoPrimeraSemana será "3" (el resultado de 8-5); o sea los tres días (jueves, viernes y sábado) que tendrá la primera semana del mes dado.
  • En las líneas 9 y 10 se define un nuevo bucle for, que define un contador $a con valor "1", al que le va agregando uno ($a++), mientras $a sea menor o igual a $restoPrimeraSemana (o sea, la cantidad de días de la primera semana del mes). Por cada vez que la condición sea válida en el bucle, se imprime una celda con el número correspondiente ("<td>".$a."</td>").
  • En la línea 11 se cierra la tercera fila (la de la primera semana, que se había abierto en la línea 4) con </td> y se abre la cuarte fila (la de la segunda semana) con <td>. Separados ambos por una secuencia de caracteres de nueva línea (\n), por el mismo motivo ya expuesto en la explilcación de la línea 1.
  • En la línea 12 se define la variable $diasDelMes que, mediante el uso de la función date con el carácter de formato 't', guarda el número de días del mes dado (en este caso el mes al que pertenece el tiempo unix almacenado en $primerDiaMes).
  • A continuación se necesita una variable que almacene el número del día del domingo con el que comienza la segunda semana del mes. Para ello, se utiliza el  valor previo de $i, que era:
    • "1" si el primer día del mes es domingo (en cuyo caso, el domingo siguiente, o sea, el primer día de la segunda semana, sería el "8").
    • "2" si el primer día del mes es lunes (entonces, el domingo siguiente es "7").
    • "3" si el primer día del mes es martes (entonces, el domingo siguiente es "6").
    • "4" si el primer día del mes es miércoles (entonces, el domingo siguiente es "5").
    • "5" si el primer día del mes es jueves (entonces, el domingo siguiente es "4").
    • "6" si el primer día del mes es viernes (entonces, el domingo siguiente es "3").
    • "7" si el primer día del mes es sábado (entonces el domingo siguiente es "2").
    Entonces, en la línea 13 se redefine el valor de $i, como el resultado de multiplicar el valor previo de $i por "-1" y sumarle "9" y obtener así el número del domingo con el que comienza la segunda semana.
  • En la línea 14 se define una variable $y con valor "1", para usar como una especie de contador en la línea 17.
  • Entre las líneas 15 y 20 se define un nuevo bucle for. En este caso, para el valor de $i definido en la línea 13, y mientras ese valor sea menor o igual a la cantidad de días del mes definidos en la línea 12 ($i<=$diasDelMes), le agrega "1" a $i.
    Lo primero que hace cuando se cumple la condición establecida es imprimir una celda con el valor de $i (línea 16).
    Luego, en la línea 17 verifica, con un if, si el valor de $y (el contador definido en la línea 14 y al que se le agrega "1" en la línea 19) es divisible entre 7 y si el valor de $i es IGUAL a $diasDelMes. Estas dos condiciones se cumplen sólo cuando el último día del mes es un sábado. Entonces, luego de ese último día se termina la tabla, sin necesidad de agregar celdas vacías. Así que, en caso que se cumplan las dos condiciones, no hace nada (por eso no hay nada entre los corchetes curvos).
    Si las condiciones de la línea 17 no se cumplen, en la línea 18, con un elseif verifica si el valor de $y es divisible entre 7 y si el valor de $i es MENOR a $diasDelMes. Estas dos condiciones sólo se cumplen cuando se llega a un sábado (el séptimo día de la semana, o sea, la séptima celda de la fila) que NO es el último día del mes. En caso que se den estas dos condiciones, imprime el cierre de esta fila y la apertura de la siguiente ("</tr>\n<tr>").
    Mientras no se den esas condiciones establecidas en las líneas 17 y 18, y mientras $i<=$diasDelMes seguirá imprimiendo celdas con el correspondiente número de día como muestra la línea 16 ("<td>".$i."</td>").
  • Con todo lo hecho hast a ahora, la tabla está prácticamente lista. Sólo falta crear las celdas vacías que sean necesarias para completar la última fila -semana- de la tabla. Para ello se utiliza un procedimiento análogo al utilizado para crear las celdas vacías en la primera semana del mes.
    Pero, primero, en las líneas 21 y 22 se le resta "1" a las variables $y y $i porque en los bucles que se las utilizó previamente se les sumaba 1 luego de verificar que se cumpliera la condición, por lo que ambas terminaron con el último valor utilizado +1.
  • En la línea 23 se verifica, con un if, si el valor de $y NO es divisible entre 7 y si el valor de $i es IGUAL a $diasDelMes. Estas dos condiciones se cumplen sólo cuando el último día del mes NO es un sábado. Por lo que sí es necesario agregar celdas vacías para completar la última fila. En caso que se cumplan las dos condiciones, se ejecuta el código de las líneas  24 a 27.
  • En la línea 24 se define la variable $ultimoDiaMes, conteniendo el tiempo unix (mktime) del último día ($diasDelMes) del mes (date("m",$_GET['fechaactual'])) y año (date("Y",$_GET['fechaactual'])) seleccionados.
  • En la línea 25 se define la variable $restoUltimaSemana que va a contener la candidad de celdas vacías que tiene que llevar la última fila. Para ello, con date('w',$ultimoDiaMes) obtiene un número que representa el día de la semana del último día del mes (representado por "0" para el domingo, "1" para el lunes y así hasta "6" para el sábado). A ese número, se lo multiplica por "-1" y se le suma "6". Y, por la misma razón expuesta en la explicación de la línea 13, se guarda la variable $restoUltimaSemana la candidad de celdas vacías que tiene que llevar la última fila. 
  • Las líneas 26 y 27 contienen el último bucle for, que define un contador $i con valor "1", al que le va agregando uno ($i++), mientras $i sea menor o igual a $restoUltimaSemana (o sea, la candidad de celdas vacías que tiene que llevar la última fila). Por cada vez que la condición sea válida en el bucle, se imprime una celda vacía ("<td></td>").
  • Por último, en la línea 29 se cierra la última fila ("</tr>") y en la 30 se cierra la tabla ("</table>").
Los cambios y agregados explicados en esta entrada dan como resultado la versión 0.2 de index.php, que, ejecutado el día de ayer, muestra lo siguiente en el navegador web:



Además, el código html5 generado por este script es válido, según http://html5.validator.nu/.

martes, 7 de febrero de 2012

Escribir código válido desde el principio

Antes de continuar agregando características al proyecto, y dado que ya cumple con la funcionalidad mínima indispensable para un calendario (mostrar la fecha del día y permitir cambiarse hacia otra), voy a incluir el código html necesario para generar código válido desde el principio.
Para ello, al script completado en la entrada anterior lo coloco rodeado de líneas de código html, como se ve a continuación:

<!DOCTYPE html>
<head>
<title>CLCPHP - Calandario Lit&uacute;rgio Cat&oacute;lico En PHP</title>
</head>
<body>
<?php
include("funciones.php");
if(!isset($_GET['fechaactual'])) {
$_GET['fechaactual']=time();}
$ayer=mktime(0,0,0,date("m",$_GET['fechaactual']), date("d",$_GET['fechaactual'])-1,date("Y",$_GET['fechaactual']));
$manana=mktime(0,0,0,date("m",$_GET['fechaactual']), date("d",$_GET['fechaactual'])+1,date("Y",$_GET['fechaactual']));
echo "<div style='text-align:center;'>";
echo "<h3>".traducir(date('l d \d\e F \d\e Y',$_GET['fechaactual']))."</h3>";
echo "<a href='index.php?fechaactual=".$ayer."'>&lt;&lt; D&iacute;a anterior</a> | ";
echo "<a href='index.php?fechaactual=".$manana."'>D&iacute;a posterior &gt;&gt;</a>";
echo "</div>";
?>
</body>
</html>

Luego, con el xampp corriendo, veo la página en un navegador web y, copio y pego el código que se genera (ver código fuente) en algún validador de html5, por ejemplo http://html5.validator.nu/.
Y el resultado es el siguiente: