Aprende eloquent con ejemplos!!! - Lección 3: Modelos, Tinker y Base de datos heredadas
Published: 2021-04-25 21:45:06

Bienvenidos a esta tercera entrega de *Eloquent con ejemplos*.  En la lección pasada aprendimos como poblar de una forma bastante práctica y cómoda nuestra base de datos, dándonos la oportunidad de conocer un poco sobre una pieza fundamental dentro del mundo de Eloquent: **Modelos**.

Hoy trataremos de indagar más a fondo dentro de esta importante clase y aprenderemos sobre su gran versatilidad para interactuar con base de datos nuevas y heredadas, conoceremos sobre algunos de sus atributos y uno que otro tip de configuración que nos ayudarán a crear aplicaciones de manera rápida y mantenibles.

Lo que aprenderemos hoy:
* Atributos de los Modelos.
* Tinker.
* Trabajar con base de datos heredadas.

Empecemos por un pequeño repaso de lo visto en la lección pasada sobre los modelos y partamos de lo que ya habíamos hecho.

Si revisamos nuestra aplicación vemos que se nos había solicitado la creación de un tabla `dogs`, procediendo a crear nuestro modelo `Dog` en la terminal y pasándole los respectivos flags de creación de migraciones, factories y seeders, a estas alturas ya deberías saber de que te estoy hablando, si no, échale una ojeada a la entrega anterior.

> Recuerda que es importante el uso correcto de las mayúsculas y minúsculas, así como el manejo de las palabras en singular y plural según sea el caso.

Pues bien, teniendo todo previamente configurado, vayamos a la consola y ejecutemos:

```php
    php artisan tinker
```

Veremos como nuestra terminal ha cambiado, mostrándonos el siguiente mensaje:

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/esmopdm7o0in9uc30ouc.png)
 

Lo que hemos hechos es ejecutar una grandioso **REPL** (*Read-Eval-Print-Loop*) llamada **Tinker**, el cual viene instalado por defecto con Laravel 8, con el, podremos interactuar con nuestras aplicaciones desde nuestra terminal, permitiéndonos hacer pruebas o revisar el funcionamiento de lo que en ellas vamos creando, esto incluye por supuesto a nuestro modelos.  ¡No más llenar nuestra base de código con llamadas dd()!

Veamos  un ejemplo y ejecutemos la siguiente instrucción:

```php
   $dog = App\Models\Dog::find(1)

   $dog->name

   => “Jack”
```

Verás como en pantalla aparecerá el nombre de nuestro amigo canino guardado con el *id = 1*. Como el nombre lo asignamos en nuestro *model factory* mediante el uso de la librería *Faker*, este será diferente para cada uno de nosotros, lo importante acá es que te aparezca un nombre, eso indica que la configuración que hicimos trabaja perfectamente y que tu modelo esta bien configurado.

Puedes ir jugando con tus modelos desde esta terminal, debes saber que **Tinker** recuerda nuestras variables durante una sesión de trabajo, para salir de ella y volver a nuestra consola solo debes teclear `exit` y listo. Cuando ingreses nuevamente deberás crear todas tus variables y configurar el entorno que tenías en la sesión anterior, pero ten presente lo siguiente: Toda interacción con la base de datos de inserción, edición y eliminación será registrada en ella de manera permanente, ten en cuenta esto al momento de realizar tus pruebas, no querrás cambiar algo que quizás necesites más adelante.

Ahora bien, hasta acá todo ha ido bien, pero no se si te haz preguntado, ¿Que pasa si nuestra aplicación  viene trabajando con una base de datos heredada? ¿Es posible trabajar con mis nuevos modelos y conectarlos a esta base de datos? ¿Es eloquent tan versátil y adaptable como para brindarnos tal facilidad?. La respuesta a todo eso es SI!.

