Lab 05 — Plantillas con require: cabecera y pie reutilizables¶
| Campo | Valor |
|---|---|
| Módulo | Implantación de Aplicaciones Web (IMW) |
| Ciclo | Administración de Sistemas Informáticos en Red (ASIR) |
| Unidad | UT4 — PHP en servidor |
| Criterios de evaluación (CE) | e (modularidad: require y plantillas) |
| Requisitos | Labs 01, 02, 03 y 04 completados |
| Agrupación | Individual |
| Herramientas | Navegador + editor de texto + terminal |
| Apuntes | https://ichigar.codeberg.page/imw/recursos/ut4_php_05_funciones_y_plantillas/ (lee solo la sección Plantillas con require; las funciones llegarán en el Lab 07) |
| Tiempo estimado | 90–120 minutos |
Antes de empezar¶
Entorno de trabajo
Este lab continúa el proyecto ~/gestor/ que vienes ampliando desde el Lab 01. La estructura actual es:
gestor/
├── public/ <-- accesible desde el navegador
│ ├── index.php, info_servidor.php (Lab 01)
│ ├── variables.php, resumen.php (Lab 02)
│ ├── arrays.php, listado.php, catalogo.php (Lab 03)
│ └── estado.php (Lab 04)
├── src/
├── templates/ <-- vacío hasta hoy
└── data/
Si http://gestor.local no responde, revisa el Lab 01 Paso 3 antes de continuar.
Qué vamos a hacer
En los labs anteriores has creado varias páginas PHP (listado.php, estado.php, catalogo.php, etc.) y todas repiten el mismo HTML de estructura: <!DOCTYPE>, <head>, <title>, <header>, <footer>... Hoy vamos a extraer ese HTML repetido a dos plantillas (_header.php y _footer.php) y a aprender a incluirlas en una página con require.
Al final del lab, public/listado.php tendrá solo su contenido único (el <table> de incidencias), y el HTML que la envuelve vendrá de las plantillas. Y en el paso "aplica" añadirás un detalle final: que el menú destaque el enlace de la página activa.
Las demás páginas del proyecto (estado.php, catalogo.php, etc.) se quedan como están. A partir del Lab 06, las páginas nuevas se construirán ya con plantillas; las viejas las migraremos en el lab de integración final (A11) si toca.
Servidor vs cliente
require se ejecuta en el servidor, antes de que Apache envíe nada al navegador. PHP "pega" el contenido de la plantilla dentro de la página y manda al navegador el HTML resultante ya unido. El navegador nunca ve los require: solo recibe un <!DOCTYPE html>...</html> completo. Esto es importante: si abres "Ver código fuente" en el navegador, no encontrarás ningún <?php require ... ?> por ningún lado.
Cómo se entrega este lab¶
Al terminar, empaqueta tu trabajo en un ZIP con esta estructura exacta:
apellido_nombre_lab05/
├── gestor/
│ ├── public/
│ │ ├── css/
│ │ │ └── estilos.css
│ │ └── listado.php
│ └── templates/
│ ├── _header.php
│ └── _footer.php
├── capturas/
│ ├── paso1_html_duplicado.png
│ ├── paso2_estructura_templates.png
│ ├── paso3_listado_con_plantillas.png
│ ├── paso4_listado_con_css_externo.png
│ └── paso5_menu_activo.png
└── RESPUESTAS.md
Nombres prescritos
Los nombres de los ficheros y carpetas son obligatorios y exactos. No uses mayúsculas, espacios ni acentos donde no los haya. El script de corrección busca estos nombres concretos: si los cambias, tu entrega aparecerá como incompleta.
Solo los ficheros que toca este lab
En el ZIP solo se incluyen los ficheros nuevos o modificados en este lab: el listado.php refactorizado, el estilos.css nuevo y las dos plantillas. El resto de tu gestor/ (index.php, estado.php, arrays.php, etc.) se queda en tu servidor y no se entrega. Esa es la regla a partir de ahora: cada lab entrega solo lo suyo.
Cómo preparar la entrega (independientemente del sistema operativo):
- Crea una carpeta en tu equipo llamada
apellido_nombre_lab05(sustituye por tu apellido y nombre reales, en minúsculas y sin espacios ni acentos). - Dentro, reproduce la estructura de arriba:
gestor/public/css/estilos.csscon el CSS externo (Paso 4).gestor/public/listado.phpcon la versión refactorizada que usa plantillas.gestor/templates/_header.phpygestor/templates/_footer.phpcon las plantillas.- Una subcarpeta
capturas/con los 5 PNG, ya renombrados exactamente como se indica en cada paso. - Un fichero
RESPUESTAS.mden la raíz de la carpeta, con una sección## Paso Npor cada pregunta del lab (la plantilla está en el anexo al final de este documento).
- Comprime esa carpeta completa en un archivo
.zip:- Windows: clic derecho sobre la carpeta → Enviar a → Carpeta comprimida (en zip). El archivo resultante debe llamarse
apellido_nombre_lab05.zip. - Linux/macOS: desde la terminal,
zip -r apellido_nombre_lab05.zip apellido_nombre_lab05/.
- Windows: clic derecho sobre la carpeta → Enviar a → Carpeta comprimida (en zip). El archivo resultante debe llamarse
- Abre el ZIP para comprobar que al descomprimirlo aparece una sola carpeta raíz llamada
apellido_nombre_lab05/, y que dentro están todos los ficheros esperados.
Comprueba la estructura del ZIP antes de subirlo
Un error habitual en Windows es seleccionar los ficheros de dentro de la carpeta en lugar de la carpeta completa, y comprimirlos. Eso genera un ZIP que al abrirse no tiene carpeta raíz, y el script de corrección lo rechaza. Comprime la carpeta apellido_nombre_lab05/, no su contenido.
Paso 1 — Diagnóstico: el HTML que se repite en cada página¶
Conceptos
- Sin plantillas, cada
.phpde tupublic/repite el mismo<head>,<header>y<footer>. Si quisiéramos cambiar el título del sitio o el menú, tendríamos que editar todos los ficheros. - DRY (Don't Repeat Yourself): si escribes lo mismo dos veces, extráelo y reutilízalo. Vale para HTML, igual que para cualquier código.
require "fichero.php"incluye el contenido de ese fichero como si lo hubieras escrito en el sitio donde aparece elrequire. La diferencia conincludees querequirelanza un error fatal si el fichero no existe (la página se rompe), mientras queincludesolo muestra un aviso y sigue. Para plantillas obligatorias usa siemprerequire: si la plantilla falta, queremos enterarnos en seguida, no pintar media página.
Pequeño aviso de coherencia: si esta comparación de hoy te da pocas líneas repetidas (porque tu listado.php de A3 y tu estado.php de A4 son cortos), no pasa nada. El argumento DRY se mantiene incluso con 8-10 líneas duplicadas: imagínate el día que tengamos 10 páginas.
Objetivo. Identificar el bloque de HTML que se repite en las páginas que ya tienes, para entender por qué require es la solución natural.
Tarea. Abre en tu editor (no hace falta tocar nada todavía) dos ficheros de los labs anteriores: ~/gestor/public/listado.php (del Lab 03) y ~/gestor/public/estado.php (del Lab 04). Compara las dos partes:
- Desde
<!DOCTYPE html>hasta el primer<h1>o<h2>→ ¿qué hay igual en ambos ficheros? ¿qué cambia? - Desde el final del contenido propio (la tabla, la lista de incidencias) hasta
</html>→ ¿es exactamente el mismo cierre?
Esto que estás detectando "a ojo" es lo que vamos a extraer a plantillas. La meta no escrita: si mañana queremos añadir un <nav> con enlaces a las páginas del proyecto, deberíamos poder hacerlo en un solo sitio.
Responde en RESPUESTAS.md, sección ## Paso 1.
Cuenta cuántas líneas de HTML "de estructura" (desde
<!DOCTYPE html>hasta el cierre</html>, excluyendo el contenido propio de cada página) se repiten entrelistado.phpyestado.php. No tiene que ser exacto a la línea: una aproximación razonable basta. ¿Qué pasaría si tuvieras 10 páginas y quisieras cambiar el texto del<title>global del sitio?
Captura requerida. Abre los dos ficheros en tu editor con vista de pantalla dividida (o uno al lado del otro) y guarda una captura en capturas/paso1_html_duplicado.png. Debe verse:
- Los dos ficheros (
listado.phpyestado.php) abiertos en paralelo. - Las primeras líneas (
<!DOCTYPE html>,<head>,<title>) visibles en ambos para que se aprecie la duplicación.
Pista si usas VS Code
Abre los dos ficheros. En el segundo, haz clic derecho en la pestaña → Split Right (o Dividir a la derecha). Te quedan los dos en paralelo.
Verificación antes de pasar al Paso 2.
- He localizado el bloque de HTML repetido en
listado.phpyestado.php. - He guardado
capturas/paso1_html_duplicado.png. - Entiendo por qué
require(y noinclude) es lo correcto para incluir una plantilla obligatoria.
Paso 2 — Crear _header.php y _footer.php¶
Conceptos
- Las plantillas van en
templates/(fuera depublic/), porque no deben ser accesibles directamente desde el navegador. Si alguien escribierahttp://gestor.local/_header.php, vería un HTML roto (solo la cabecera, sin contenido ni cierre). Y en labs futuros, ahí guardaremos plantillas con datos sensibles que tampoco queremos servir sueltas. - El prefijo
_en_header.phpes una convención para indicar "esto es un fragmento, no una página completa". -
Una plantilla puede usar variables definidas antes del
requireen la página que la incluye. Anticipo del patrón completo que verás aplicado en el Paso 3:<?php $titulo_pagina = 'Listado de incidencias'; // 1. defines la variable require __DIR__ . '/../templates/_header.php'; // 2. incluyes la plantilla ?> ...contenido único de la página...Dentro de
_header.php,$titulo_paginaestá disponible "como si la hubieras escrito allí". Esto es lo que permite que una sola plantilla sirva para muchas páginas, cada una con su título. -
Si una página olvida definir
$titulo_pagina,_header.phpla usaría sin valor y daría aviso. Por eso la plantilla pone un valor por defecto conisset()al inicio.isset($var)es una función de PHP que devuelvetruesi la variable existe (y no esnull), yfalsesi no. Es el equivalente "largo" del operador??que viste en A4:$x = $x ?? 'default';yif (!isset($x)) { $x = 'default'; }hacen lo mismo.
Mala práctica: poner _header.php dentro de public/
Si ponen las plantillas en public/templates/ o directamente en public/, Apache las sirve por URL como cualquier otra página: cualquiera podría abrir http://gestor.local/_header.php y vería un HTML incompleto. Peor: en el Lab 09 las plantillas mostrarán nombres de usuario, y servirlas sueltas filtraría información. Los ficheros que no son páginas finales se guardan fuera de public/. Esta regla vale para todo el proyecto y para todas las páginas que escriban a partir de hoy.
Objetivo. Crear las dos plantillas (_header.php y _footer.php) en ~/gestor/templates/, con el HTML que ahora está duplicado en las páginas.
Tarea 1 — Crear _header.php. Crea el fichero ~/gestor/templates/_header.php con este contenido:
Fíjate en que _header.php abre <main> pero no lo cierra: el cierre lo pondrá _footer.php. Entre ambos va el contenido único de cada página.
Tarea 2 — Crear _footer.php. Crea el fichero ~/gestor/templates/_footer.php con este contenido:
_footer.php cierra </main>, pinta el pie y cierra </body> y </html>. El año del pie se calcula en el servidor con la función date('Y'), así que cuando cambie el año cambia solo.
Responde en RESPUESTAS.md, sección ## Paso 2.
Fíjate en que
_header.phpabre<main>pero no lo cierra, y_footer.phpcierra</main>pero no lo abre. ¿Por qué está hecho así? Pista: piensa en qué pasaría si cada plantilla cerrara sus propias etiquetas — ¿dónde meterías entonces el contenido específico de cada página (la tabla dellistado.php, el bloque deestado.php...)?
Captura requerida. En tu terminal, ejecuta ls -la ~/gestor/templates/ y guarda una captura en capturas/paso2_estructura_templates.png. Debe verse:
- El listado del directorio
~/gestor/templates/. - Los dos ficheros
_header.phpy_footer.phpcon sus tamaños.
Verificación antes de pasar al Paso 3.
-
~/gestor/templates/_header.phpexiste y contiene el HTML hasta<h2>...</h2>. -
~/gestor/templates/_footer.phpexiste y cierra</main>,<footer>,</body>y</html>. - Los dos ficheros están en
templates/, NO enpublic/. -
php -l ~/gestor/templates/_header.phpyphp -l ~/gestor/templates/_footer.phpno dan errores. - He guardado
capturas/paso2_estructura_templates.png.
Paso 3 — Refactorizar listado.php con require y __DIR__¶
Conceptos
- Refactorizar = mejorar la estructura interna de un código sin cambiar lo que se ve por fuera. El navegador debe mostrar lo mismo antes y después de la refactorización; lo que cambia es cómo está organizado el código en el servidor.
__DIR__es una constante de PHP que vale "la ruta absoluta del directorio donde está el fichero actual". Silistado.phpvive en/home/alumno/gestor/public/, dentro delistado.phpla constante__DIR__vale literalmente/home/alumno/gestor/public.- El punto
.concatena cadenas en PHP. Por eso__DIR__ . "/../templates/_header.php"significa "el directorio actual, sube un nivel, entra en templates, coge_header.php". - El patrón completo de cada página queda así: define las variables (
$titulo_pagina, datos a mostrar) →requirecabecera → contenido único →requirepie.
¿Por qué __DIR__ y no una ruta sin más?
Tienes tres formas de escribir la ruta a la plantilla. Compara qué pasa con cada una:
| Forma | Ejemplo | Problema |
|---|---|---|
| Ruta absoluta | require "/home/alumno/gestor/templates/_header.php"; |
Solo funciona en tu equipo. Si entregas el ZIP y el profesor lo descomprime en otra ruta, no funciona. |
| Ruta relativa | require "../templates/_header.php"; |
Funciona si el directorio de trabajo es public/, pero Apache no siempre garantiza eso. Si la página se incluyera desde otro contexto, la ruta se rompe. |
Con __DIR__ |
require __DIR__ . "/../templates/_header.php"; |
Siempre funciona, porque parte del directorio del fichero actual, que PHP conoce con seguridad. |
Usa siempre la tercera. Es lo que hacen todos los frameworks PHP del mundo.
Cómo se "lee" esa línea, paso a paso. Si listado.php vive en /home/alumno/gestor/public/, entonces dentro de ese fichero __DIR__ vale literalmente /home/alumno/gestor/public. La expresión __DIR__ . "/../templates/_header.php" se convierte en la cadena /home/alumno/gestor/public/../templates/_header.php, que el sistema operativo resuelve a /home/alumno/gestor/templates/_header.php. Es decir: sube un nivel desde public/, entra en templates/, abre _header.php.
Objetivo. Reescribir ~/gestor/public/listado.php para que use las dos plantillas, eliminando todo el HTML duplicado.
Tarea. Reescribe ~/gestor/public/listado.php completo (sustituye lo que tenías por esto):
Accede a http://gestor.local/listado.php y comprueba que la página muestra:
- Cabecera azul con "Gestor de incidencias" y el enlace "Listado" en el menú.
- Título
Listado de incidenciasdebajo de la cabecera. - La tabla de 3 incidencias (todavía sin filas alternas — eso vendrá con el CSS externo del Paso 4).
- Pie centrado con "Gestor de incidencias — ASIR IMW —
2026" (o el año actual).
Y muy importante: el <title> de la pestaña del navegador debe decir "Listado de incidencias — Gestor".
Pista si ves los require literales en la página
Si en el navegador aparece texto como <?php require __DIR__ ... en lugar de la página renderizada, Apache no está interpretando PHP en listado.php. Eso suele significar que el módulo PHP está deshabilitado: sudo a2enmod php8.3 && sudo systemctl reload apache2. Si ves una página en blanco o un error 500, mira el log con sudo tail /var/log/apache2/error.log: ahí aparecerá si la ruta del require está mal.
Si la pantalla en blanco / HTTP 500 son habituales en este lab y te toca abrir el log cada vez, comprueba que activaste display_errors = On en el Paso 5 del lab A1 — Depuración: ver los errores de PHP. Con esa directiva activa, los errores fatales tipo "Failed opening required" aparecen directamente en el navegador y no necesitas mirar el log para verlos. Una vez activado, sirve para el resto de los labs.
Pista si la página dice 'Failed opening required ...'
Es el error fatal de require cuando no encuentra el fichero. Tres cosas a comprobar, en este orden:
- Que existen
~/gestor/templates/_header.phpy~/gestor/templates/_footer.phpcon esos nombres exactos (cuidado con el_inicial). - Que la ruta
__DIR__ . '/../templates/_header.php'parte depublic/: las plantillas tienen que estar un nivel por encima. - Que Apache (usuario
www-data) puede leer la carpetatemplates/. Compruébalo consudo -u www-data cat ~/gestor/templates/_header.php: si te muestra el contenido, ok; si dice "Permission denied", hay un problema de permisos en el directorio del usuario.
Responde en RESPUESTAS.md, sección ## Paso 3.
Si moviéramos
_header.phpdentro depublic/(por ejemplo, apublic/_header.php) y un usuario curioso abriera la URLhttp://gestor.local/_header.phpen su navegador, ¿qué vería? ¿Por qué es esto un problema, y por qué guardar las plantillas entemplates/(fuera depublic/) lo evita?
Captura requerida. Visita http://gestor.local/listado.php y guarda una captura en capturas/paso3_listado_con_plantillas.png. Debe verse:
- La URL
http://gestor.local/listado.phpen la barra de direcciones. - La pestaña del navegador con el título "Listado de incidencias — Gestor".
- La cabecera azul con "Gestor de incidencias" y el menú con "Listado".
- La tabla de las 3 incidencias.
- El pie con el año actual.
Verificación antes de pasar al Paso 4.
-
listado.phpusarequire __DIR__ . '/../templates/_header.php'para la cabecera. -
listado.phpusarequire __DIR__ . '/../templates/_footer.php'para el pie. -
listado.phpya no contiene<!DOCTYPE html>,<head>,<header>ni<footer>propios. - La pestaña del navegador muestra "Listado de incidencias — Gestor".
- La página se ve correctamente con la cabecera azul y la tabla.
-
php -l ~/gestor/public/listado.phpno da errores. - He guardado
capturas/paso3_listado_con_plantillas.png.
Paso 4 — CSS externo en public/css/estilos.css¶
Conceptos
- El CSS, las imágenes, los iconos y los
.jsvan enpublic/porque sí necesitan ser accesibles desde el navegador (el navegador los pide directamente por URL). - Convención habitual:
public/css/,public/js/,public/img/. - Cómo funciona el
<link>(importante, distinto delrequire): cuando Apache envía el HTML al navegador, el navegador ve la línea<link rel="stylesheet" href="/css/estilos.css">y hace una segunda petición HTTP ahttp://gestor.local/css/estilos.css. Apache le responde con el fichero CSS y el navegador lo aplica. Es decir: el CSS no lo "pega" el servidor dentro de la página como hacerequirecon las plantillas; el servidor manda un HTML que menciona la ruta del CSS, y es el navegador quien lo va a buscar. Por eso el fichero CSS tiene que estar dentro depublic/: el navegador lo va a pedir directamente. Las plantillas, en cambio, pueden quedarse fuera depublic/porque el navegador no las pide nunca. - La ruta en el
<link>se escribe relativa a la raíz del servidor:href="/css/estilos.css". La barra inicial significa "desde la raíz del DocumentRoot de Apache", que en nuestro caso es~/gestor/public/. Por eso/css/estilos.cssapunta a~/gestor/public/css/estilos.css. - Centralizar el CSS en un fichero externo tiene dos ventajas: un cambio de color o fuente afecta a todas las páginas a la vez, y el navegador puede cachear ese fichero en lugar de descargarlo en cada página.
Objetivo. Extraer el CSS que ahora está dentro del <style> de _header.php a un fichero externo public/css/estilos.css, y enlazarlo desde la plantilla.
Tarea 1 — Crear el directorio y el fichero CSS. Desde la terminal:
Después, crea ~/gestor/public/css/estilos.css con exactamente el mismo contenido que tenías en el <style> de _header.php, más unas reglas extra para la tabla:
Tarea 2 — Sustituir el <style> por un <link> en _header.php. Abre ~/gestor/templates/_header.php y elimina el bloque entero <style> ... </style> que va dentro del <head>. En su lugar, añade esta línea (debajo del <title>):
El bloque <head> debe quedar así:
Tarea 3 — Quitar los estilos inline de listado.php. En listado.php, los style="..." que pusimos en el <table>, <tr>, <th> y <td> ya están cubiertos por el CSS externo: bórralos. La tabla queda así de limpia:
Tarea 4 — Quitar el style inline del <footer> de _footer.php. El CSS externo ya define una regla footer { ... } con los mismos colores y bordes que el style="..." que pusimos en el Paso 2. Abre ~/gestor/templates/_footer.php y deja el <footer> sin atributo style:
Guarda los cuatro ficheros y recarga http://gestor.local/listado.php. La página debe verse igual que antes (mismos colores, mismas filas alternas), pero ahora todo el CSS viene del fichero externo: ni <style> en el <head> ni style="..." en ninguna etiqueta.
Pista para comprobar que el CSS lo sirve Apache
En el navegador, pulsa F12 para abrir las DevTools y ve a la pestaña Network (o Red). Recarga la página. Deberías ver entre las peticiones una a /css/estilos.css con código de estado 200. Si ves un 404, la ruta del <link> está mal o el fichero no está en ~/gestor/public/css/.
Responde en RESPUESTAS.md, sección ## Paso 4.
¿Por qué el CSS se carga con
<link rel="stylesheet" href="/css/estilos.css">(una etiqueta HTML que descarga el navegador) y no conrequireen PHP como las plantillas? Pista: piensa en quién interpreta cada cosa (servidor o navegador) y cuándo.
Captura requerida. Recarga http://gestor.local/listado.php con las DevTools abiertas en la pestaña Network y guarda una captura en capturas/paso4_listado_con_css_externo.png. Debe verse:
- La página renderizada con los mismos colores que antes (cabecera azul, tabla con filas alternas).
- La pestaña Network de las DevTools mostrando la petición a
/css/estilos.csscon código 200.
Verificación antes de pasar al Paso 5.
-
~/gestor/public/css/estilos.cssexiste y contiene los estilos. -
_header.phpya no tiene el bloque<style>y sí tiene el<link rel="stylesheet" ...>. -
listado.phpya no tiene atributosstyle="..."en la tabla. - La página se ve igual que en el Paso 3, pero el CSS viene del fichero externo.
- En la pestaña Network del navegador aparece la petición a
/css/estilos.csscon código 200. - He guardado
capturas/paso4_listado_con_css_externo.png.
Paso 5 — Aplica lo aprendido: enlace activo en el menú¶
Qué es este paso
Los cuatro pasos anteriores han sido guiados: te he dado el código y tú lo has tecleado, probado y respondido. En este quinto paso no hay código de referencia completo. Lo que hay son requisitos, y tú aplicas lo aprendido sobre paso de variables a plantillas y sobre isset() para resolver un problema nuevo.
El reto: cuando un usuario está en listado.php, el enlace "Listado" del menú debe aparecer destacado (subrayado y en negrita). El sistema tiene que funcionar con cualquier futura página: si mañana añadimos panel.php con un enlace "Panel" en el menú, debe poder destacarse igual sin reescribir la plantilla.
Aquí no creamos un fichero nuevo: vamos a ampliar los ficheros del Paso 3 (_header.php y listado.php) y a añadir una clase nueva al CSS externo. Si después de hacerlo decides borrar esta ampliación, los ficheros vuelven a la versión del Paso 4 y siguen funcionando: el "enlace activo" es una capa decorativa encima del sistema de plantillas, no una pieza imprescindible.
Objetivo. Hacer que _header.php destaque el enlace del menú correspondiente a la página actual, usando una variable $pagina_activa que cada página define antes del require.
Tarea. Modifica tres ficheros cumpliendo los requisitos siguientes.
Requisitos obligatorios de contenido:
- En
~/gestor/templates/_header.php:- Al inicio del bloque PHP de cabecera (donde ya pones el valor por defecto de
$titulo_pagina), añade un valor por defecto para$pagina_activaconisset(): si la página no la define, vale cadena vacía. - En el
<nav>, sustituye el único<a href="/listado.php">Listado</a>actual por un bloqueif/elseque pinte dos<a>distintos según la condición$pagina_activa === 'listado': si es verdad, el<a>llevaclass="activo"; si no, va sin clase. Es el mismo patrónif/elsecon sintaxis alternativa (if (...): ... else: ... endif) que viste en A4, pero ahora la "salida" de cada rama es una etiqueta HTML completa, no texto.
- Al inicio del bloque PHP de cabecera (donde ya pones el valor por defecto de
- En
~/gestor/public/css/estilos.css: añade al final una regla nueva paranav a.activoque destaque el enlace activo. Como mínimo debe cambiar el color a blanco, ponerlo en negrita y añadirle un borde inferior (border-bottom) para que se vea subrayado. - En
~/gestor/public/listado.php: justo después de la línea$titulo_pagina = 'Listado de incidencias';añade la línea que define$pagina_activa = 'listado';.
Requisitos de presentación HTML:
- Al cargar
http://gestor.local/listado.php, el enlace "Listado" del menú debe aparecer destacado (blanco, en negrita, subrayado). - Si quitas la línea
$pagina_activa = 'listado';delistado.phpy recargas, el menú sigue funcionando pero ningún enlace queda marcado: no debe salir ningún error en pantalla.
Requisitos de calidad del código:
- La plantilla no asume que
$pagina_activasiempre esté definida: usaisset()(o el operador??) para darle un valor por defecto. - La clase
activose añade desde PHP de forma dinámica, no escribiendoclass="activo"hardcoded en el HTML.
Pista sobre cómo pintar dos <a> distintos según la condición
El bloque dentro del <nav> puede quedar así:
<?php if ($pagina_activa === 'listado'): ?>
<a href="/listado.php" class="activo">Listado</a>
<?php else: ?>
<a href="/listado.php">Listado</a>
<?php endif ?>
Es repetitivo (el href y el texto aparecen dos veces), pero a cambio es muy claro de leer y muy fácil de verificar: si pulsas "Ver código fuente" en el navegador después de cargar, verás un solo <a> impreso, el que corresponda. Es exactamente la misma estructura if/else con sintaxis alternativa que has usado en A4 — lo único nuevo es que aquí cada rama imprime una etiqueta HTML diferente.
Pista sobre el valor por defecto de $pagina_activa
Igual que en _header.php ya proteges $titulo_pagina con isset(), haz lo mismo con $pagina_activa:
Con la cadena vacía como valor por defecto, la condición $pagina_activa === 'listado' siempre da false si la página no la define, y ningún enlace sale marcado. Sin error.
Responde en RESPUESTAS.md, sección ## Paso 5.
- ¿Qué pasa exactamente si una página olvida definir
$pagina_activaantes delrequire __DIR__ . '/../templates/_header.php';? ¿Sale un error en pantalla, sale un aviso, o sale la página normal sin enlace marcado? Explica por qué.- Si mañana queremos añadir al menú un enlace "Panel" (a un futuro
panel.php), ¿qué dos cambios habría que hacer en_header.phpy qué línea habría que añadir enpanel.phppara que el enlace se destaque al estar en esa página? No hace falta escribir el código, basta con describir los cambios.
Captura requerida. Visita http://gestor.local/listado.php y guarda una captura en capturas/paso5_menu_activo.png. Debe verse:
- La URL
http://gestor.local/listado.phpen la barra de direcciones. - La cabecera azul con el menú.
- El enlace "Listado" del menú destacado: en blanco, en negrita y con borde inferior.
Verificación.
-
_header.phpdefine$pagina_activaconisset()(valor por defecto cadena vacía). - El enlace "Listado" del
<nav>recibeclass="activo"solo cuando$pagina_activa === 'listado'. -
estilos.csstiene una reglanav a.activocon color blanco,font-weight: boldyborder-bottom. -
listado.phpdefine$pagina_activa = 'listado';antes delrequiredel header. - Al cargar
listado.php, el enlace "Listado" sale destacado. - Si quitas temporalmente la línea de
$pagina_activaenlistado.php, no sale error y ningún enlace queda marcado. - He guardado
capturas/paso5_menu_activo.png.
Si tu Paso 5 deja _header.php o listado.php con error de sintaxis
Antes de hacer el ZIP, deshaz tus cambios del Paso 5 en _header.php y en listado.php y vuelve a la versión que tenías al final del Paso 4. Es preferible entregar el Paso 5 vacío (perdiendo solo los puntos de ese paso) que entregar un _header.php roto que rompa también lo del Paso 3 y el Paso 4. Comprueba con php -l ~/gestor/templates/_header.php y php -l ~/gestor/public/listado.php antes de empaquetar.
Checklist final de entrega¶
Antes de subir el ZIP al Campus, revisa uno a uno:
- He creado la carpeta
apellido_nombre_lab05/(con mi apellido y nombre reales). - Dentro hay
gestor/public/listado.phpcon el código final del Paso 5. - Dentro hay
gestor/public/css/estilos.csscon la reglanav a.activoincluida. - Dentro hay
gestor/templates/_header.phpygestor/templates/_footer.php. - Dentro hay
capturas/con los 5 PNG:paso1_html_duplicado.png,paso2_estructura_templates.png,paso3_listado_con_plantillas.png,paso4_listado_con_css_externo.png,paso5_menu_activo.png. - Dentro hay
RESPUESTAS.mdcon las 5 secciones rellenas. - Los tres ficheros PHP pasan
php -lsin errores:php -l ~/gestor/public/listado.phpphp -l ~/gestor/templates/_header.phpphp -l ~/gestor/templates/_footer.php
- El ZIP se llama
apellido_nombre_lab05.zipy al descomprimirlo solo aparece una carpeta raíz con ese nombre. - He subido el ZIP a la tarea correspondiente en el Campus antes de la fecha límite.
Anexo — Plantilla de RESPUESTAS.md¶
Crea un fichero llamado RESPUESTAS.md dentro de apellido_nombre_lab05/ con esta plantilla y rellena cada sección:
# Respuestas — Lab 05 Plantillas con `require`
**Nombre:** Apellido, Nombre
**Fecha:** YYYY-MM-DD
## Paso 1
(Tu respuesta: cuántas líneas de HTML estructural se repiten entre `listado.php` y `estado.php`, y qué pasaría con 10 páginas si cambias el `<title>` global.)
## Paso 2
(Tu respuesta: por qué `_header.php` abre `<main>` pero no lo cierra, y qué va en el hueco entre los dos `require`.)
## Paso 3
(Tu respuesta: qué vería un usuario que abriera `http://gestor.local/_header.php` si las plantillas estuvieran en `public/`, y por qué es un problema.)
## Paso 4
(Tu respuesta: por qué el CSS se carga con `<link>` y no con `require`, pensando en quién interpreta cada cosa.)
## Paso 5
1. (Tu respuesta: qué pasa si una página olvida definir `$pagina_activa` y por qué.)
2. (Tu respuesta: qué cambios harían falta en `_header.php` y en `panel.php` para destacar un futuro enlace "Panel".)