

Investiga qué otros framworks utiliza este paradigma.
El patrón **Modelo-Vista-Controlador (MVC)** es una arquitectura de software que se utiliza para separar la lógica de negocio de la presentación en aplicaciones web . En resumen, el patrón MVC consta de tres componentes principales:
- **Modelo**: Es la capa que se encarga de la lógica de negocio y la interacción con la base de datos. Aquí se definen las reglas de negocio y se realizan las operaciones de lectura y escritura en la base de datos.
- **Vista**: Es la capa que se encarga de la presentación de la información al usuario. Aquí se definen los elementos visuales que el usuario verá en la pantalla.
- **Controlador**: Es la capa que se encarga de recibir las peticiones del usuario y de coordinar la interacción entre el modelo y la vista. Aquí se definen las acciones que se realizarán en función de las peticiones del usuario.
En PHP, el patrón MVC se puede implementar utilizando el lenguaje de programación nativo o mediante el uso de un framework . Para implementar el patrón MVC en PHP nativo, se pueden seguir los siguientes pasos:
1. El usuario realiza una petición.
2. El controlador captura la petición.
3. Hace la llamada al modelo correspondiente. El modelo será el encargado de interactuar con la base de datos.
4. El controlador recibe la información y la envía a la vista.
5. La vista muestra la información.
Además necesitamos algo que ayude a mantener todas las rutas que se llama **ROUTER**:

O sea, cuando entramos a una ruta dentro de nuestro proyecto el sistema irá así:

Como ves entraremos a endpoints, que son rutas, nunca más a un archivo /propiedades.php
## La estructura:
Vamos a crear un proyecto nuevo limpio con una estructura MVC típica y desde el explorador de archivos vamos copiando archivos a la nueva carpeta.
1. Lo primero que hacemos es crear una nueva carpeta Public, en esta carpeta estará todo lo que los usuarios puedan ver, así separamos los archivos visibles de los no visibles, añadiendo una capa de seguridad. El servidor web lo tenemos que arrancar desde Public con `php -S localhost:3000`
2. Copiamos en el raiz composer.json y composer.lock
3. Ejecutamos en nuestro VSCode el `composer install ` para que instale todas las dependencias.
4. La carpeta "clases" ahora será modelos, la copiamos y le cambiamos el nombre.
5. Movemos gulpfile.js y los package.json y package.lock.json si los hubiera, y ponemos `npm i ` para que instale también las posibles dependencias de javascript
6. Copiamos también SRC en el raíz ya que los archivos source no deben verse por los usuarios, sin embargo el "build" lo copiamos dentro de public.No habría que copiarlo si hubiéramos estado trabajando correctamente con el gulp pero como no es el caso...así a lo bruto.
7. Copiamos también los includes.
8. Creamos una carpeta "controllers"
9. Creamos una carpeta "views"
Así que así quedaría más o menos la estructura:

## Creando los modelos
Lo primero es en el composer.json cambiar la carpeta donde están las clases y cambiamos el namespace a Model:

Hacemos un `composer update` después de haber hecho este cambio.
Recordamos que el modelo es quien interactúa con la base de datos, como es lo que hacen tampoco hay que cambiarlos tanto.
Tendremos que cambiar el nombre del namespaces en otros sitios...dónde?
El public va a llamar a todo siguiendo lo que programemos en el router tal y como explicamos así que vamos a crear en el raíz el router.php:
## Creando los controladores y el router
El router va a tener nuevas clases así que necesitamos otro namespace, lo incluimos en el composer.json, de paso creamos también el namespace para los controladores y update del composer.