Algunas veces nos encontraremos en situaciones en la que heredamos una base de datos cuya estructura no se adapta exactamente a nuestra aplicación actual o a nuestro marco de trabajo en si, debiendo tomar decisiones que quizás no sean muy convenientes o que incluso necesiten de modificaciones difíciles y/o costosas. Sin embargo, con eloquent, en la gran mayoría de los casos, no es más que hacer unas pequeñas configuraciones y todo estará listo de una manera rápida, fácil y mantenible.

> Para poder cubrir bien el ejemplo que te mostraré, deberás ir a tu base de datos y crear la tabla correspondiente e insertar al menos un registro  en ella. Te dejo el código SQL por si quieres hacer uso de él, aunque la puedes crear manualmente sin ningún inconveniente.

```sql
CREATE TABLE `TblContacts`
(
`Contacts_ID` INT NOT NULL AUTO_INCREMENT ,
`Contacts_Name` VARCHAR(50) NOT NULL ,
`Contacts_Email` VARCHAR(50) NOT NULL ,
PRIMARY KEY (`Contacts_ID`)
) ENGINE = InnoDB;

INSERT INTO `TblContacts`
(`Contacts_ID`, `Contacts_Name`, `Contacts_Email`)
VALUES ('1', 'Jeff', 'jeff@codebyjeff.com');
```

Veamos un ejemplo:

Supongamos que nuestra aplicación tiene una tabla llamada  TblContacts, lo que a primera vista denota la imposibilidad de poder hacer uso de la lógica de reflexión que Laravel nos ofrece, pues no se ajusta al standar de nombre al que tantas veces he hecho referencia. Sin embargo, vayamos a nuestra terminal para crear nuestro modelo y tratar de interactuar  con ella:

```php
    php artisan make:model Contact
```

Abramos Tinker y ejecutemos la siguiente instrucción:

```php
    App\Models\Contact::all()
```
Vemos como rápidamente nos salta un enorme mensaje de error, en el que, en resumidas cuentas, nos esta indicando que la tabla `contacts` no existe, pues nuestra tabla realmente se llama `TblContacts` . Ahora bien, ¿como hacemos entonces para que nuestro modelo puede enlazarse con dicha tabla? . Pues esto y mucho más podemos hacerlo a través de los atributos de clase de los modelos.

Todos nuestros modelos tienen un conjunto de atributos y métodos que nos facilitarán su configuración, dándonos esa versatilidad de uso que necesitamos para adaptarnos a cualquier situación que se nos presente, en este caso, una base de datos heredada.

Pues, pongamos manos a la obra y configuremos nuestra tabla para que, al usar nuestro modelo `Contact` este interactúe con nuestra tabla heredada `TblContacts`. Vayamos a nuestro modelo y agreguemos la siguiente propiedad:

> Creo que no he hecho mención a que desde la ultima versión de laravel, nuestro modelos se encuentran en `App\Models\` a diferencia de versiones anteriores, en las que puedes encontrarlos en  `App\`. Ten en cuenta esto al momento de trabajar con tus modelos.


```php
class Contact extends Model
{
    protected $table = 'TblContacts';
}
```
Prueba tu comando Tinker otra vez (tendrás que salir de Tinker y abrirlo de nuevo, lamentablemente las sesiones de Tinker no detectarán cambios de código), verás que devuelve una colección (el objeto devuelto estándar de Eloquent) con una única instancia de modelo del registro que insertamos "Jeff".

Vamos a probar una idea más en Tinker - vamos a obtener el número de contacto `1`. ¿Qué crees que pasará?


```php
App\Contact::find(1)
```

"Illuminate\Database\QueryException with message 'SQLSTATE[42S22]: Column not found: 1054 Unknown column 'TblContacts.id' in 'where clause' (SQL: select * from TblContacts where TblContacts.id = 1 limit 1)'"


Como era de esperar, está buscando una clave principal llamada `id` y no la encuentra, pues la clave primaria de nuestra tabla es `Contacts_ID`. Eloquent nos ofrece la misma solución fácil y limpia que para nuestra tabla:


```php
class Contact extends Model
{
    protected $table = 'TblContacts';

