Diferencia entre revisiones de «PHP Conceptos básicos Modelo-Vista-Controlador»
| (No se muestran 19 ediciones intermedias del mismo usuario) | |||
| Línea 18: | Línea 18: | ||
| − | + | * '''Clase para acceder a Mysql''' | |
* En primeiro lugar, poderíamos crear unha clase que se encargue da facer a conexión á base de datos e as operacións contra a mesma. | * En primeiro lugar, poderíamos crear unha clase que se encargue da facer a conexión á base de datos e as operacións contra a mesma. | ||
| Línea 81: | Línea 81: | ||
::<syntaxhighlight lang="java" enclose="div" highlight="" > | ::<syntaxhighlight lang="java" enclose="div" highlight="" > | ||
<?php | <?php | ||
| − | + | require('Database.php'); | |
$conex = Database::obterConexion(); | $conex = Database::obterConexion(); | ||
| Línea 199: | Línea 199: | ||
::<syntaxhighlight lang="java" enclose="div" highlight="23" > | ::<syntaxhighlight lang="java" enclose="div" highlight="23" > | ||
<?php | <?php | ||
| − | + | require('Database.php'); | |
$conex = Database::obterConexion(); | $conex = Database::obterConexion(); | ||
| Línea 244: | Línea 244: | ||
* Tamén poderíamos aplicar os [http://wiki.cifprodolfoucha.es/index.php?title=PHP_Programaci%C3%B3n_Orientada_a_obxectos conceptos da POO que aprendemos anteriormente na wiki] e facer que a información que devolva a función 'consultarLibros' da clase Database, sexa un array de obxectos dunha clase definida previamente, que representaría a táboa LIBROS. | * Tamén poderíamos aplicar os [http://wiki.cifprodolfoucha.es/index.php?title=PHP_Programaci%C3%B3n_Orientada_a_obxectos conceptos da POO que aprendemos anteriormente na wiki] e facer que a información que devolva a función 'consultarLibros' da clase Database, sexa un array de obxectos dunha clase definida previamente, que representaría a táboa LIBROS. | ||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | + | * No seguinte punto imos aprender como 'separar' en diferentes 'capas' a aplicación para que o mantemento do proxecto sexa moito máis doado. | |
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | * | ||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
== Modelo-Vista-Controlador == | == Modelo-Vista-Controlador == | ||
| Línea 467: | Línea 262: | ||
* Esta forma de programar é a que empregan os frameworks servidor de PHP, como [https://laravel.com/ LARAVEL] e [https://symfony.es/ SYMFONY]. | * Esta forma de programar é a que empregan os frameworks servidor de PHP, como [https://laravel.com/ LARAVEL] e [https://symfony.es/ SYMFONY]. | ||
| − | : Veremos LARAVEL na [https://wiki.cifprodolfoucha.es/index.php?title= | + | : Veremos LARAVEL na [https://wiki.cifprodolfoucha.es/index.php?title=PHP_Modelo_-_Vista_-_Controlador UNIDADE_6:Programación de Servizos Web]. Cando cheguedes a dita unidade xa teredes experiencia no manexo de Laravel para o desenvolvemento de aplicacións se fixéchedes as tarefas propostas no Moodle. |
| Línea 485: | Línea 280: | ||
:* /var/www/html/public: Onde vai ir a páxina controladora frontal. É a única á que van ter acceso os usuarios dende o navegador. | :* /var/www/html/public: Onde vai ir a páxina controladora frontal. É a única á que van ter acceso os usuarios dende o navegador. | ||
:: Esta páxina vai ter o formato: | :: Esta páxina vai ter o formato: | ||
| − | :::index.php?paxina= | + | :::'''index.php?paxina=libros''' => Entón cargará o que estea en ControladorLibro.php => getLibros |
| − | :::index.php?paxina=libroautor => Entón cargará o que estea en ControladorLibro.php => getLibrosPorAutor | + | :::'''index.php?paxina=libroautor''' => Entón cargará o que estea en ControladorLibro.php => getLibrosPorAutor |
| + | :::'''index.php?paxina=altalibro''' => A esta páxina podemos chegar dende dous sitios diferentes. Ao premer no botón de alta libro amosaremos un formulario baleiro e cando prememos no botón ALTA, deberemos de chamar á base de datos cós datos do formulario para facer un insert. Diferenciaremos un ou outro en función se temos datos en $_POST (neste caso vimos do formulario para dar de alta). Chamaremos por tanto a dous métodos no controlador: <u>altalibro</u> cando queramos cargar o formulario e <u>create</u> cando queramos engadir os datos do libro á base de datos. Para simplificalo soamente se dará de alta na táboa Libro e non na de libro_autor. | ||
| + | :::'''index.php?paxina=editarlibro''' => A esta páxina podemos chegar dende dous sitios diferentes. Ao seleccionar un libro cargaremos un formulario cós datos do libro seleccionado e cando prememos no botón Modificar, deberemos de chamar á base de datos cós datos do formulario para facer unha modificación. Diferenciaremos un ou outro en función se temos datos en $_POST (neste caso vimos do formulario). Chamaremos por tanto a dous métodos no controlador: <u>editarLibro</u> cando queramos cargar o formulario e <u>update</u> cando queramos modificar os datos do libro. | ||
| + | :::'''index.php?paxina=borrarlibro''' => Entón cargará o que estea en ControladorLibro.php => destroy. O id do libro virá no $_POST | ||
| + | |||
| + | |||
| + | |||
| + | * <u>Nota:</u> Por simplificar non vou reutilizar o código das páxinas nin vou enviar o token csrf para protexer aos formularios, pero lembrade que o teriades que facer nun sitio web real. | ||
| + | : O páxina de alta e modificar teñen os mesmos contidos cambiando o action do formulario e no contido do botón que terá o texto Alta ou Modificar según o caso polo que se podería crear unha única vista. | ||
| Línea 493: | Línea 296: | ||
<center>https://victorroblesweb.es/wp-content/uploads/2013/11/mvc-php.jpg</center> | <center>https://victorroblesweb.es/wp-content/uploads/2013/11/mvc-php.jpg</center> | ||
<small><center>Imaxe obtida [https://victorroblesweb.es/2013/11/18/tutorial-mvc-en-php-nativo/ deste tutorial]</small></center> | <small><center>Imaxe obtida [https://victorroblesweb.es/2013/11/18/tutorial-mvc-en-php-nativo/ deste tutorial]</small></center> | ||
| + | |||
| + | |||
| + | |||
| + | * <u>'''NOTA:'''</u> No exemplo, os include/require están empregando rutas relativas para que poidades probalo en calquera cartafol, pero nun sitio real deberíamos empregar $_SERVER['DOCUMENT_ROOT']. | ||
| + | |||
| + | |||
<br/> | <br/> | ||
====Acceso a datos==== | ====Acceso a datos==== | ||
| − | * No cartafol /var/www/acceso_datos creamos a páxina ''' | + | * No cartafol /var/www/acceso_datos creamos a páxina '''database.php'''. |
: O seu contido xa o vimos no punto anterior. É onde están definidas as constantes de conexión e os métodos que executan sentenzas contra a base de datos Mysql. | : O seu contido xa o vimos no punto anterior. É onde están definidas as constantes de conexión e os métodos que executan sentenzas contra a base de datos Mysql. | ||
::<syntaxhighlight lang="java" enclose="div" highlight="" > | ::<syntaxhighlight lang="java" enclose="div" highlight="" > | ||
| Línea 557: | Línea 366: | ||
<br /> | <br /> | ||
| + | |||
====Modelos==== | ====Modelos==== | ||
* No cartafol /var/www/modelos creamos a páxina '''Libro.php'''. | * No cartafol /var/www/modelos creamos a páxina '''Libro.php'''. | ||
: Nesta clase estarán definidos todos os atributos e métodos relacionados coa clase. A maiores estarán os métodos que farán uso da clase DataBase e obterán os datos de facer as consultas. | : Nesta clase estarán definidos todos os atributos e métodos relacionados coa clase. A maiores estarán os métodos que farán uso da clase DataBase e obterán os datos de facer as consultas. | ||
| − | : No noso exemplo, imos crear | + | : No noso exemplo, imos crear 6 métodos que van acceder á base de datos: |
| + | :* Listado dos libros => '''getLibros''' | ||
| + | :* Listado de libros por autor => '''getLibrosPorAutor'''. O código de ambas consultas xa estaba feito na UD3, no [https://wiki.cifprodolfoucha.es/index.php?title=PHP_UD3_OP_CONSULTA punto de operacións contra a base de datos]. | ||
| + | :* Obter os datos un libro en base ao seu id => '''getLibro($id)''' | ||
| + | :* Engadir un libro => '''altalibro''' | ||
| + | :* Actualizar os datos dun libro => '''update''' | ||
| + | :* Borrar un libro => '''delete''' | ||
| + | |||
| + | |||
| + | <br /> | ||
::<syntaxhighlight lang="java" enclose="div" highlight="" > | ::<syntaxhighlight lang="java" enclose="div" highlight="" > | ||
<?php | <?php | ||
| + | <?php | ||
| + | namespace modelos; | ||
| − | |||
| − | + | require_once(__DIR__ . '/../acceso_datos/database.php'); # => RUTA CON RESPECTO A ONDE SE ATOPA ESTE SCRIPT | |
| + | #require_once('../acceso_datos/database.php'); => RUTA RELATIVA CON RESPECTO A QUEN EXECUTA O SCRIPT (/var/www/html/public/index.php) | ||
use databases\Database; | use databases\Database; | ||
| Línea 576: | Línea 397: | ||
" where CONCAT(autores.nome,' ',autores.apelidos) like '%%%s%%' " . | " where CONCAT(autores.nome,' ',autores.apelidos) like '%%%s%%' " . | ||
'order by nome_autor,titulo'; | 'order by nome_autor,titulo'; | ||
| + | |||
| + | const CONSULTAR_LIBRO_POR_ID='select id,titulo from libros where id=%d'; | ||
| + | const ALTA_LIBRO = "INSERT INTO libros (titulo) VALUES ('%s')"; | ||
| + | const MODIFICAR_LIBRO="update libros set titulo='%s' where id=%d"; | ||
| + | const BAIXA_LIBRO="delete from libros where id=%d"; | ||
| − | public $id; | + | public int $id; |
| − | public $titulo; | + | public string $titulo; |
| − | function __construct($id,$titulo){ | + | function __construct(int $id,string $titulo){ |
$this->id = $id; | $this->id = $id; | ||
$this->titulo = $titulo; | $this->titulo = $titulo; | ||
} | } | ||
| − | public static function getLibros(){ | + | public static function getLibros(): array { |
$listaLibros = []; | $listaLibros = []; | ||
$db = Database::obterConexion(); // Por se facemos transaccions | $db = Database::obterConexion(); // Por se facemos transaccions | ||
| Línea 595: | Línea 421: | ||
return $listaLibros; | return $listaLibros; | ||
} | } | ||
| + | public static function getLibro($id): Libro { | ||
| + | |||
| + | $db = Database::obterConexion(); // Por se facemos transaccions | ||
| − | public static function getLibrosPorAutor($autor){ | + | $consulta = sprintf(Libro::CONSULTAR_LIBRO_POR_ID,$id); |
| + | |||
| + | $resultado = Database::executarSQL($consulta); | ||
| + | $fila = $resultado->fetch_assoc(); | ||
| + | $libro = new Libro($fila['id'],$fila['titulo']); | ||
| + | |||
| + | return $libro; // Devolve un único libro | ||
| + | } | ||
| + | |||
| + | public static function getLibrosPorAutor($autor): array{ | ||
$listaLibros = []; | $listaLibros = []; | ||
$db = Database::obterConexion(); // Por se facemos transaccions | $db = Database::obterConexion(); // Por se facemos transaccions | ||
| − | $consulta = sprintf(Libro::CONSULTAR_LIBROS_POR_AUTOR,$autor); | + | $consulta = sprintf(Libro::CONSULTAR_LIBROS_POR_AUTOR,$db->real_escape_string(($autor)); |
$resultado = Database::executarSQL($consulta); | $resultado = Database::executarSQL($consulta); | ||
while($fila = $resultado->fetch_assoc()) { | while($fila = $resultado->fetch_assoc()) { | ||
| Línea 608: | Línea 446: | ||
} | } | ||
| + | public static function altaLibro($libro): void{ | ||
| + | |||
| + | try{ | ||
| + | $db = Database::obterConexion(); // Por se facemos transaccions | ||
| + | $consulta = sprintf(Libro::ALTA_LIBRO,$db->real_escape_string($libro->titulo)); | ||
| + | $resultado = Database::executarSQL($consulta); | ||
| + | } | ||
| + | catch (\mysqli_sql_exception $e) { | ||
| + | error_log("Error al insertar libro: " . $e->getMessage()); | ||
| + | return -1; | ||
| + | } | ||
| + | |||
| + | return $db->insert_id; | ||
| + | } | ||
| + | public static function update($libro): int{ | ||
| + | |||
| + | try{ | ||
| + | $db = Database::obterConexion(); // Por se facemos transaccions | ||
| + | $consulta = sprintf(Libro::MODIFICAR_LIBRO,$db->real_escape_string($libro->titulo),$libro->id); | ||
| + | $resultado = Database::executarSQL($consulta); | ||
| + | } | ||
| + | catch (\mysqli_sql_exception $e) { | ||
| + | error_log("Error al actualizar libro: " . $e->getMessage()); | ||
| + | return -1; | ||
| + | } | ||
| + | |||
| + | return $resultado; | ||
| + | } | ||
| + | public static function delete($id): int{ | ||
| + | |||
| + | try{ | ||
| + | $db = Database::obterConexion(); // Por se facemos transaccions | ||
| + | $consulta = sprintf(Libro::BAIXA_LIBRO,$id); | ||
| + | $resultado = Database::executarSQL($consulta); | ||
| + | } | ||
| + | catch (\mysqli_sql_exception $e) { | ||
| + | error_log("Error al borrarlibro: " . $e->getMessage()); | ||
| + | return -1; | ||
| + | } | ||
| + | |||
| + | return $resultado; | ||
| + | } | ||
} | } | ||
| Línea 615: | Línea 495: | ||
<br /> | <br /> | ||
| + | |||
====Vistas==== | ====Vistas==== | ||
* No cartafol /var/www/vistas creamos a páxina: | * No cartafol /var/www/vistas creamos a páxina: | ||
:* '''listado_libros.php''': Amosará o listado de libros e fará que cada libro sexa un enlace a unha páxina de detalle (a páxina non está feita) | :* '''listado_libros.php''': Amosará o listado de libros e fará que cada libro sexa un enlace a unha páxina de detalle (a páxina non está feita) | ||
:* '''listado_libros_por_autor.php''': Amosará o listado de libros por autor. A mesma páxina xa ten un input onde escribir o nome do autor a buscar. | :* '''listado_libros_por_autor.php''': Amosará o listado de libros por autor. A mesma páxina xa ten un input onde escribir o nome do autor a buscar. | ||
| + | :* '''alta_libro.php''': Amosará o formulario para dar de alta a un libro. | ||
| + | :* '''editar_libro.php''': Amosar o formulario para modificar os datos dun libro. | ||
| − | '''Páxina listado_libros.php''' | + | |
| + | |||
| + | |||
| + | |||
| + | <br /> | ||
| + | '''Páxina listado_libros.php''': | ||
| + | Esta páxina a maiores de listar os libros | ||
| + | :* Crea un formulario por cada libro e un botón Eliminar asociado para que cando se preme nel, se envíe a url index.php?paxina=borrarlibro o id do libro a borrar. | ||
| + | :* Tamén ten un enlace <a href=index.php?paxina=editarlibro?id=NUMERO> para que cando prememos nun libro carga o formulario para poder modificar os datos. | ||
| + | :* Ao final de todo ten un enlace <a href=index.php?paxina=altalibro> para cargar o formulario de alta de libro. | ||
| + | |||
::<syntaxhighlight lang="java" enclose="div" highlight="" > | ::<syntaxhighlight lang="java" enclose="div" highlight="" > | ||
<!DOCTYPE html> | <!DOCTYPE html> | ||
<html lang="en"> | <html lang="en"> | ||
| + | |||
<head> | <head> | ||
<meta charset="UTF-8"> | <meta charset="UTF-8"> | ||
| Línea 629: | Línea 523: | ||
<title>Listado de libros</title> | <title>Listado de libros</title> | ||
</head> | </head> | ||
| + | |||
<body> | <body> | ||
<h1>Listado de libros</h1> | <h1>Listado de libros</h1> | ||
<ul> | <ul> | ||
| − | + | <?php | |
| − | + | if (count($libros) == 0) { | |
| − | + | printf("<h5>SEN LIBROS</h5>"); | |
| − | + | } else { | |
| − | + | foreach ($libros as $libro) { | |
| − | + | printf( | |
| − | + | "<li>%s - | |
| + | <a href='%s?paxina=editarlibro&id=%d'>Editar</a> | | ||
| + | <form action='%s?paxina=borrarlibro' method='POST' style='display:inline;'> | ||
| + | <input type='hidden' name='id' value='%d'> | ||
| + | <button type='submit' onclick='return confirm(\"¿Seguro que quieres eliminar este libro?\");'>Eliminar</button> | ||
| + | </form> | ||
| + | </li>", | ||
| + | htmlentities($libro->titulo), | ||
| + | htmlentities($_SERVER['PHP_SELF']), | ||
| + | $libro->id, | ||
| + | htmlentities($_SERVER['PHP_SELF']), | ||
| + | $libro->id | ||
| + | ); | ||
| + | } | ||
} | } | ||
| − | + | ?> | |
| − | |||
</ul> | </ul> | ||
| + | <div> | ||
| + | <a href="<?php echo htmlspecialchars($_SERVER['PHP_SELF']); ?>?paxina=altalibro">Alta Liibro</a> | ||
| + | </div> | ||
</body> | </body> | ||
| + | |||
</html> | </html> | ||
</syntaxhighlight> | </syntaxhighlight> | ||
| Línea 677: | Línea 588: | ||
printf("<ul>"); | printf("<ul>"); | ||
foreach($libros as $libro){ | foreach($libros as $libro){ | ||
| − | printf("<li><a href='index.php?paxina=detallelibro&id=%d'>%s</a></li>",$libro->id,$libro->titulo); | + | printf("<li><a href='index.php?paxina=detallelibro&id=%d'>%s</a></li>",$libro->id,htmlentities($libro->titulo)); |
} | } | ||
printf("</ul>"); | printf("</ul>"); | ||
| Línea 695: | Línea 606: | ||
<br /> | <br /> | ||
| + | '''Paxina alta_libro.php''': | ||
| + | Cando se preme o botón de alta, se envía no $_POST o titulo do novo libro. | ||
| + | |||
| + | ::<syntaxhighlight lang="java" enclose="div" highlight="" > | ||
| + | <!DOCTYPE html> | ||
| + | <html lang="en"> | ||
| + | <head> | ||
| + | <meta charset="UTF-8"> | ||
| + | <meta name="viewport" content="width=device-width, initial-scale=1.0"> | ||
| + | <title>Listado de libros</title> | ||
| + | </head> | ||
| + | <body> | ||
| + | <h1>Alta de libro</h1> | ||
| + | |||
| + | |||
| + | <form action="<?php echo htmlspecialchars($_SERVER['PHP_SELF']); ?>?paxina=altalibro" method="post"> | ||
| + | <label for="texto">Introduce un texto:</label><br> | ||
| + | <input type="text" id="titulo" name="titulo" maxlength="300" required> | ||
| + | <br><br> | ||
| + | <button type="submit">Enviar</button> | ||
| + | <button type="reset">Limpar</button> | ||
| + | </form> | ||
| + | |||
| + | </body> | ||
| + | </html> | ||
| + | </syntaxhighlight> | ||
| + | |||
| + | |||
| + | |||
| + | |||
| + | <br /> | ||
| + | '''Paxina editar_libro.php''': | ||
| + | Cando se preme o botón de modificar, se envía no $_POST o titulo modificado do libro e nun campo oculto o id do libro que foi modificado. | ||
| + | |||
| + | ::<syntaxhighlight lang="java" enclose="div" highlight="" > | ||
| + | <!DOCTYPE html> | ||
| + | <html lang="en"> | ||
| + | <head> | ||
| + | <meta charset="UTF-8"> | ||
| + | <meta name="viewport" content="width=device-width, initial-scale=1.0"> | ||
| + | <title>Listado de libros</title> | ||
| + | </head> | ||
| + | <body> | ||
| + | <h1>Editar libro</h1> | ||
| + | |||
| + | |||
| + | <form action="<?php echo htmlspecialchars($_SERVER['PHP_SELF']); ?>?paxina=editarlibro" method="post"> | ||
| + | <input type='hidden' value="<?php echo $libro->id;?>" name='id'> | ||
| + | <label for="texto">Introduce un texto:</label><br> | ||
| + | <input type="text" id="titulo" name="titulo" maxlength="300" required value="<?php echo htmlentities($libro->titulo); ?>"> | ||
| + | <br><br> | ||
| + | <button type="submit">Modificar</button> | ||
| + | <button type="reset">Limpar</button> | ||
| + | </form> | ||
| + | |||
| + | </body> | ||
| + | </html> | ||
| + | </syntaxhighlight> | ||
| + | |||
| + | |||
| + | |||
| + | |||
| + | <br /> | ||
| + | |||
====Controlador==== | ====Controlador==== | ||
| − | * No cartafol /var/www/controladores creamos a páxina ''' | + | * No cartafol /var/www/controladores creamos a páxina '''LibroController.php'''. |
::<syntaxhighlight lang="java" enclose="div" highlight="" > | ::<syntaxhighlight lang="java" enclose="div" highlight="" > | ||
| − | |||
| − | namespace | + | <?php |
| + | |||
| + | namespace controladores; | ||
| + | |||
| + | require_once(__DIR__ . '/../modelos/Libro.php'); # => RUTA CON RESPECTO A ONDE SE ATOPA ESTE SCRIPT | ||
| + | #require_once('../modelos/Libro.php'); => RUTA RELATIVA CON RESPECTO A QUEN EXECUTA O SCRIPT (/var/www/html/public/index.php) | ||
| + | |||
| − | |||
use modelos\Libro; | use modelos\Libro; | ||
class LibroController{ | class LibroController{ | ||
| − | public static function listarLibros(){ | + | public static function listarLibros(): void { |
$libros = Libro::getLibros(); | $libros = Libro::getLibros(); | ||
| − | + | require_once(__DIR__ . "/../vistas/listado_libros.php"); # => RUTA CON RESPECTO A ONDE SE ATOPA ESTE SCRIPT | |
| + | #require_once('../vistas/listado_libros.php'); => RUTA RELATIVA CON RESPECTO A QUEN EXECUTA O SCRIPT (/var/www/html/public/index.php) | ||
} | } | ||
| − | public static function listarLibrosPorAutor($autor){ | + | public static function listarLibrosPorAutor(string $autor): void{ |
if ($autor!=null) { | if ($autor!=null) { | ||
| Línea 719: | Línea 699: | ||
} | } | ||
| − | + | require_once(__DIR__ . "/../vistas/listado_libros_por_autor.php"); # => RUTA CON RESPECTO A ONDE SE ATOPA ESTE SCRIPT | |
| + | #require_once('../vistas/listado_libros_por_autor.php'); => RUTA RELATIVA CON RESPECTO A QUEN EXECUTA O SCRIPT (/var/www/html/public/index.php) | ||
| + | } | ||
| + | public static function create(array $datosFormulario): void{ | ||
| + | $titulo = filter_var($datosFormulario['titulo'], FILTER_SANITIZE_FULL_SPECIAL_CHARS, FILTER_FLAG_NO_ENCODE_QUOTES); | ||
| + | $libro = new Libro(-1,$titulo); | ||
| + | |||
| + | $id = Libro::altaLibro($libro); | ||
| + | |||
| + | header('Location:' . htmlspecialchars($_SERVER['PHP_SELF']).'?paxina=libros'); | ||
| + | } | ||
| + | |||
| + | |||
| + | public static function altalibro(): void{ | ||
| + | |||
| + | require_once(__DIR__ . "/../vistas/alta_libro.php"); | ||
| + | } | ||
| + | |||
| + | public static function editarLibro(array $datosFormulario): void { | ||
| + | $id = filter_var($datosFormulario['id'], FILTER_SANITIZE_NUMBER_INT); | ||
| + | $libro = Libro::getLibro($id); | ||
| + | |||
| + | require_once(__DIR__ . "/../vistas/editar_libro.php"); | ||
| + | } | ||
| + | |||
| + | public static function update(array $datosFormulario): void{ | ||
| + | // Atención: O id vai na URL. Se existe seguridade por usuario teríamos que comprobar se o usuario conectado ten permiso para modificar este libro | ||
| + | $id = filter_var($datosFormulario['id'], FILTER_SANITIZE_NUMBER_INT); | ||
| + | $titulo = filter_var($datosFormulario['titulo'], FILTER_SANITIZE_STRING); | ||
| + | $libro = new Libro($id,$titulo); | ||
| + | |||
| + | Libro::update($libro); | ||
| + | |||
| + | header('Location:' . htmlspecialchars($_SERVER['PHP_SELF']).'?paxina=libros'); | ||
| + | } | ||
| + | public static function destroy(array $datosFormulario): void { | ||
| + | $id = filter_var($datosFormulario['id'], FILTER_SANITIZE_STRING); | ||
| + | Libro::delete($id); | ||
| + | |||
| + | header('Location:' . htmlspecialchars($_SERVER['PHP_SELF']).'?paxina=libros'); | ||
} | } | ||
| Línea 725: | Línea 744: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
| − | : Esta clase será empregada por index.php para cargar os datos que queiramos (libros ou libros por autor) | + | : Esta clase será empregada por index.php para cargar os datos que queiramos (libros ou libros por autor) e facer todas as operacións sobre os libros (alta, modificación e baixa) |
: Fixarse que cando chamemos a listarLibros() se define a variable $libros que será empregada pola vista có include que estamos a facer. | : Fixarse que cando chamemos a listarLibros() se define a variable $libros que será empregada pola vista có include que estamos a facer. | ||
: No método listarLibrosPorAutor($autor) o $autor vai ser enviado dende index.php e vai ser o dato que ven en $_POST['txtAutor'] do formulario. A primeira vez que se carga, $autor terá o valor de null e por iso non carga os datos da base de datos. | : No método listarLibrosPorAutor($autor) o $autor vai ser enviado dende index.php e vai ser o dato que ven en $_POST['txtAutor'] do formulario. A primeira vez que se carga, $autor terá o valor de null e por iso non carga os datos da base de datos. | ||
| + | : No método altalibro cargamos a vista, é decir, o formulario para dar de alta a un novo libro. | ||
| + | : No método create recibimos de index o título do libro a dar de alta no $_POST. | ||
| + | : No método editarlibro cargamos a vista, é decir, o formulario para modificar os datos dun libro. De index ven o id do libro no $_GET. | ||
| + | : No método update recibimos de index o título do libro a modificar e o id do libro. Facemos a modificación na base de datos. Os datos veñen de index no $_POST. | ||
| + | : No método destroy bórrase o libro. O id do libro a borrar ven de $_GET dende o index. | ||
| + | |||
| + | |||
<br /> | <br /> | ||
| + | |||
====Controlador Frontal==== | ====Controlador Frontal==== | ||
* No cartafol /var/www/html/public creamos a páxina '''index.php'''. | * No cartafol /var/www/html/public creamos a páxina '''index.php'''. | ||
::<syntaxhighlight lang="java" enclose="div" highlight="" > | ::<syntaxhighlight lang="java" enclose="div" highlight="" > | ||
<?php | <?php | ||
| − | |||
| − | |||
| − | |||
| − | |||
| − | require_once('../controladores/LibroController.php'); | + | require_once(__DIR__ . "/../controladores/LibroController.php"); # => RUTA CON RESPECTO A ONDE SE ATOPA ESTE SCRIPT |
| − | use | + | #require_once('../controladores/LibroController.php'); => RUTA RELATIVA CON RESPECTO A QUEN EXECUTA O SCRIPT (/var/www/html/public/index.php) |
| + | |||
| + | use controladores\LibroController; | ||
if(!isset($_GET['paxina'])){ | if(!isset($_GET['paxina'])){ | ||
| − | die(('É necesario cargar unha páxina na url da forma paxina= | + | die(('É necesario cargar unha páxina na url da forma paxina=libros|libroautor|altalibro')); |
} | } | ||
switch($_GET['paxina']){ | switch($_GET['paxina']){ | ||
| − | case ' | + | case 'libros': |
LibroController::listarLibros(); | LibroController::listarLibros(); | ||
| Línea 760: | Línea 785: | ||
LibroController::listarLibrosPorAutor($autor); | LibroController::listarLibrosPorAutor($autor); | ||
| + | break; | ||
| + | case 'altalibro': | ||
| + | if(!empty($_POST)){ | ||
| + | $datosFormulario = $_POST; | ||
| + | LibroController::create($datosFormulario); | ||
| + | } | ||
| + | else { | ||
| + | LibroController::altalibro(); | ||
| + | } | ||
| + | |||
| + | break; | ||
| + | case 'editarlibro': | ||
| + | if(!empty($_POST)) { // Primeiro post xa que cando facemos o submit do formulario tamén veñen datos no $_GET | ||
| + | $datosFormulario = $_POST; | ||
| + | LibroController::update($datosFormulario); | ||
| + | } | ||
| + | elseif(!empty($_GET)){ // Vimos de pulsar un libro do listado. O id ven na URL | ||
| + | $datosFormulario = $_GET; | ||
| + | LibroController::editarLibro($datosFormulario); | ||
| + | } | ||
| + | |||
| + | break; | ||
| + | case 'borrarlibro': | ||
| + | if(!empty($_POST)){ | ||
| + | $datosFormulario = $_POST; | ||
| + | LibroController::destroy($datosFormulario); | ||
| + | } | ||
| + | |||
break; | break; | ||
default: | default: | ||
print("PAXINA NON PREPARADA"); | print("PAXINA NON PREPARADA"); | ||
} | } | ||
| − | |||
</syntaxhighlight> | </syntaxhighlight> | ||
| Línea 779: | Línea 831: | ||
| + | |||
| + | <br /> | ||
| + | |||
| + | == Uso de 'modelos' nas páxinas cliente == | ||
| + | |||
| + | * Analizando as páxinas que se amosan ao cliente, é dicir, as páxinas que conteñen código HTML que vai visualizar o cliente (o que veñen ser as vistas no MVC) , podemos empregar o que se chaman 'modelos' para o sitio web. | ||
| + | : Normalmente todas as páxinas terán a mesma estrutura de bloques (cabeceira, menús, contido), polo que, en vez de repetir o código en todas elas, poderíamos empregar un modelo que sexa utilizado en todas. | ||
| + | |||
| + | |||
| + | ==== Opción 1 ==== | ||
| + | |||
| + | * Unha forma sería utilizar arquivos de include para cada bloque, da forma (aplicado ao exemplo anterior): | ||
| + | |||
| + | '''Arquivo:MeuSitio.css''': Arquivo de css que será aplicado a todas as páxinas do sitio web. Defínense o aspecto e tamaño de cada bloque que conforma o sitio web. | ||
| + | ::<syntaxhighlight lang="java" enclose="div" highlight="" > | ||
| + | #cabecera{ | ||
| + | |||
| + | width:100%; | ||
| + | height:25%; | ||
| + | margin:0px auto; | ||
| + | text-align: center; | ||
| + | background-color: blue; | ||
| + | |||
| + | } | ||
| + | |||
| + | #menus{ | ||
| + | float:left; | ||
| + | height:5%; | ||
| + | background-color: red; | ||
| + | font-weight: bold; | ||
| + | color: yellow; | ||
| + | } | ||
| + | |||
| + | #contido{ | ||
| + | clear:both; | ||
| + | width:100%; | ||
| + | background-color: green; | ||
| + | |||
| + | |||
| + | } | ||
| + | </syntaxhighlight> | ||
| + | |||
| + | |||
| + | '''Arquivo:Cabecera.php''': Cabeceira do sitio web. Podería ter código PHP. | ||
| + | ::<syntaxhighlight lang="java" enclose="div" highlight="" > | ||
| + | <div id='cabecera'>ISTO É A CABECEIRA DO NOSO SITIO WEB | ||
| + | <?php | ||
| + | echo "<p>Poderíamos engadir código php</p>"; | ||
| + | ?> | ||
| + | |||
| + | </div> | ||
| + | </syntaxhighlight> | ||
| + | |||
| + | |||
| + | |||
| + | '''Arquivo:Menu.php''': Arquivo que representa o zona de menús do sitio web. Podería ter código PHP. | ||
| + | ::<syntaxhighlight lang="java" enclose="div" highlight="" > | ||
| + | <div id='menus'> <!--Exemplo de menu. Os enlaces non funcionan--> | ||
| + | <a href='Inicial.php'>Incio</a> | ||
| + | <a href='Consulta_Libros.php'>Consultar Libros</a> | ||
| + | </div> | ||
| + | </syntaxhighlight> | ||
| + | |||
| + | |||
| + | '''Arquivo:Consultar_Libros.php''' | ||
| + | ::<syntaxhighlight lang="java" enclose="div" highlight="21-23,42" > | ||
| + | <?php | ||
| + | require('Database.php'); | ||
| + | |||
| + | $conex = Database::obterConexion(); | ||
| + | if ($conex->connect_error){ | ||
| + | die('Erro de Conexión (' . mysqli_connect_errno() . ') ' . mysqli_connect_error()); | ||
| + | } | ||
| + | ?> | ||
| + | |||
| + | |||
| + | <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" | ||
| + | "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> | ||
| + | <html xmlns="http://www.w3.org/1999/xhtml" lang="es" xml:lang="es"> | ||
| + | <head> | ||
| + | <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> | ||
| + | <title>Operacións BD</title> | ||
| + | <link href="MeuSitio.css" rel="stylesheet" /> | ||
| + | </head> | ||
| + | |||
| + | <body> | ||
| + | <?php include('Cabecera.php'); ?> | ||
| + | <?php include('Menu.php'); ?> | ||
| + | <div id='contido'> | ||
| + | <?php | ||
| + | |||
| + | $result=Database::executarSQL(Database::CONSULTAR_LIBROS); | ||
| + | if ($result && $result->num_rows>0){ | ||
| + | echo "<table border='1'>"; | ||
| + | while($row = $result->fetch_assoc()) { | ||
| + | echo '<tr>'; | ||
| + | printf("<td>%s</td>",$row["titulo"]); | ||
| + | echo '</tr>'; | ||
| + | } | ||
| + | echo '</table>'; | ||
| + | $result->free(); // Liberamos da memoria os recursos | ||
| + | } | ||
| + | else { | ||
| + | echo "Non hai datos que amosar!!!!"; | ||
| + | } | ||
| + | |||
| + | ?> | ||
| + | </div> | ||
| + | </body> | ||
| + | </html> | ||
| + | |||
| + | </syntaxhighlight> | ||
| + | |||
| + | |||
| + | |||
| + | |||
| + | ==== Opción 2 ==== | ||
| + | |||
| + | * En PHP temos outra forma de facer 'modelos' de páxinas. O procedemento é ao revés do feito no exemplo anterior. | ||
| + | : Cada páxina do noso sitio web estará formado por un 'modelo' de páxina (sería a páxina na que se definen os bloques) ao que se engade o contido específico da páxina a cargar. | ||
| + | |||
| + | : Para facelo desta forma temos que utilizar as funcións: | ||
| + | :* [http://php.net/manual/es/function.ob-start.php Función ob_start()]. | ||
| + | :* [http://php.net/manual/es/function.ob-get-clean.php Función ob_get_clean()]. | ||
| + | |||
| + | |||
| + | : Vexamos un exemplo: | ||
| + | '''Arquivo:Layout.php''': Vai ser a páxina 'modelo' de todas as páxinas do noso sitio web. | ||
| + | ::<syntaxhighlight lang="java" enclose="div" highlight="24" > | ||
| + | <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" | ||
| + | "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> | ||
| + | <html xmlns="http://www.w3.org/1999/xhtml" lang="es" xml:lang="es"> | ||
| + | <head> | ||
| + | <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> | ||
| + | <title>Optimizando sitio web</title> | ||
| + | <link href="MeuSitio.css" rel="stylesheet" /> | ||
| + | </head> | ||
| + | |||
| + | <body> | ||
| + | <div id='cabecera'>ISTO É A CABECEIRA DO NOSO SITIO WEB | ||
| + | <?php | ||
| + | echo "<p>Poderíamos engadir código php</p>"; | ||
| + | ?> | ||
| + | |||
| + | </div> | ||
| + | <div id='menus'> <!--Exemplo de menu. Os enlaces non funcionan--> | ||
| + | <a href='Inicial.php'>Incio</a> | ||
| + | <a href='Consulta_Libros.php'>Consultar Libros</a> | ||
| + | </div> | ||
| + | |||
| + | |||
| + | <div id='contido'> | ||
| + | <?php echo $contido ?> | ||
| + | </div> | ||
| + | |||
| + | </body> | ||
| + | |||
| + | </html> | ||
| + | </syntaxhighlight> | ||
| + | |||
| + | * Liña 24: Fixarse que o contido vai vir nunha variable de nome $contido | ||
| + | |||
| + | |||
| + | '''Arquivo:Consultar_Libros_Con_Modelo.php''': Esta sería a forma de cargar cada unha das páxinas. | ||
| + | ::<syntaxhighlight lang="java" enclose="div" highlight="1,28,30" > | ||
| + | <?php ob_start() ?> | ||
| + | |||
| + | <?php | ||
| + | |||
| + | require('Database.php'); | ||
| + | |||
| + | $conex = Database::obterConexion(); | ||
| + | if ($conex->connect_error){ | ||
| + | die('Erro de Conexión (' . mysqli_connect_errno() . ') ' . mysqli_connect_error()); | ||
| + | } | ||
| + | |||
| + | $result=Database::executarSQL(Database::CONSULTAR_LIBROS); | ||
| + | if ($result && $result->num_rows>0){ | ||
| + | echo "<table border='1'>"; | ||
| + | while($row = $result->fetch_assoc()) { | ||
| + | echo '<tr>'; | ||
| + | printf("<td>%s</td>",$row["titulo"]); | ||
| + | echo '</tr>'; | ||
| + | } | ||
| + | echo '</table>'; | ||
| + | $result->free(); // Liberamos da memoria os recursos | ||
| + | } | ||
| + | else { | ||
| + | echo "Non hai datos que amosar!!!!"; | ||
| + | } | ||
| + | |||
| + | ?> | ||
| + | <?php $contido = ob_get_clean() ?> | ||
| + | |||
| + | <?php include 'Layout.php' ?> | ||
| + | </syntaxhighlight> | ||
| + | |||
| + | * Liña 1,28: Utilizamos as funcións indicadas anteriormente. | ||
| + | : Estas funcións o que fan basicamente é que a saída que fagamos (echo, printf,...) non se mande ao navegador do usuario, se non que se garde nun 'buffer'. A función ob_get_clean() devolve o contido do buffer (no noso caso o gardamos na variable $contido) e limpa o buffer. | ||
| + | : Liña 29: Unha vez feito o anterior temos na variable $contido o resultado de executar o código PHP. Dita variable se utiliza na modelo 'Layout.php' para colocar o contido no seu sitio. | ||
| + | |||
| + | |||
| + | |||
| + | |||
| + | |||
| + | * Como vemos, a idea é ir separando aspectos funcionais do sitio web das páxinas que se amosan ao usuario. | ||
| + | : Aínda temos aspectos que mesturan aspectos do acceso a datos da presentación do usuario, como pode ser a validación de campos. | ||
| + | |||
| + | |||
| + | * O conxunto de validacións, xunto coas regras que poidamos ter para acceder aos datos da nosa base de datos conforman as ''' [https://es.wikipedia.org/wiki/L%C3%B3gica_de_negocio regras de negocio]'''. No MVC dita función atópase na capa de MODELO como veremos a continuación (unha capa vai ser unha ou varias clases que van ter unha función específica). | ||
| + | |||
| + | : Por exemplo, chamar a unha función que consultara os libros dun determinado autor. Dita función comprobaría previamente se o autor existe e,en caso de que o autor non exista, avisar a quen fixo a chamada. Esta función sería a encargada de facer a orde SQL contra a base de datos e devolvería un array de datos co resultado da chamada ou un código indicando que o autor non existe (regra de negocio). Tamén se encargaría de validar que o dato enviado (o autor a buscar) sexa do tipo e formato correcto (enviar o nome e apelidos, por exemplo). | ||
Revisión actual del 18:35 15 ene 2026
Sumario
Introdución
- Có que levamos visto ata o de agora xa podemos facer sitios webs en PHP, pero teremos certos problemas 'de mantemento' en caso de que o sitio sexa grande (con grande me refiro a unha cantidade alta de páxinas PHP).
- Isto é debido a que estamos a 'mesturar' aspectos, como por exemplo as funcións de acceso a datos (conexión e operacións) dentro das páxinas que van 'presentar' ao usuario a información.
- Imaxinemos como estamos a facer agora que queremos cambiar o acceso á base de datos e no canto de utilizar Mysql queremos usar SQLServer...
- Teríamos que ir a todas as páxinas cambiando as funcións de acceso a datos.
- Por outra banda, imaxinade que temos un equipo de persoas e queremos 'distribuír' o traballo en equipos.
- De tal forma que un equipo se encargue de 'maquetar' a información con CSS e HTML e outro que se adique a facer as chamadas á base de datos en busca de dita información.
- Esta labor non a poderíamos facer en 'paralelo' xa que a presentación de datos e o acceso aos mesmos se fan dentro da mesma páxina.
Melloras ao feito ata o de agora
- Clase para acceder a Mysql
- En primeiro lugar, poderíamos crear unha clase que se encargue da facer a conexión á base de datos e as operacións contra a mesma.
<?php class Database { const CONSULTAR_LIBROS='select id_libro,titulo from LIBROS order by titulo'; const SERVIDOR = 'localhost'; const USUARIO = 'user_php'; const PASSWORD = 'user_php'; const BD = 'PHP'; private static $db; private $conexion; private function __construct() { $this->conexion = new mysqli(self::SERVIDOR,self::USUARIO,self::PASSWORD,self::BD); $this->conexion->set_charset('utf8'); } function __destruct() { if(!$this->conexion) $this->conexion->close(); } public static function obterConexion() { if (self::$db == null) { self::$db = new Database(); } return self::$db->conexion; } public static function executarSQL($consulta) { $result=self::$db->conexion->query($consulta); return $result; } public static function executarProc($procedure) { if(self::$db->conexion->multi_query($procedure)){ $result[]=self::$db->conexion->store_result(); while(self::$db->conexion->next_result()){ $result[]= self::$db->conexion->store_result(); } return $result; } else{ return null; } } }
Nota: Lembrar que a clase anterior non tería que estar na estrutura de cartafol de acceso do Apache (en Linux sería /var/www/html/), como indicamos anteriormente na WIKI.
- Se aplicamos a clase anterior a unha das páxinas feitas durante este manual, por exemplo, a páxina que consulta os libros da táboa LIBROS:
<?php require('Database.php'); $conex = Database::obterConexion(); if ($conex->connect_error){ die('Erro de Conexión (' . mysqli_connect_errno() . ') ' . mysqli_connect_error()); } ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" lang="es" xml:lang="es"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <title>Operacións BD</title> </head> <body> <?php $result=Database::executarSQL(Database::CONSULTAR_LIBROS); if ($result && $result->num_rows>0){ echo "<table border='1'>"; while($row = $result->fetch_assoc()) { echo '<tr>'; printf("<td>%s</td>",$row["titulo"]); echo '</tr>'; } echo '</table>'; $result->free(); // Liberamos da memoria os recursos } else { echo "Non hai datos que amosar!!!!"; } ?> </body> </html>
- Poderíamos 'optimizar' un pouco máis e facer que a clase DataBase tamén incorpore os métodos que respondan ás peticións das páxinas, facendo que os métodos definidos devolvan xa un array cos datos.
- Desta forma, nesta clase, poderíamos poñer as regras de validación en caso de engadir datos, xunto cos procedementos que devolven ou xestionan a información que reciben dende as páxinas (regras de negocio)
- Aplicado ao exemplo anterior:
Arquivo: Database.php
<?php class Database { const CONSULTAR_LIBROS='select id_libro,titulo from LIBROS order by titulo'; const SERVIDOR = 'localhost'; const USUARIO = 'user_php'; const PASSWORD = 'user_php'; const BD = 'PHP'; private static $db; private $conexion; private function __construct() { $this->conexion = new mysqli(self::SERVIDOR,self::USUARIO,self::PASSWORD,self::BD); $this->conexion->set_charset('utf8'); } function __destruct() { $this->conexion->close(); } public static function obterConexion() { if (self::$db == null) { self::$db = new Database(); } return self::$db->conexion; } public static function executarSQL($consulta) { $result=self::$db->conexion->query($consulta); return $result; } public static function executarProc($procedure) { if(self::$db->conexion->multi_query($procedure)){ $result[]=self::$db->conexion->store_result(); while(self::$db->conexion->next_result()){ $result[]= self::$db->conexion->store_result(); } return $result; } else{ return null; } } public static function consultarLibros(){ $resultados=null; $result=Database::executarSQL(Database::CONSULTAR_LIBROS); if ($result && $result->num_rows>0){ while($row = $result->fetch_assoc()) { $resultados[]=$row; } $result->free(); // Liberamos da memoria os recursos } return $resultados; } }
Arquivo: Consultar_Libros.php
<?php require('Database.php'); $conex = Database::obterConexion(); if ($conex->connect_error){ die('Erro de Conexión (' . mysqli_connect_errno() . ') ' . mysqli_connect_error()); } ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" lang="es" xml:lang="es"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <title>Operacións BD</title> </head> <body> <?php $result=Database::consultarLibros(); if (!empty($result)){ echo "<table border='1'>"; foreach ($result as $fila){ echo '<tr>'; printf("<td>%s</td>",$fila["titulo"]); echo '</tr>'; } echo '</table>'; } else { echo "Non hai datos que amosar!!!!"; } ?> </body> </html> <?php ob_start() ?>
- Tamén poderíamos aplicar os conceptos da POO que aprendemos anteriormente na wiki e facer que a información que devolva a función 'consultarLibros' da clase Database, sexa un array de obxectos dunha clase definida previamente, que representaría a táboa LIBROS.
- No seguinte punto imos aprender como 'separar' en diferentes 'capas' a aplicación para que o mantemento do proxecto sexa moito máis doado.
Modelo-Vista-Controlador
- O visto nos puntos anteriores mellora moito a claridade e mantemento dos programas PHP, pero a forma correcta (polo menos en proxectos grandes) sería empregar o patrón de deseño MODELO-VISTA-CONTROLADOR.
- Basicamente se basa en dividir o proxecto PHP nas seguintes partes:
- MODELOS: Onde están definidas as clases que van acceder á base de datos (pode ser outra fonte de datos, pero imos simplificalo). Cada clase fará referencia a unha táboa da base de datos.
- A maiores dos atributos (columnas na táboa) terá gardado os métodos que irán contra a base de datos a facer operacións. Para acceder á base de datos farán uso dunha clase cos métodos que conectan contra a base de datos e executan as consultas/operacións.
- VISTAS: Son as páxinas con código HTML/Javascript que vai visualizar o usuario.
- CONTROLADORES: Son as páxinas que van recibir as peticións por parte del usuario e serán encargadas de buscar os datos (empregando o modelo) e devolver as vistas (empregando as vistas) cos datos obtidos.
- A maiores, teremos un controlador frontal que será o encargado de recibir a URL coas peticións de carga das páxinas e chamar ao controlador adeucado en base a dita URL.
- Veremos LARAVEL na UNIDADE_6:Programación de Servizos Web. Cando cheguedes a dita unidade xa teredes experiencia no manexo de Laravel para o desenvolvemento de aplicacións se fixéchedes as tarefas propostas no Moodle.
- Para entender mellor como funciona podedes consultar este exemplo.
Posta en práctica dun exemplo sinxelo empregando MVC
- Imos crear un proxecto PHP seguindo o patrón MVC aplicado ao exemplo da BD creada na UD3.
- Para iso imos crear a estrutura de cartafoles seguinte, supoñendo que o servidor web está apuntando a /var/www/html (lembrade dar os permisos adecuados para que o servidor web teña acceso):
- /var/www/acceso_datos: Onde vai ir a clase que se conecta á base de datos.
- /var/www/controladores: Onde vai ir as clases controladoras.
- /var/www/modelos: Onde van ir os modelos.
- /var/www/vistas: Onde van ir as vistas.
- /var/www/html/public: Onde vai ir a páxina controladora frontal. É a única á que van ter acceso os usuarios dende o navegador.
- Esta páxina vai ter o formato:
- index.php?paxina=libros => Entón cargará o que estea en ControladorLibro.php => getLibros
- index.php?paxina=libroautor => Entón cargará o que estea en ControladorLibro.php => getLibrosPorAutor
- index.php?paxina=altalibro => A esta páxina podemos chegar dende dous sitios diferentes. Ao premer no botón de alta libro amosaremos un formulario baleiro e cando prememos no botón ALTA, deberemos de chamar á base de datos cós datos do formulario para facer un insert. Diferenciaremos un ou outro en función se temos datos en $_POST (neste caso vimos do formulario para dar de alta). Chamaremos por tanto a dous métodos no controlador: altalibro cando queramos cargar o formulario e create cando queramos engadir os datos do libro á base de datos. Para simplificalo soamente se dará de alta na táboa Libro e non na de libro_autor.
- index.php?paxina=editarlibro => A esta páxina podemos chegar dende dous sitios diferentes. Ao seleccionar un libro cargaremos un formulario cós datos do libro seleccionado e cando prememos no botón Modificar, deberemos de chamar á base de datos cós datos do formulario para facer unha modificación. Diferenciaremos un ou outro en función se temos datos en $_POST (neste caso vimos do formulario). Chamaremos por tanto a dous métodos no controlador: editarLibro cando queramos cargar o formulario e update cando queramos modificar os datos do libro.
- index.php?paxina=borrarlibro => Entón cargará o que estea en ControladorLibro.php => destroy. O id do libro virá no $_POST
- Nota: Por simplificar non vou reutilizar o código das páxinas nin vou enviar o token csrf para protexer aos formularios, pero lembrade que o teriades que facer nun sitio web real.
- O páxina de alta e modificar teñen os mesmos contidos cambiando o action do formulario e no contido do botón que terá o texto Alta ou Modificar según o caso polo que se podería crear unha única vista.
- A idea é facer algo parecido a isto:

- NOTA: No exemplo, os include/require están empregando rutas relativas para que poidades probalo en calquera cartafol, pero nun sitio real deberíamos empregar $_SERVER['DOCUMENT_ROOT'].
Acceso a datos
- No cartafol /var/www/acceso_datos creamos a páxina database.php.
- O seu contido xa o vimos no punto anterior. É onde están definidas as constantes de conexión e os métodos que executan sentenzas contra a base de datos Mysql.
<?php namespace databases; use mysqli; // Necesario para que atopa a clase ao estar nun namespace Database class Database { const SERVIDOR = 'localhost'; const USUARIO = 'root'; const PASSWORD = 'root'; const BD = 'php'; private static $db; private $conexion; private function __construct() { $this->conexion = new mysqli(self::SERVIDOR,self::USUARIO,self::PASSWORD,self::BD); $this->conexion->set_charset('utf8'); } function __destruct() { if(!$this->conexion) $this->conexion->close(); } public static function obterConexion() { if (self::$db == null) { self::$db = new Database(); } return self::$db->conexion; } public static function executarSQL($consulta) { $result=self::$db->conexion->query($consulta); return $result; } public static function executarProc($procedure) { if(self::$db->conexion->multi_query($procedure)){ $result[]=self::$db->conexion->store_result(); while(self::$db->conexion->next_result()){ $result[]= self::$db->conexion->store_result(); } return $result; } else{ return null; } } }
Modelos
- No cartafol /var/www/modelos creamos a páxina Libro.php.
- Nesta clase estarán definidos todos os atributos e métodos relacionados coa clase. A maiores estarán os métodos que farán uso da clase DataBase e obterán os datos de facer as consultas.
- No noso exemplo, imos crear 6 métodos que van acceder á base de datos:
- Listado dos libros => getLibros
- Listado de libros por autor => getLibrosPorAutor. O código de ambas consultas xa estaba feito na UD3, no punto de operacións contra a base de datos.
- Obter os datos un libro en base ao seu id => getLibro($id)
- Engadir un libro => altalibro
- Actualizar os datos dun libro => update
- Borrar un libro => delete
<?php <?php namespace modelos; require_once(__DIR__ . '/../acceso_datos/database.php'); # => RUTA CON RESPECTO A ONDE SE ATOPA ESTE SCRIPT #require_once('../acceso_datos/database.php'); => RUTA RELATIVA CON RESPECTO A QUEN EXECUTA O SCRIPT (/var/www/html/public/index.php) use databases\Database; class Libro{ const CONSULTAR_LIBROS='select id,titulo from libros order by titulo'; const CONSULTAR_LIBROS_POR_AUTOR = "select CONCAT(apelidos,',',nome) as nome_autor,libros.id ,titulo from libros " . ' INNER JOIN libro_autor ON (libro_autor.libro_id=libros.id) ' . ' INNER JOIN autores ON (libro_autor.autor_id=autores.id)' . " where CONCAT(autores.nome,' ',autores.apelidos) like '%%%s%%' " . 'order by nome_autor,titulo'; const CONSULTAR_LIBRO_POR_ID='select id,titulo from libros where id=%d'; const ALTA_LIBRO = "INSERT INTO libros (titulo) VALUES ('%s')"; const MODIFICAR_LIBRO="update libros set titulo='%s' where id=%d"; const BAIXA_LIBRO="delete from libros where id=%d"; public int $id; public string $titulo; function __construct(int $id,string $titulo){ $this->id = $id; $this->titulo = $titulo; } public static function getLibros(): array { $listaLibros = []; $db = Database::obterConexion(); // Por se facemos transaccions $resultado = Database::executarSQL(Libro::CONSULTAR_LIBROS); while($fila = $resultado->fetch_assoc()) { $listaLibros[] = new Libro($fila['id'],$fila['titulo']); } return $listaLibros; } public static function getLibro($id): Libro { $db = Database::obterConexion(); // Por se facemos transaccions $consulta = sprintf(Libro::CONSULTAR_LIBRO_POR_ID,$id); $resultado = Database::executarSQL($consulta); $fila = $resultado->fetch_assoc(); $libro = new Libro($fila['id'],$fila['titulo']); return $libro; // Devolve un único libro } public static function getLibrosPorAutor($autor): array{ $listaLibros = []; $db = Database::obterConexion(); // Por se facemos transaccions $consulta = sprintf(Libro::CONSULTAR_LIBROS_POR_AUTOR,$db->real_escape_string(($autor)); $resultado = Database::executarSQL($consulta); while($fila = $resultado->fetch_assoc()) { $listaLibros[] = new Libro($fila['id'],$fila['titulo']); } return $listaLibros; } public static function altaLibro($libro): void{ try{ $db = Database::obterConexion(); // Por se facemos transaccions $consulta = sprintf(Libro::ALTA_LIBRO,$db->real_escape_string($libro->titulo)); $resultado = Database::executarSQL($consulta); } catch (\mysqli_sql_exception $e) { error_log("Error al insertar libro: " . $e->getMessage()); return -1; } return $db->insert_id; } public static function update($libro): int{ try{ $db = Database::obterConexion(); // Por se facemos transaccions $consulta = sprintf(Libro::MODIFICAR_LIBRO,$db->real_escape_string($libro->titulo),$libro->id); $resultado = Database::executarSQL($consulta); } catch (\mysqli_sql_exception $e) { error_log("Error al actualizar libro: " . $e->getMessage()); return -1; } return $resultado; } public static function delete($id): int{ try{ $db = Database::obterConexion(); // Por se facemos transaccions $consulta = sprintf(Libro::BAIXA_LIBRO,$id); $resultado = Database::executarSQL($consulta); } catch (\mysqli_sql_exception $e) { error_log("Error al borrarlibro: " . $e->getMessage()); return -1; } return $resultado; } }
Vistas
- No cartafol /var/www/vistas creamos a páxina:
- listado_libros.php: Amosará o listado de libros e fará que cada libro sexa un enlace a unha páxina de detalle (a páxina non está feita)
- listado_libros_por_autor.php: Amosará o listado de libros por autor. A mesma páxina xa ten un input onde escribir o nome do autor a buscar.
- alta_libro.php: Amosará o formulario para dar de alta a un libro.
- editar_libro.php: Amosar o formulario para modificar os datos dun libro.
Páxina listado_libros.php:
Esta páxina a maiores de listar os libros
- Crea un formulario por cada libro e un botón Eliminar asociado para que cando se preme nel, se envíe a url index.php?paxina=borrarlibro o id do libro a borrar.
- Tamén ten un enlace <a href=index.php?paxina=editarlibro?id=NUMERO> para que cando prememos nun libro carga o formulario para poder modificar os datos.
- Ao final de todo ten un enlace <a href=index.php?paxina=altalibro> para cargar o formulario de alta de libro.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Listado de libros</title> </head> <body> <h1>Listado de libros</h1> <ul> <?php if (count($libros) == 0) { printf("<h5>SEN LIBROS</h5>"); } else { foreach ($libros as $libro) { printf( "<li>%s - <a href='%s?paxina=editarlibro&id=%d'>Editar</a> | <form action='%s?paxina=borrarlibro' method='POST' style='display:inline;'> <input type='hidden' name='id' value='%d'> <button type='submit' onclick='return confirm(\"¿Seguro que quieres eliminar este libro?\");'>Eliminar</button> </form> </li>", htmlentities($libro->titulo), htmlentities($_SERVER['PHP_SELF']), $libro->id, htmlentities($_SERVER['PHP_SELF']), $libro->id ); } } ?> </ul> <div> <a href="<?php echo htmlspecialchars($_SERVER['PHP_SELF']); ?>?paxina=altalibro">Alta Liibro</a> </div> </body> </html>
- Como vedes é moi sinxela. Vai recibir unha variable de nome $libros que estará definida no controlador. Dita variable vai ser unha lista de obxectos Libros.
Paxina listado_libros_por_autor.php:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Listado de libros</title> </head> <body> <form action="<?php echo htmlentities($_SERVER['PHP_SELF']) ?>?paxina=libroautor" method='post' > BUSCAR POR AUTOR:<input type='text' size='50' maxlength="100" required name="txtAutor" /> </form> <?php if(isset($libros)) { printf("<h1>Listado de libros</h1>"); if(count($libros)==0){ printf("<h5>SEN LIBROS CON ESE AUTOR</h5>"); } else{ printf("<ul>"); foreach($libros as $libro){ printf("<li><a href='index.php?paxina=detallelibro&id=%d'>%s</a></li>",$libro->id,htmlentities($libro->titulo)); } printf("</ul>"); } } ?> </body> </html>
- Nesta páxina o concepto é o mesmo que na anterior. Vai recibir do controlador un conxunto de obxectos da clase Libros. Soamente os amosará se existe a variable $libros. Se non existe quere dicir que cargamos a páxina por primeira vez e que non debe amosar o resultado de buscar.
- Se buscamos por algo, chamamos á mesma páxina index.php indicando a páxina que queremos cargar e enviando o nome do autor en $_POST['txtAutor'].
Paxina alta_libro.php:
Cando se preme o botón de alta, se envía no $_POST o titulo do novo libro.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Listado de libros</title> </head> <body> <h1>Alta de libro</h1> <form action="<?php echo htmlspecialchars($_SERVER['PHP_SELF']); ?>?paxina=altalibro" method="post"> <label for="texto">Introduce un texto:</label><br> <input type="text" id="titulo" name="titulo" maxlength="300" required> <br><br> <button type="submit">Enviar</button> <button type="reset">Limpar</button> </form> </body> </html>
Paxina editar_libro.php:
Cando se preme o botón de modificar, se envía no $_POST o titulo modificado do libro e nun campo oculto o id do libro que foi modificado.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Listado de libros</title> </head> <body> <h1>Editar libro</h1> <form action="<?php echo htmlspecialchars($_SERVER['PHP_SELF']); ?>?paxina=editarlibro" method="post"> <input type='hidden' value="<?php echo $libro->id;?>" name='id'> <label for="texto">Introduce un texto:</label><br> <input type="text" id="titulo" name="titulo" maxlength="300" required value="<?php echo htmlentities($libro->titulo); ?>"> <br><br> <button type="submit">Modificar</button> <button type="reset">Limpar</button> </form> </body> </html>
Controlador
- No cartafol /var/www/controladores creamos a páxina LibroController.php.
<?php namespace controladores; require_once(__DIR__ . '/../modelos/Libro.php'); # => RUTA CON RESPECTO A ONDE SE ATOPA ESTE SCRIPT #require_once('../modelos/Libro.php'); => RUTA RELATIVA CON RESPECTO A QUEN EXECUTA O SCRIPT (/var/www/html/public/index.php) use modelos\Libro; class LibroController{ public static function listarLibros(): void { $libros = Libro::getLibros(); require_once(__DIR__ . "/../vistas/listado_libros.php"); # => RUTA CON RESPECTO A ONDE SE ATOPA ESTE SCRIPT #require_once('../vistas/listado_libros.php'); => RUTA RELATIVA CON RESPECTO A QUEN EXECUTA O SCRIPT (/var/www/html/public/index.php) } public static function listarLibrosPorAutor(string $autor): void{ if ($autor!=null) { $autor = htmlentities($autor); $libros = Libro::getLibrosPorAutor($autor); } require_once(__DIR__ . "/../vistas/listado_libros_por_autor.php"); # => RUTA CON RESPECTO A ONDE SE ATOPA ESTE SCRIPT #require_once('../vistas/listado_libros_por_autor.php'); => RUTA RELATIVA CON RESPECTO A QUEN EXECUTA O SCRIPT (/var/www/html/public/index.php) } public static function create(array $datosFormulario): void{ $titulo = filter_var($datosFormulario['titulo'], FILTER_SANITIZE_FULL_SPECIAL_CHARS, FILTER_FLAG_NO_ENCODE_QUOTES); $libro = new Libro(-1,$titulo); $id = Libro::altaLibro($libro); header('Location:' . htmlspecialchars($_SERVER['PHP_SELF']).'?paxina=libros'); } public static function altalibro(): void{ require_once(__DIR__ . "/../vistas/alta_libro.php"); } public static function editarLibro(array $datosFormulario): void { $id = filter_var($datosFormulario['id'], FILTER_SANITIZE_NUMBER_INT); $libro = Libro::getLibro($id); require_once(__DIR__ . "/../vistas/editar_libro.php"); } public static function update(array $datosFormulario): void{ // Atención: O id vai na URL. Se existe seguridade por usuario teríamos que comprobar se o usuario conectado ten permiso para modificar este libro $id = filter_var($datosFormulario['id'], FILTER_SANITIZE_NUMBER_INT); $titulo = filter_var($datosFormulario['titulo'], FILTER_SANITIZE_STRING); $libro = new Libro($id,$titulo); Libro::update($libro); header('Location:' . htmlspecialchars($_SERVER['PHP_SELF']).'?paxina=libros'); } public static function destroy(array $datosFormulario): void { $id = filter_var($datosFormulario['id'], FILTER_SANITIZE_STRING); Libro::delete($id); header('Location:' . htmlspecialchars($_SERVER['PHP_SELF']).'?paxina=libros'); } }
- Esta clase será empregada por index.php para cargar os datos que queiramos (libros ou libros por autor) e facer todas as operacións sobre os libros (alta, modificación e baixa)
- Fixarse que cando chamemos a listarLibros() se define a variable $libros que será empregada pola vista có include que estamos a facer.
- No método listarLibrosPorAutor($autor) o $autor vai ser enviado dende index.php e vai ser o dato que ven en $_POST['txtAutor'] do formulario. A primeira vez que se carga, $autor terá o valor de null e por iso non carga os datos da base de datos.
- No método altalibro cargamos a vista, é decir, o formulario para dar de alta a un novo libro.
- No método create recibimos de index o título do libro a dar de alta no $_POST.
- No método editarlibro cargamos a vista, é decir, o formulario para modificar os datos dun libro. De index ven o id do libro no $_GET.
- No método update recibimos de index o título do libro a modificar e o id do libro. Facemos a modificación na base de datos. Os datos veñen de index no $_POST.
- No método destroy bórrase o libro. O id do libro a borrar ven de $_GET dende o index.
Controlador Frontal
- No cartafol /var/www/html/public creamos a páxina index.php.
<?php require_once(__DIR__ . "/../controladores/LibroController.php"); # => RUTA CON RESPECTO A ONDE SE ATOPA ESTE SCRIPT #require_once('../controladores/LibroController.php'); => RUTA RELATIVA CON RESPECTO A QUEN EXECUTA O SCRIPT (/var/www/html/public/index.php) use controladores\LibroController; if(!isset($_GET['paxina'])){ die(('É necesario cargar unha páxina na url da forma paxina=libros|libroautor|altalibro')); } switch($_GET['paxina']){ case 'libros': LibroController::listarLibros(); break; case 'libroautor': $autor = $_POST['txtAutor'] ?? null; // Operador que devolve null se $_POST[txtAutor] non existe. Poderíamos empregar isset //if(!isset($_POST['txtAutor'])) $autor = null; //else $autor = $_POST['txtAutor']; LibroController::listarLibrosPorAutor($autor); break; case 'altalibro': if(!empty($_POST)){ $datosFormulario = $_POST; LibroController::create($datosFormulario); } else { LibroController::altalibro(); } break; case 'editarlibro': if(!empty($_POST)) { // Primeiro post xa que cando facemos o submit do formulario tamén veñen datos no $_GET $datosFormulario = $_POST; LibroController::update($datosFormulario); } elseif(!empty($_GET)){ // Vimos de pulsar un libro do listado. O id ven na URL $datosFormulario = $_GET; LibroController::editarLibro($datosFormulario); } break; case 'borrarlibro': if(!empty($_POST)){ $datosFormulario = $_POST; LibroController::destroy($datosFormulario); } break; default: print("PAXINA NON PREPARADA"); }
Máis información MVC
Uso de 'modelos' nas páxinas cliente
- Analizando as páxinas que se amosan ao cliente, é dicir, as páxinas que conteñen código HTML que vai visualizar o cliente (o que veñen ser as vistas no MVC) , podemos empregar o que se chaman 'modelos' para o sitio web.
- Normalmente todas as páxinas terán a mesma estrutura de bloques (cabeceira, menús, contido), polo que, en vez de repetir o código en todas elas, poderíamos empregar un modelo que sexa utilizado en todas.
Opción 1
- Unha forma sería utilizar arquivos de include para cada bloque, da forma (aplicado ao exemplo anterior):
Arquivo:MeuSitio.css: Arquivo de css que será aplicado a todas as páxinas do sitio web. Defínense o aspecto e tamaño de cada bloque que conforma o sitio web.
#cabecera{ width:100%; height:25%; margin:0px auto; text-align: center; background-color: blue; } #menus{ float:left; height:5%; background-color: red; font-weight: bold; color: yellow; } #contido{ clear:both; width:100%; background-color: green; }
Arquivo:Cabecera.php: Cabeceira do sitio web. Podería ter código PHP.
<div id='cabecera'>ISTO É A CABECEIRA DO NOSO SITIO WEB <?php echo "<p>Poderíamos engadir código php</p>"; ?> </div>
Arquivo:Menu.php: Arquivo que representa o zona de menús do sitio web. Podería ter código PHP.
<div id='menus'> <!--Exemplo de menu. Os enlaces non funcionan--> <a href='Inicial.php'>Incio</a> <a href='Consulta_Libros.php'>Consultar Libros</a> </div>
Arquivo:Consultar_Libros.php
<?php require('Database.php'); $conex = Database::obterConexion(); if ($conex->connect_error){ die('Erro de Conexión (' . mysqli_connect_errno() . ') ' . mysqli_connect_error()); } ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" lang="es" xml:lang="es"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <title>Operacións BD</title> <link href="MeuSitio.css" rel="stylesheet" /> </head> <body> <?php include('Cabecera.php'); ?> <?php include('Menu.php'); ?> <div id='contido'> <?php $result=Database::executarSQL(Database::CONSULTAR_LIBROS); if ($result && $result->num_rows>0){ echo "<table border='1'>"; while($row = $result->fetch_assoc()) { echo '<tr>'; printf("<td>%s</td>",$row["titulo"]); echo '</tr>'; } echo '</table>'; $result->free(); // Liberamos da memoria os recursos } else { echo "Non hai datos que amosar!!!!"; } ?> </div> </body> </html>
Opción 2
- En PHP temos outra forma de facer 'modelos' de páxinas. O procedemento é ao revés do feito no exemplo anterior.
- Cada páxina do noso sitio web estará formado por un 'modelo' de páxina (sería a páxina na que se definen os bloques) ao que se engade o contido específico da páxina a cargar.
- Para facelo desta forma temos que utilizar as funcións:
- Vexamos un exemplo:
Arquivo:Layout.php: Vai ser a páxina 'modelo' de todas as páxinas do noso sitio web.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" lang="es" xml:lang="es"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <title>Optimizando sitio web</title> <link href="MeuSitio.css" rel="stylesheet" /> </head> <body> <div id='cabecera'>ISTO É A CABECEIRA DO NOSO SITIO WEB <?php echo "<p>Poderíamos engadir código php</p>"; ?> </div> <div id='menus'> <!--Exemplo de menu. Os enlaces non funcionan--> <a href='Inicial.php'>Incio</a> <a href='Consulta_Libros.php'>Consultar Libros</a> </div> <div id='contido'> <?php echo $contido ?> </div> </body> </html>
- Liña 24: Fixarse que o contido vai vir nunha variable de nome $contido
Arquivo:Consultar_Libros_Con_Modelo.php: Esta sería a forma de cargar cada unha das páxinas.
<?php ob_start() ?> <?php require('Database.php'); $conex = Database::obterConexion(); if ($conex->connect_error){ die('Erro de Conexión (' . mysqli_connect_errno() . ') ' . mysqli_connect_error()); } $result=Database::executarSQL(Database::CONSULTAR_LIBROS); if ($result && $result->num_rows>0){ echo "<table border='1'>"; while($row = $result->fetch_assoc()) { echo '<tr>'; printf("<td>%s</td>",$row["titulo"]); echo '</tr>'; } echo '</table>'; $result->free(); // Liberamos da memoria os recursos } else { echo "Non hai datos que amosar!!!!"; } ?> <?php $contido = ob_get_clean() ?> <?php include 'Layout.php' ?>
- Liña 1,28: Utilizamos as funcións indicadas anteriormente.
- Estas funcións o que fan basicamente é que a saída que fagamos (echo, printf,...) non se mande ao navegador do usuario, se non que se garde nun 'buffer'. A función ob_get_clean() devolve o contido do buffer (no noso caso o gardamos na variable $contido) e limpa o buffer.
- Liña 29: Unha vez feito o anterior temos na variable $contido o resultado de executar o código PHP. Dita variable se utiliza na modelo 'Layout.php' para colocar o contido no seu sitio.
- Como vemos, a idea é ir separando aspectos funcionais do sitio web das páxinas que se amosan ao usuario.
- Aínda temos aspectos que mesturan aspectos do acceso a datos da presentación do usuario, como pode ser a validación de campos.
- O conxunto de validacións, xunto coas regras que poidamos ter para acceder aos datos da nosa base de datos conforman as regras de negocio. No MVC dita función atópase na capa de MODELO como veremos a continuación (unha capa vai ser unha ou varias clases que van ter unha función específica).
- Por exemplo, chamar a unha función que consultara os libros dun determinado autor. Dita función comprobaría previamente se o autor existe e,en caso de que o autor non exista, avisar a quen fixo a chamada. Esta función sería a encargada de facer a orde SQL contra a base de datos e devolvería un array de datos co resultado da chamada ou un código indicando que o autor non existe (regra de negocio). Tamén se encargaría de validar que o dato enviado (o autor a buscar) sexa do tipo e formato correcto (enviar o nome e apelidos, por exemplo).
-- Ángel D. Fernández González -- (2024).