Creamos una pruebita:
```
<?php
namespace MVC;
class Router{
public function __construct(){
echo "llamando al router";
}
}
```
Y en el index.php
```
<?php
require_once __DIR__ . '/../includes/app.php';
use MVC\Router;
$router=new Router();
```
## Registrando URL y los métodos asociados
En el index vamos a definir todas las posibles url de nuestra web y una función que aún no existe que va a hacer algo cuando se entre a esa URL:
```
<?php
require_once __DIR__ . '/../includes/app.php';
use MVC\Router;
$router=new Router();
$router->get('/admin', 'funcion_admin');
$router->comprobarRutas();
```
Y programamos nuestro router para que por ahora gestione todo lo que llegue por el método GET.
```
<?php
namespace MVC;
class Router{
public $rutasGET=[];
public $rutasPOST=[];
public function get($url, $fn){
$this->rutasGET[$url]=$fn;
}
public function comprobarRutas(){
$urlActual=$_SERVER['PATH_INFO']??'/';
$metodo=$_SERVER['REQUEST_METHOD'];
if ($metodo==='GET'){
$fn=$this->rutasGET[$urlActual]??null;
}
if ($fn){
//la url existe y hay una función asociada
call_user_func($fn, $this);
}else {
echo "página no encontrada";
}
}
}
```
Analiza lo que hace el router y averigua qué es call_user_func
## Asociando URL's a métodos del Controlador
Vamos a crear clases del controlador que tendrán los métodos que se llamarán desde el router.
Creamos en controllers/PropiedadController.php
Lo llamamos propiedad porque normalmente cada controlador tendrá un modelo asociado.
En el index vamos a crear varias rutas que nos harán falta y ya
```
<?php
require_once __DIR__ . '/../includes/app.php';
use MVC\Router;
use Controllers\PropiedadController;
$router=new Router();
$router->get('/admin', [PropiedadController::class, 'index']);
$router->get('/propiedades/crear', [PropiedadController::class, 'crear']);
$router->get('/propiedades/actualizar', [PropiedadController::class, 'actualizar']);
$router->comprobarRutas();
```
Y este sería el código del PropiedadController por ahora:
```
<?php
namespace Controllers;
class PropiedadController{
public static function index(){
echo "en el index";
}
public static function crear(){
echo "creandooo";
}
public static function modificar(){
echo "modificandoooo";
}
}
```
## Creando el método para mostrar las Vistas
Creamos el archivo admin/propiedades/index.php ponemos cualquier cosa a mostrar y cómo hacemos que se llame a esta vista desde el controlador?
Este será nuestro index por ahora:
```
<?php
require_once __DIR__ . '/../includes/app.php';
use MVC\Router;
use Controllers\PropiedadController;
$router=new Router();
$router->get('/admin', [PropiedadController::class, 'index']);
$router->get('/propiedades/crear', [PropiedadController::class, 'crear']);
$router->get('/propiedades/actualizar', [PropiedadController::class, 'actualizar']);
$router->comprobarRutas();
```
Este será nuestro nuevo router.
```
<?php
namespace MVC;
class Router{
public $rutasGET=[];
public $rutasPOST=[];
public function get($url, $fn){
$this->rutasGET[$url]=$fn;
}
public function comprobarRutas(){
$urlActual=$_SERVER['PATH_INFO']??'/';
$metodo=$_SERVER['REQUEST_METHOD'];
if ($metodo==='GET'){
$fn=$this->rutasGET[$urlActual]??null;
}
if ($fn){
//la url existe y hay una función asociada
call_user_func($fn, $this);
}else {
echo "página no encontrada";
}
}
public function render($view){
include __DIR__."/views/$view.php";
}
}
```
Nuestro nuevo controller:
```
<?php
namespace Controllers;
use MVC\Router;
class PropiedadController{
public static function index(Router $router){
$router->render('propiedades/admin');
}
public static function crear(){
echo "creandooo";
}
public static function modificar(){
echo "modificandoooo";
}
}
```
y creamos una carpeta de vistas donde dentro de views/propiedades/admin.php solo pondremos un html sencillo.
Y ahora nos planteamos que en nuestro proyecto teníamos unos templates. Aquí se usa un layout principal.
## Creando un layout principal
La idea es que sea una página maestra y que sólo algunas partes cambien.
La realizamos como sigue:
```
<?php
if(!isset($_SESSION)) {
session_start();
}
$auth = $_SESSION['login'] ?? false;
if(!isset($inicio)) {
$inicio = false;
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Bienes Raices</title>
<link rel="stylesheet" href="../build/css/app.css">
</head>
<body>
<header class="header <?php echo $inicio ? 'inicio' : ''; ?>">
<div class="contenedor contenido-header">
<div class="barra">
<a href="/">
<img src="../build/img/logo.svg" alt="Logotipo de Bienes Raices">
</a>
<div class="mobile-menu">
<img src="../build/img/barras.svg" alt="icono menu responsive">
</div>
<div class="derecha">
<img class="dark-mode-boton" src="/build/img/dark-mode.svg">
<nav class="navegacion">
<a href="/nosotros">Nosotros</a>
<a href="/propiedades">Anuncios</a>
<a href="/blog">Blog</a>
<a href="/contacto">Contacto</a>
<?php if($auth): ?>
<a href="/logout">Cerrar Sesión</a>
<?php endif; ?>
</nav>
</div>
</div> <!--.barra-->
<?php echo $inicio ? "<h1>Venta de Casas y Departamentos Exclusivos de Lujo</h1>" : ''; ?>
</div>
</header>
<?php echo $contenido; ?>
<footer class="footer seccion">
<div class="contenedor contenedor-footer">
<nav class="navegacion">
<a href="nosotros.php">Nosotros</a>
<a href="anuncios.php">Anuncios</a>
<a href="blog.php">Blog</a>
<a href="contacto.php">Contacto</a>
</nav>
</div>
<p class="copyright">Todos los derechos Reservados <?php echo date('Y'); ?> ©</p>
</footer>
<script src="/build/js/bundle.min.js"></script>
</body>
</html>
```
Hemos creado nuestro layout, con una variable contenido que tendrá el contenido de la página, pero no le hemos dicho al controler que lo vamos a utilizar.
vamos a la función render del router:
```
public function render($view){
ob_start();
include __DIR__."/views/$view.php";
$contenido=ob_get_clean();
include __DIR__."/views/layout.php";
}
}
```
Investiga lo que es el ob_start y el ob_get_clean.
Finalmente lo que queremos hacer es inyectar el contenido dentro del layout.
Prueba a ver si funciona, experimenta y piensa sobre las opciones de trabajar así.
## Pasar datos a la vista
Tenemos que encontrar una manera de pasar los datos desde el router hasta la vista, seguiremos el modelo de laravel.
Lo primero es que al router le vamos a pasar un vector con los parámetros a pasar a la vista, como no sabemos el nombre de las variables que vamos a pasar usamos $$key=$value, que es una asignación "variable de variable" investiga como funciona.
```
public function render($view, $datos=[]){
foreach ($datos as $key =>$value){
$$key=$value;
}
ob_start();
include __DIR__."/views/$view.php";
$contenido=ob_get_clean();
include __DIR__."/views/layout.php";
}
}
```
Si en el controlador pasamos lo siguiente:
```
public static function index(Router $router){
$router->render('propiedades/admin', [
'mensaje'=>1,
'propiedades'=>[1,2,3]
]);
}
```
Si en views/propiedades/admin.php ponemos
```
<?php debuguear($propiedades) ?>
```
Verás que esos datos se están pasando a la vista. Vamos a ver cómo mostrar los datos.
## Consultar el modelo en el controlador y pasar los resultados a la vista
En PropiedadesController.php debemos incluir el modelo de propiedades y pasar todos los campos de propiedades usando el método Propiedad::all()
```
use Model\Propiedad;
class PropiedadController{
public static function index(Router $router){
$propiedades= Propiedad::all();
$router->render('propiedades/admin', ['propiedades'=>$propiedades]);
}
```
Sólo nos faltaría hacer que se viera en la vista que ya teníamos hecha en la versión de objetos.
Quedaría así:
```
<main class="contenedor seccion">
<h1>Administrador de Bienes Raices</h1>
<h2>Propiedades</h2>
<table class="propiedades">
<thead>
<tr>
<th>ID</th>
<th>Titulo</th>
<th>Imagen</th>
<th>Precio</th>
<th>Acciones</th>
</tr>
</thead>
<tbody> <!-- Mostrar los Resultados -->
<?php foreach( $propiedades as $propiedad ): ?>
<tr>
<td><?php echo $propiedad->id; ?></td>
<td><?php echo $propiedad->titulo; ?></td>
<td> <img src="/imagenes/<?php echo $propiedad->imagen; ?>" class="imagen-tabla"> </td>
<td>$ <?php echo $propiedad->precio; ?></td>
<td>
<form method="POST" action="propiedades/eliminar" class="w-100">
<input type="hidden" name="id" value="<?php echo $propiedad->id; ?>">
<input type="hidden" name="tipo" value="propiedad">
<input type="submit" class="boton-rojo-block" value="Eliminar">
</form>
<a href="propiedades/actualizar?id=<?php echo $propiedad->id; ?>" class="boton-amarillo-block">Actualizar</a>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</main>
```
Prueba e investiga cómo está funcionando esta magia!
Subo el proyecto completo para que puedas investigar!
****
Si deseas profundizar más en el tema, te recomiendo que consultes los siguientes recursos:
- [Tutorial de MVC en PHP nativo por Victor Robles [^1^][1]](https://https://dev.to/ulisesafcdev/desarrollar-un-proyecto-mvc-con-php-puro-4akg).
- [Aprende a desarrollar aplicaciones web con MVC en PHP desde cero por Aprendeprogramando [^3^][3].
](https://https://aprendeprogramando.es/mvc-php-desde-cero/)