    protected $primaryKey = 'Contacts_ID';
}

```

y las cosas funcionan bien de nuevo.

Como podrán ver, la forma en la que podemos configurar nuestros modelos nos abre un abanico de posibilidades, algunas serán para buenas prácticas, otras no lo serán tanto, todo depende de nosotros y el uso que le demos, pero la verdad es que, de la forma en la que se plantean estas configuraciones podremos jugar a nuestras anchas, asignando los valores correspondiente a cada propiedad de clase según nuestra conveniencia.

Existen muchas otras propiedades de clase que podamos modificar para cambiar el comportamiento de nuestro modelos, por ejemplo, las claves primarias por defecto son de tipo enteros auto-incrementales, esto lo podemos cambiar a través de la propiedad:


```php
class Contact extends Model
{
    protected $keyType = 'string';

    public $incrementing = false;
}
```

Con este cambio le estamos indicando a nuestro marco que el modelo tiene una clave primaria tipo ‘string’ que no se auto-incremental, lo que es muy útil si queremos ser nosotros quienes generemos nuestras propia claves primarias. Otra propiedad muy importante es `protected $connection = 'sqlite';`
, con ella podemos cambiar la conexión a la base de datos, según las configuradas en nuestro archivo `config\database.php`, en este caso, activamos la conexión para sqlite, pero esta y otras propiedades las dejaremos para otras entregas más avanzadas y especificas del curso.


Como último tip de esta entrega, me gustaría enseñarte como hacer para deshacernos de ese arcaico esquema de nombres heredado de nuestra base de datos. Si bien es cierto que hasta ahora todo funciona para nosotros, no debería escapársenos el hecho que los actuales campos de nuestra base de datos fueron construido bajo un esquema de nombres bastante arcaico y lejos de los standares que hoy en día manejamos. El problema al que nos enfrentamos es este: si empezamos a construir nuestra aplicación, nos encontraremos por doquier algo como esto `$contact->Contacs_Name`, lo que supondría, en un futuro,  un trabajo de refactorización bastante laborioso. Realmente nos gustaría poner otra capa entre nuestro modelo y la salida que eventualmente usaremos en las vistas, más acorde a los standares y que sea fácilmente mantenible.

Por un lado, podemos declarar, dentro de nuestro modelo, un método de acceso a nuestra propiedad, algo muy propio de la Programación Orientada a Objetos (POO),  este podría ser un ejemplo:

```php
public function contactName(){
    return $this->Contacts_Name;
}
```

Ahora podremos acceder a nuestro valor haciendo uso de `$contact->contactName()`. Esto nos permitirá en un futuro, poder cambiar la salida de nuestro atributo sin que tengamos que hacer ninguna otra modificación dentro de nuestra aplicación. Otra manera de hacer esto mismo puede ser con el uso de los `Accesors`, pero eso ya es tema de otra lección más delante.

Existen otras formas como lo es el uso de un objeto completamente independiente llamado "transformador" que tiene el trabajo de presentar sus datos. Un popular paquete que ayuda a esta implementación es ["Fractals"](http://fractal.thephpleague.com), por otra parte, si estas trabajando con API’s, un recurso muy recomendado para esta tarea son los [Eloquent: API Resources](https://laravel.com/docs/8.x/eloquent-resources). Ambas implementaciones escapan del ámbito que esta lección pretende abordar, pero realmente son bastante sencillas, así que te invito a que le eches una ojeada a las fuentes si te interesa ampliar más sobre ellas.

Pues bien, esto ha sido todo por hoy, hemos aprendimos un poco sobre cómo funciona nuestro modelo, y cómo podemos controlarlo para usar tablas heredadas y esquemas de nomenclatura, así como algunos tips para enmascarar la salida de nuestros modelos. Empieza a hacer tus pruebas y jugar con el código, recuerda que el verdadero aprendizaje se da a través de la práctica, si tienes alguna duda o comentario no dudes en contactarme.  Que tengas un feliz y exitoso día.