---
# System prepended metadata

title: 'Día 1, Bienes Raíces-POO: añadiendo POO al proyecto'
tags: [php]

---

# Día 1, Bienes Raíces-POO: añadiendo POO al proyecto

Lo primero será crear la carpeta donde crearemos nuestras clases, vamos crearla en la raíz y de nombre clases.

Inicializamos el composer: 
composer init
Pon tu nombre e email en este formato Noelia \<email@delaprofe.com\>, dile que no quieres que te genere dependencias de manera interactiva y que genere el fichero. 

Verás que se crea el fichero composer.json que es donde se van a ir guardando todas las dependencias.
Vamos a decirle al composer dónde vamos a tener nuestras clases y nuestro namespace para que no haya conflictos con clases de otras dependencias que vayamos instalando:
![image.png](https://hackmd.io/_uploads/Bk4rGhvmT.png)

Así no tendremos que preocuparnos por realizar las importaciones, el composer se encargará por nosotros. 

Una vez modificado el composer.json tenemos que ir a la terminal y escribir: 
composer update

Creará la carpeta vendor que es donde se guardará la información de las dependencias. 

Lo siguiente es cambiar algo la estructura de los requires en nuestra aplicación. 
El objetivo es que desde app.php se llamen todas las dependencias, para que el compose pueda controlarlo más fácilmente. 
por lo que en app.php también incluimos la conexión a la bd y el autoload de composer. 

Vamos a ir a includes/app.php y desde aquí hacemos que se carguen las funciones. Debe quedar así: 
```
<?php
require 'funciones.php';
require 'config/database.php';
require __DIR__.'/../vendor/autoload.php';
```


Se crea un loop ya que en funciones.php también estamos incluyendo app.php así que borramos la línea 
`include 'app.php';`
y añadimos 
```
define('FUNCIONES_URL', __DIR__ . "funciones.php");
define('TEMPLATES_URL', __DIR__ . "/templates");
```

Van a dar varios errores en varios archivos por este cambio, hay que sustituir varios includes y cambiarlos por `include 'app.php'` que ya lo englobaría todo, o hay que directamente quitar algún include porque se duplica. Busca y corrige los errores!




Creamos una clase en clases:
Propiedad.php

```
<?php

namespace App;

class Propiedad {
    
}

```

para probar, vamos a modificar app.php  añadiendo:

```
use App\Propiedad;

$propiedad= new Propiedad();

var_dump($propiedad);
```

Hacemos un` composer update`

y recargamos el index.php del proyecto, debería salir el var_dump del objeto, lo que significa que el composer está funcionando y nos ha registrado esa clase que está disponible para usar en el proyecto. 

![image.png](https://hackmd.io/_uploads/HytQiAdXT.png)


Una vez comprobado que está funcionando quitamos las dos últimas líneas y comenzamos a orientar nuestro proyecto a objetos, pero sólo la parte de la base de datos por ahora. 

## Usando Active Record. 

Ya estuvimos mirando la teoría sobre Active Record, al verlo de manera práctica se va a entender mucho mejor. 

Vamos a ir al archivo crear.php del admin. 

Vamos a trasladar casi todo ese código a una clase que se encargará de todos los métodos relativos al acceso a la bd con el modelo active record. 

Según el patrón active record:
- crearemos una clase por cada tabla y los atributos de cada clase serán los campos de la tabla
- cada atributo se "mapea" utilizando los campos de la bd, es decir se crea un objeto en memoria que es igual a lo que tenemos en la bd
- active record mantiene y lee los cambios que se hacen en los atributos. 
- los métodos serán, o sorpresa!:
    - $propiedad-> guardar();
    - $propiedad->actualizar();
    - $propiedad-> eliminar();
    - Propiedad::find();
    - Propiedad::all();

Les voy a dar primero cómo va a quedar el código final, para que intenten entender el cambio de paradigma y en próximas clases iremos paso a paso, pero vale la pena pasar este momento:

En clases tendríamos una clase ActiveRecord con esta forma:

```
<?php

namespace App;

class ActiveRecord {


// Base DE DATOS
protected static $db;
protected static $tabla = '';
protected static $columnasDB = [];

// Errores
protected static $errores = [];


// Definir la conexión a la BD
public static function setDB($database) {
    self::$db = $database;
}

// Validación
public static function getErrores() {
    return static::$errores;
}
public function validar() {
    static::$errores = [];
    return static::$errores;
}

// Registros - CRUD
public function guardar() {
    if(!is_null($this->id)) {
        // actualizar
        $this->actualizar();
    } else {
        // Creando un nuevo registro
        $this->crear();
    }
}

public static function all() {
    $query = "SELECT * FROM " . static::$tabla;

    $resultado = self::consultarSQL($query);

    return $resultado;
}

// Busca un registro por su id
public static function find($id) {
    $query = "SELECT * FROM " . static::$tabla  ." WHERE id = ${id}";

    $resultado = self::consultarSQL($query);

    return array_shift( $resultado ) ;
}

// crea un nuevo registro
public function crear() {
    // Sanitizar los datos
    $atributos = $this->sanitizarAtributos();

    // Insertar en la base de datos
    $query = " INSERT INTO " . static::$tabla . " ( ";
    $query .= join(', ', array_keys($atributos));
    $query .= " ) VALUES (' "; 
    $query .= join("', '", array_values($atributos));
    $query .= " ') ";

    // Resultado de la consulta
    $resultado = self::$db->query($query);

    // Mensaje de exito
    if($resultado) {
        // Redireccionar al usuario.
        header('Location: /admin?resultado=1');
    }
}

public function actualizar() {

    // Sanitizar los datos
    $atributos = $this->sanitizarAtributos();

    $valores = [];
    foreach($atributos as $key => $value) {
        $valores[] = "{$key}='{$value}'";
    }

    $query = "UPDATE " . static::$tabla ." SET ";
    $query .=  join(', ', $valores );
    $query .= " WHERE id = '" . self::$db->escape_string($this->id) . "' ";
    $query .= " LIMIT 1 "; 

    $resultado = self::$db->query($query);

    if($resultado) {
        // Redireccionar al usuario.
        header('Location: /admin?resultado=2');
    }
}

// Eliminar un registro
public function eliminar() {
    // Eliminar el registro
    $query = "DELETE FROM "  . static::$tabla . " WHERE id = " . self::$db->escape_string($this->id) . " LIMIT 1";
    $resultado = self::$db->query($query);

    if($resultado) {
        $this->borrarImagen();
        header('location: /admin?resultado=3');
    }
}

public static function consultarSQL($query) {
    // Consultar la base de datos
    $resultado = self::$db->query($query);

    // Iterar los resultados
    $array = [];
    while($registro = $resultado->fetch_assoc()) {
        $array[] = static::crearObjeto($registro);
    }

    // liberar la memoria
    $resultado->free();

    // retornar los resultados
    return $array;
}

protected static function crearObjeto($registro) {
    $objeto = new static;

    foreach($registro as $key => $value ) {
        if(property_exists( $objeto, $key  )) {
            $objeto->$key = $value;
        }
    }

    return $objeto;
}



// Identificar y unir los atributos de la BD
public function atributos() {
    $atributos = [];
    foreach(static::$columnasDB as $columna) {
        if($columna === 'id') continue;
        $atributos[$columna] = $this->$columna;
    }
    return $atributos;
}

public function sanitizarAtributos() {
    $atributos = $this->atributos();
    $sanitizado = [];
    foreach($atributos as $key => $value ) {
        $sanitizado[$key] = self::$db->escape_string($value);
    }
    return $sanitizado;
}

public function sincronizar($args=[]) { 
    foreach($args as $key => $value) {
      if(property_exists($this, $key) && !is_null($value)) {
        $this->$key = $value;
      }
    }
}

// Subida de archivos
public function setImagen($imagen) {
    // Elimina la imagen previa
    if( !is_null($this->id) ) {
        $this->borrarImagen();
    }
    // Asignar al atributo de imagen el nombre de la imagen
    if($imagen) {
        $this->imagen = $imagen;
    }
}

// Elimina el archivo
public function borrarImagen() {
    // Comprobar si existe el archivo
    $existeArchivo = file_exists(CARPETA_IMAGENES . $this->imagen);
    if($existeArchivo) {
        unlink(CARPETA_IMAGENES . $this->imagen);
    }
}
}
```


La clase Propiedad quedaría:
```
<?php

namespace App;

class Propiedad extends ActiveRecord {

    // Base DE DATOS
    protected static $tabla = 'propiedades';
    protected static $columnasDB = ['id', 'titulo', 'precio', 'imagen', 'descripcion', 'habitaciones', 'wc', 'estacionamiento', 'creado', 'vendedorId'];


    public $id;
    public $titulo;
    public $precio;
    public $imagen;
    public $descripcion;
    public $habitaciones;
    public $wc;
    public $estacionamiento;
    public $creado;
    public $vendedorId;

    public function __construct($args = [])
    {
        $this->id = $args['id'] ?? null;
        $this->titulo = $args['titulo'] ?? '';
        $this->precio = $args['precio'] ?? '';
        $this->imagen = $args['imagen'] ?? '';
        $this->descripcion = $args['descripcion'] ?? '';
        $this->habitaciones = $args['habitaciones'] ?? '';
        $this->wc = $args['wc'] ?? '';
        $this->estacionamiento = $args['estacionamiento'] ?? '';
        $this->creado = date('Y/m/d');
        $this->vendedorId = $args['vendedorId'] ?? '';
    }

    public function validar() {

        if(!$this->titulo) {
            self::$errores[] = "Debes añadir un titulo";
        }

        if(!$this->precio) {
            self::$errores[] = 'El Precio es Obligatorio';
        }

        if( strlen( $this->descripcion ) < 50 ) {
            self::$errores[] = 'La descripción es obligatoria y debe tener al menos 50 caracteres';
        }

        if(!$this->habitaciones) {
            self::$errores[] = 'El Número de habitaciones es obligatorio';
        }
        
        if(!$this->wc) {
            self::$errores[] = 'El Número de Baños es obligatorio';
        }

        if(!$this->estacionamiento) {
            self::$errores[] = 'El Número de lugares de Estacionamiento es obligatorio';
        }
        
        if(!$this->vendedorId) {
            self::$errores[] = 'Elige un vendedor';
        }

        if(!$this->imagen ) {
            self::$errores[] = 'La Imagen es Obligatoria';
        }

        return self::$errores;
    }

}
```

Ejemplo de cómo quedaría el crear.php de productos, va a fallar porque en la versión final usaremos una librería para manejar imágenes, pero para que se hagan una idea:

```
<?php 
    require '../../includes/app.php';
    use App\Propiedad;
    use App\Vendedor;

    estaAutenticado();

    // Importar Intervention Image
    use Intervention\Image\ImageManagerStatic as Image;

    // Crear el objeto
    $propiedad = new Propiedad;

    // Consultar para obtener los vendedores
    $vendedores = Vendedor::all();

    // Arreglo con mensajes de errores
    $errores = Propiedad::getErrores();

    // Ejecutar el código después de que el usuario envia el formulario
    if($_SERVER['REQUEST_METHOD'] === 'POST') {

        /** Crea una nueva instancia */
        $propiedad = new Propiedad($_POST['propiedad']);

        // Generar un nombre único
        $nombreImagen = md5( uniqid( rand(), true ) ) . ".jpg";

        // Setear la imagen
        // Realiza un resize a la imagen con intervention
        if($_FILES['propiedad']['tmp_name']['imagen']) {
            $image = Image::make($_FILES['propiedad']['tmp_name']['imagen'])->fit(800,600);
            $propiedad->setImagen($nombreImagen);
        }
        
        // Validar
        $errores = $propiedad->validar();

        if(empty($errores)) {
        
            // Crear la carpeta para subir imagenes
            if(!is_dir(CARPETA_IMAGENES)) {
                mkdir(CARPETA_IMAGENES);
            }

            // Guarda la imagen en el servidor
            $image->save(CARPETA_IMAGENES . $nombreImagen);

            // Guarda en la base de datos
            $propiedad->guardar();
        }
    }

    incluirTemplate('header');
?>

    <main class="contenedor seccion">
        <h1>Crear</h1>

        

        <a href="/admin" class="boton boton-verde">Volver</a>

        <?php foreach($errores as $error): ?>
        <div class="alerta error">
            <?php echo $error; ?>
        </div>
        <?php endforeach; ?>

        <form class="formulario" method="POST" action="/admin/propiedades/crear.php" enctype="multipart/form-data">
            <?php include '../../includes/templates/formulario_propiedades.php'; ?>

            <input type="submit" value="Crear Propiedad" class="boton boton-verde">
        </form>
        
    </main>

<?php 
    incluirTemplate('footer');
?> 
```