Curso Laravel 8.0 clase 29/05/2023
Notas sobre la clase del 29/05/2023 del curso Curso de Laravel 8.0
Resumen semana pasada:
- Tests unitarios
- Estructura de Laravel
- MVC
LAravel se lleva muy bien con Vue (y quizás con React). Laravel no quiere jQuery
Recordamos la creación del modelo:
php artisan make:model Product -a
Creará también los métodos para hacer un CRUD.
En base de datos, aunque nuestro modelo sea singular, Laravel crea la base de datos en plural.
database/migrations/….create_products_table.php
Para crear realmente la estructura en base de datos, lanzamos todas las migraciones:
php artisan migrate
Echando vistazo a la base de datos, vemos las siguientes tablas:
- failed_jobs: colas de tareas. Tareas que se ejecutan de manera asíncrona. Envío de e-mails, por ejemplo. Aquí se guardarán las tareas que no han terminado correctamente.
- migrations: ficheros de migraciones. Los que aparezcan, Laravel no los ejecutará más.
- password_resets
- personal_access_tokens
- products
- users
Si queremos forzar a lanzar todas las migraciones:
php artisan migra:fresh
No usar ese comando en producción porque se borrará la base de datos.
Nuevo fichero de migración:
php artisan make:migration adds_description_to_products
Añadimos un campo nuevo a la tabla “products”
php artisan migrate
Laravel solo ejecutará la nueva migración (porque no está en la tabla migrations)
En database/seeders/DatabaseSeeder.php vamos a generar datos:
run() { Product::factory(['name' => 'tesla 5', 'description' => 'coche que mola'])->create(); }
php artisan db:seed
Tendremos el registro nuevo en tabla products.
En database/factories/ProductFactory.php
Para tener variedad en los datos que se vayan a meter:
public function definition() { return [ 'name' => $this->faker->name(), 'description' => $this->faker-text() ]; }
Modificaríamos ahora DatabaseSeeder.php:
// ... Product::factory(100)->create();
Como no indicamos nada por argumento a create, tomará lo de la biblioteca Faker.
Limpieza:
php artisan migrate:fresh -- seed
Borra la base de datos, la vuelve a crear y luego la rellena de datos.
Vamos con las rutas. Para poder verlas:
php artisan route:list
app/Http/Controllers/ProeductController.php
public function index() { return view ("product.index"); // el punto sustituye la barra (/) para evitar incompatibilidades Windows-Linux }
Creamos la vista:
resources/views/products/index.blade.php:
<h1>Listado de productos</h1>
<ul>
<li><p>Nombre: tesla5</p>
<p>Descripción: coche que mola</p></li>
</ul>
Ahora podemos ir a http://localhost/product
Para pasarle lo que hay en base de datos:
public function index() { // Cogemos todos los productos $products = Product::all(); return view ("product.index", ["productsList" => $products]); }
En la vista:
<h1>Listado de productos</h1> <ul> @foreach($productsList as $product) <li><p>Nombre: {{$product->name}}</p> <p>Descripción: {{$product->name}}</p></li> @endforeach </ul>
Eloquent es el ORM que utiliza Laravel. Object Relational Mapping. AL profe le gusta más el que usa Symfony: Doctrine.
El modelo Producto y el modelo de datos no tendría que ser lo mismo. Laravel lo junta. Veremos más adelante cómo separarlo.
public function index() { // Cogemos todos los productos $products = Product::all(); // Para visualizar el contenido y no continuar luego: dd($products); return view ("product.index", ["productsList" => $products]); }
Vamos con el create, para la creación (no confundir con store que sería el que almacena):
public function create() { // Cogemos todos los productos $products = Product::all(); // Para visualizar el contenido y no continuar luego: dd($products); return view ("product.create", ["productsList" => $products]); }
Se crea la vista en resources/views/products/create.blade.php:
<form action="/product" method="post"> <input typè="text" name="name"> <input typè="text" name="description"> <input typè="submit" value="Enviar"> </form>
En el atributo “name” hay que poner el nombre del campo.
Ese formulario irá a
public function store(StoreProductRequest $request) { dd($request); }
Al enviar formulario nos saldrá el error 419 page expired se debe al CSRF (Cross Site Request Forgery). Lo arreglamos con:
<form action="/product" method="post"> @csrf <input typè="text" name="name"> <input typè="text" name="description"> <input typè="submit" value="Enviar"> </form>
Ahora el error cambiará a 403 - non authorized. Miramos StoreProductRequest.php y en el método authorize() cambiamos el boolean que devuelve (estaba en false, entonces ponemos true).
Modificamos el store:
public function store(StoreProductRequest $request) { Product::create($request->all()); }
Si ahora volvemos a enviar el formulario, tendremos otro error relacionado con el token. Laravel por seguridad no permite meter de todo.
Solucionamos en el modelo Product.php:
use HasFactory; protected $fillable = ['name', "description"];
Seguimos modificando la vista:
<form action="/product" method="post"> @csrf <input type="text" name="name"> <input type="text" name="description"> <input type="text" name="id"> <input type="submit" value="Enviar"> </form>
Ignorará el campo ID porque no está en el $fillable.
Nos mandan hacer una tarea usando TDD para
- Crear modelo:
- Que el modelo esté en base de datos
- Formulario creación
Uno de los primeros indicadores que dice que un test no es unitario es que conecte con base de datos. Sería un test de integración.
No testeamos código que no sea nuestro.
Para saber qué testeamos tenemos que pensar primero en qué necesitamos. El test tiene que llevar a un diseño concreto.
No probamos datos, solo comportamientos. Por ejemplo, comprobar si existen ciertos campos.
Tests unitarios:
- Un test unitario no habla con servicios externos (la base de datos es un servicio externo, el reloj del sistema es también externo)
