0% encontró este documento útil (0 votos)
53 vistas247 páginas

Laravelengineer v1.3 Rimorsoft

Cargado por

dcnx
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
0% encontró este documento útil (0 votos)
53 vistas247 páginas

Laravelengineer v1.3 Rimorsoft

Cargado por

dcnx
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
Está en la página 1/ 247

Laravel Engineer

Rimorsoft Online y el Profesor Italo Morales F.


Este libro está a la venta en http://leanpub.com/laravelengineer

Esta versión se publicó en 2020-04-21

Éste es un libro de Leanpub. Leanpub anima a los autores y publicadoras con el proceso de
publicación. Lean Publishing es el acto de publicar un libro en progreso usando herramientas
sencillas y muchas iteraciones para obtener retroalimentación del lector hasta conseguir el libro
adecuado.

© 2019 - 2020 Rimorsoft Online y el Profesor Italo Morales F.


Dedicado a ti querido estudiante.
Índice general

Sobre Nosotros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . i

Al Estudiante . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ii

Nota Importante . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . iii

Agradecimiento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . iv

Posibles Errores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . v

Introducción . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . vi
Bienvenida . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . vi
¿Qué es Laravel? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . vi
¡Atención! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . viii

Parte 1: Conceptos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
Capítulo 1: Lo que debes saber . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
Qué es Laravel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
Qué necesitamos para su Instalación . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
Temas Importantes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
Ciclo de Vida . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8

Capítulo 2: Laravel es Poderoso . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9


CRUD en Laravel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9

Parte 2: Fundamentos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
Capítulo 3: Te Presento a Laravel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
Estructura de Carpetas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
Sistema de Rutas, URLs y Controladores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
Capa de Middleware . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
Validación de datos (vistas, formularios y controladores) . . . . . . . . . . . . . . . . . . . . . 28
ÍNDICE GENERAL

Capítulo 4: Sistema de Plantilla . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35


Herencia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
Magia de Yield . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
Estructuras de Control . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
Configuración de Formularios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
Componentes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
Ingeniería . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55

Capítulo 5: Componente de Login y Registro . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56


Laravel/UI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
El comando ui y ui:auth . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57

Parte 3: Base de datos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59


Capítulo 6: Fundamentos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
Curso en Video . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
Introducción a Eloquent . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
Relaciones de Base de datos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
Collections y Serialización . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
Formato de valores en Tablas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
Convenciones en Eloquent . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
Carpeta de Base de Datos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78

Capítulo 7: Query Builder . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85


Su Uso . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
Selects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
Uniones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
Where . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
Otros Métodos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88
Crear Registros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88
Actualizar un Registro . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
Eliminar un Registro . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89

Parte 4: API con TDD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90


Capítulo 8: Introducción al Testing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
Testing en Laravel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
Metodología TDD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92

Capítulo 9: API y nada mas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94


Verbos HTTP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
Estados HTTP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
Proyecto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96
ÍNDICE GENERAL

Store . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96
Validar al guardar un post . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104
Show . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107
Update . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113
Delete . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116
Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119
Usuarios Invitados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124

Parte 5: Ingeniería de Software . . . . . . . . . . . . . . . . . . . . . . . 126

Capítulo 10: PHP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127


Función como Parámetro . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127
Clases en PHP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128
Programación Orientada a Objetos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134

Capítulo 11: SOLID . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 152


Bases Sólidas de un Proyecto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 152
SOLID . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 159

Capítulo 12: SOLID en Laravel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 190


SOLID en la Práctica . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 190

Capítulo 13: Ingeniería de Software . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 195


Principios SOLID aplicados en Laravel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 195
SOLID . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 199
Controlador Final . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 221
Reflexión . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 222

Capítulo 14: Arquitectura . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 223


Fachada . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 223

Notas Finales . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 225

Feedback . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1

Actualizaciones del Libro . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2

Contactos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
Rimorsoft Online . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
Profesor Italo Morales F. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3

Guía de Futuros Pasos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4

Italo Morales F . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
ÍNDICE GENERAL

Mensaje Final . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
Sobre Nosotros
Somos una comunidad de programadores web de habla hispana. Nuestros temas son varios pero
giran entorno a PHP y lo enseñamos mediante Laravel.
Enseñamos a trabajar, nos gusta ayudar y consideramos como nuestro mayor placer ver a las
personas crecer, formar sus empresas o escalar rápidamente como empleados. Nuestra meta es usar
la tecnología de estudio de Rimorsoft para transformar la forma en que se enseña y así vencer las
barreras de estudio.
Somos reconocidos por la comunidad por nuestra entrega en cada video, libro o artículo educativo,
deseamos desarrollar de forma confiable, segura y rentable conocimientos con la calidad humana y
capacidad de Rimorsoft Online.
Desarrollamos líderes que se anticipan y adaptan al cambio, que aprenden de la experiencia e
innovan permanentemente.
Nuestra web https://rimorsoft.com
– Profesor, Italo Morales F.
Al Estudiante
Este es un curso completamente práctico, la idea real es enseñarte a trabajar y prepararte con
textos sencillos pero de gran competencia para enfrentarte al mundo laboral como un profesional
verdadero. En este caso te presento el maravilloso mundo llamado Laravel.
Este material es parte de una obra más extensa que te forma en varias áreas técnicas, donde al
juntar cada granito de arena buscamos desarrollarte como un programador web competente. Yo me
formé como programador y luego de unos años como profesor… La metodología aquí empleada está
probada y funciona.
No te ofrezco mas que ayudarte en el bello mundo del saber, específicamente en estos temas infor-
máticos. Espero que este libro sea un bonito viaje al descubrimiento y futuros logros empresariales.
Te deseo el mayor de los éxitos.
– Profesor, Italo Morales F.
Nota Importante
Al estudiar este libro me voy a asegurar de que realmente aprendas… En ese sentido necesito tu
ayuda, por favor no pases ninguna página si no está completamente claro el tema o si alguna palabra
no está totalmente comprendida.
Una persona abandona un estudio, libro, tema o un curso cuando no comprende, y esto no se debe
exactamente a la falta de capacidad, en realidad se debe a que el alumno no se atrevió a aclarar eso
que quedó confuso o muy poco claro.
Por favor no sigas adelante si algo parece confuso, la forma correcta de atacar es ir ANTES de que
tuvieras problemas, debes encontrar eso que no entiendes; definirlo y aclararlo hasta que tengas
una imagen clara del tema o palabra. Si lo haces así serás un gran profesional, serás una persona de
excelente competencia en el mercado laboral.
Recuerda que puedo ayudarte en cualquier momento. Escríbeme siempre que necesites ayuda a
[email protected] o a mis redes sociales, estoy para ayudarte.
– Profesor, Italo Morales F.
Agradecimiento
Te agradezco a ti de corazón lo hago. La confianza que me tienes es algo que me llena de mucha
alegría, emoción y al mismo tiempo me otorga una gran responsabilidad. Cuando recibo mensajes
de guía, investigación, en fin de invaluable colaboración siento el pago mas grande que a un profesor
le pueden dar.
Las palabras que busco no existen, pues mí agradecimiento hacia ti no consigo describirlo con
exactitud. Aunque no nos conozcamos considero que ya somos amigos y que estamos unidos por
cada video, tutorial, comentario, like y desafíos de programación que vencemos en el día a día.
Sigo con este loco invento llamado Rimorsoft Online gracias a ti querido suscriptor y ahora querido
alumno.
Desde aquí agradezco tu confianza.
De verdad mil gracias.
– Profesor, Italo Morales F.
Posibles Errores
Toda obra tiene varios filtros de calidad pero en quien más confío es en ti, eres el mejor control y
supervisor de calidad, si te consigues con algún error te pido paciencia y al mismo tiempo pido tu
ayuda.
Puedes mejorar esta obra enviando un email con cualquier error que hayas encontrado a i@
rimorsoft.com, envía un mensaje con los detalles necesarios para editarlo y publicar la nueva versión.
Los errores serán corregidos conforme se vayan descubriendo.
De esa manera estarías ayudando a cientos de personas que como tú han adquirido este libro.
Recuerda que es un producto Online y se actualizará automáticamente para todos, así ayudaremos
a todas las personas a aumentar y mejorar sus habilidades profesionales. Los reconocimientos los
haré publico en esta misma hoja.

Especial Mención - Año 2020


1. Ecuador: Segundo Jaramillo Romero.
2. México: Juan Carlos Sanchez.
3. Venezuela: Luis Cumare.

Por participar activamente. Estos alumnos mientras leían la versión 1.0 del libro con frecuencia me
hacían llegar las palabras que estaban mal escritas y las cosas que se entendían de una manera algo
rara.
Muchas gracias, este tipo de esfuerzos mejoran mucho el producto final.
Introducción
Bienvenida
Desde el canal me han escrito miles de veces (y no exagero) sobre la importancia de crear una serie
de Laravel que vaya de lo mas básico hasta lo mas avanzado, eso siempre estuvo en mi cabeza y
luego se materializó como LaravelEngineer.
Lo llamé así porque creo que quien pase por este material obtendrá la capacidad de crear grandes
cosas con este Framework. Este libro estará acompañado por mucho material gratuito sobre cada
una de las tecnologías.
Por ejemplo voy a crear las siguientes series para el canal.

1. Routes.
2. Controllers.
3. Middleware.
4. Requests.
5. Models.
6. Etc.

¿Entiende a que me refiero?, una serie por cada una de sus capas.
Cuando pensaba en crear una serie llamada “Laravel”, tenía en mente crear un video para las rutas,
otro video para los controladores y así, esto ya no será así y serán varios videos por cada una de sus
funciones. Prometo una serie por cada una de las capas.
¿Quieres ser Ingeniero en Laravel? Entonces acompañame…
Lee este libro y sigue cada uno de los videos del canal y cada uno de los artículos de nuestro sitio
web. Vamos a empezar bien.

¿Qué es Laravel?
Laravel es una herramienta que nos ayuda a desarrollar sistemas para el mundo web, puede ser
un sistema, página web o un API. A este tipo de herramientas se les llama Framework que es
precisamente un entorno de trabajo o herramienta estandarizada en cuanto a conceptos, buenas
prácticas, funciones comunes y estilo para resolver algún un tipo de problema.
Introducción vii

En nuestro caso ¿cuál era el problema? Precisamente escribir una sintaxis elegante y expresiva en
PHP. Es una sencilla pero gran alternativa porque cuenta con todas las funcionalidades que debe
tener un Framework de desarrollo.
Si empezamos un sistema desde cero en PHP debemos resolver problemas que ya están resueltos
como el inicio de sesión, registro de usuario, paginación de datos, conexión y consultas a la base de
datos, el sistema de cache, ruteo, seguridad, etc. Si necesito fabricar un proyecto educativo nota con
atención todo lo que debo resolver primero antes de realmente trabajar en el núcleo de mi sistema.
Un cliente no te paga porque has creado un sistema de inicio de sesión, esto es muy importante
porque también tiene un claro enfoque comercial. Por ejemplo un cliente te contrata para que le
fabriques el sistema de inventario, la página web, el registro de su recepción, etc. El cliente asume
que cuenta con inicio de sesión, registro, exportar a Excel y a PDF los datos, bitácora de cambios,
etc.
Es ahí donde ves el poder de este gran Framework.
En la pregunta ¿qué es Laravel? podemos responder “herramienta de desarrollo web escrito en PHP”.
Laravel es un proyecto que definitivamente te cambia la vida. Te lleva de la mano y al mismo tiempo
te introduce poco a poco en conceptos avanzados hasta que tengas un gran nivel como programador.
Un día podrás ver en el navegador un texto cualquiera y sabrás de inmediato qué ha sucedido. Sin
darte cuenta habrás pasado a través de la capa de las rutas y así por cada capa.
Dale tiempo, Laravel te hará un mejor programador.

1 <?php
2
3 Route::get('/', function () {
4 return 'Raíz de mi proyecto';
5 });

Luego sin tanta dificultad avanzamos y tocamos la capa del controlador.

1 Route::get('/', 'PageController@index');

Rápidamente podemos ver que tenemos en nuestra experiencia la capa de rutas y la de los
controladores. Detectamos que el sistema funciona pero algo nos dice que está mal programado
y comenzamos a tocar otras capas. Cada capa es la clave, lo debes imaginar y eso te ayudará
muchísimo.

1. Seguridad de acceso: Middleware.


2. Políticas: Policy.
3. Validación: Requests.
4. API: Resources.
Introducción viii

5. Lógica de datos: Models.


6. Presentación de datos: Views.
7. Control de calidad: Tests.
8. …y mucho más.

Poco a poco Laravel nos proporciona conceptos y nos dice cómo usarlos, a primera vista parece
que son técnicas impuestas por Laravel pero no es así, siempre han existido y es algo que puedes
aplicar en cualquier otro proyecto como Symfony, Django o en directamente en otros lenguajes de
programación.
Un programador debe saber de SOLID, de Programación Orientada a Objetos, Middlewares,
Requests, Models, Controllers, etc. Y Laravel te convierte en un mejor programador porque trae
consigo todos estos conceptos de una forma muy sencilla. La buena noticia es que si no dominas
ninguno de estos conceptos puedes igual usar a Laravel porque él no te obliga a implementarlos,
eres libre. A medida que avanzas mejoras de forma natural. En el futuro serás un buen programador
con capacidad para crear retos profesionales avanzados.
Taylor Otwell es un gran empresario, él sabe cómo construir sistemas de éxito y eso es principal-
mente lo que proporciona Laravel, con poco conocimiento podrás salir al mercado y crear retos
profesionales para cualquier cliente.
En el pasado usé Zend, Symfony, CodeIgniter y otras tecnologías con PHP como base, la decisión
de usar Laravel se basa en el principio de “no reinventar la rueda” y en la elegancia con la que
podemos escribir código, tenemos cubiertas las necesidades comunes y sin embargo no obliga a
implementarlas, es opcional y te lleva a manejar todos los estándares de desarrollo.
Me encanta su comunidad porque gira al alrededor de la mejora de si mismo, eso por supuesto ayuda
a que el Framework crezca y al mismo tiempo mejoramos nuestro trabajo como profesionales.
Laravel nos permite desarrollar a medida, personalización de componentes y estructura, nos brinda
seguridad, escalabilidad y mucha ayuda al momento del mantenimiento de software. Con Laravel
tenemos mucho código creado que no necesitamos repetir en cada proyecto. Puedes ser principiante
o avanzado en PHP en ambos casos Laravel te llevará a Senior.

¡Atención!

Actualizaciones
Este curso cada vez tendrá nuevas actualizaciones, tu solo hiciste un pago y tendrás acceso a todo
lo nuevo sin pagar nada adicional.

¿Cómo me puedes ayudar?


Puedes descargar el material pero quisiera me ayudes a no compartirlo… Al menos por un tiempo
para poder vivir del curso mientras logro fabricar otro, puedes quizás compartirlo con un familiar o
Introducción ix

un amigo, pero no más en este momento por favor. Al final el curso es tuyo, solo te lo pido como un
favor muy personal.

¿Podemos estar en contacto?


Tengo Instagram, Youtube, Facebook y Twitter, y parece que vamos a pasar mucho tiempo juntos
así que si quieres contactarme puedes escribirme cuando quieras, asegúrate de saludar en Slack en
el canal de #rimorsoft haciendo mención a @italomoralesf.
Recuerda que quiero saber de ti, no dudes en escribir al email [email protected].

Usa el Foro
Todo lo que no entiendas debes comentarlo en el foro de Rimorsoft https://rimorsoft.com/foro. Usa
esta herramienta recuerda que somos una comunidad y mantendremos contacto siempre.
Escribe allí tus preguntas, yo personalmente las revisaré y te daré respuesta.

Usa Slack
Chatea con otros y comparte experiencias, si no te he invitado escríbeme para invitarte, es fácil y
rápido formar parte de nuestra comunidad.

Regálame una mención


Difunde en Twitter e Instagram: Estoy estudiando el libro de #LaravelEngineer de @italomoralesf,
un Material Profesional de #rimorsoft
¡Te lo agradezco de corazón!.
Parte 1: Conceptos
Capítulo 1: Lo que debes saber
Qué es Laravel
Laravel es una herramienta que nos ayuda a desarrollar sistemas para el mundo web, puede ser
un sistema, página web o un API. A este tipo de herramientas de les llama Framework que es
precisamente un entorno de trabajo que estandarizada conceptos, buenas prácticas y estilo para
resolver algún problema. En nuestro caso ¿cuál era el problema? Precisamente escribir una sintaxis
elegante y expresiva en PHP.
Es una gran alternativa sencilla de usar porque cuenta con todas las funcionalidades que debe tener
un Framework de desarrollo.
Si empezamos un sistema desde cero en PHP debemos resolver problemas que ya están resueltos
como el inicio de sesión y registro, paginación de datos, la conexión y consultas a la base de datos,
el sistema de cache, rutas, seguridad, etc.
Si necesito fabricar un proyecto educativo nota con atención todo lo que debo resolver primero antes
de realmente trabajar en el núcleo de mi sistema. Un cliente no te paga porque has creado un sistema
de inicio de sesión, esto es muy importante porque también tiene un claro enfoque comercial. Por
ejemplo un cliente te contrata para que le fabriques el sistema de inventario, la página web, el registro
de su recepción, etc. El cliente asume que cuenta con inicio de sesión, registro, exportar a Excel y a
PDF lo datos, bitácora de cambios, etc.
Es ahí donde ves el poder de este gran Framework.
En la pregunta ¿qué es Laravel? podemos responder “herramienta de desarrollo web escrito en PHP”.

Su Poder
El poder está en que ya tiene muchas cosas resueltas. Inicio de sesión y registro, paginación de datos,
la conexión y consultas a la base de datos, el sistema de cache, rutas, sistema de plantillas avanzado,
seguridad y mucho más. Un cliente te paga porque resolviste su problema.

Consejos
Debemos entenderlo como un sistema de capas y de acuerdo al problema podrías entender que capa
debes tratar.

1. Puedes decidir crear una ruta y desde allí lanzar una vista si deseas.
Capítulo 1: Lo que debes saber 3

2. O hacer algo más organizado como crear una ruta, que esta apunte a un controlador y desde
allí lanzar o imprimir una vista en pantalla.
3. O podrías mantener el mismo orden pero agregando una capa de seguridad. Por ejemplo creas
la ruta, agregas una capa de seguridad y si esta logueado entonces el sistema permite ir al
controlador y luego lanza la vista deseada.

Qué necesitamos para su Instalación


Laravel es PHP y para ellos necesitamos convertir a nuestro equipo en un servidor web, esto se debe
a que PHP es un lenguaje del lado del servidor, esto significa que procesamos una petición de un
usuario mediante un código PHP en una computadora llamada servidor web, esta petición se procesa
y luego genera la respuesta deseada en páginas HTML.

Servidor HTTP
Un servidor HTTP es básicamente un programa que se instala en una computadora con el fin
de procesar un sistema web, con este programa instalado podemos recibir peticiones de usuarios
y podemos generar respuestas al cliente. Para crear un proyecto web necesitamos simular que
nuestro computador es un servidor y lo logramos instalando un programa, cuando hablamos de
PHP instalamos Apache o Nginx.

Lenguaje de Programación PHP


PHP es el lenguaje de programación que usaremos porque Laravel está construido en él, así que
necesitamos instalarlo para que nuestro Servidor HTTP interprete correctamente nuestro código.
Básicamente vamos a escribir en PHP así que instalamos el idioma en nuestro equipo.

La Base de Datos
Necesitamos instalar en nuestro equipo la base de datos, esta puede ser MySql o MariaDB. Ambas
funcionarían muy bien porque se entienden perfectamente con PHP.

Software: Todo en Uno.


¿Qué necesitamos?

1. Servidor web: Apache o Nginx.


2. Lenguaje: PHP.
3. Base de datos: MySql o MariaDB.
Capítulo 1: Lo que debes saber 4

Te recomiendo instalar la opción mas sencillas porque nuestro enfoque es la programación no


la administración de servidores, sin darnos cuenta estamos haciendo de nuestro computador un
servidor web y un servidor de base de datos.

1. XAMPP: https://www.apachefriends.org/es/download.html.
2. MAMP: https://www.mamp.info/en/downloads/.
3. En Mac: Podemos usar brew para instalar valet y por separado a PHP y MySql. El tutorial
completo está en la doc de Laravel https://laravel.com/docs/6.x/valet básicamente sería:
1. brew update.
2. brew install php.
3. brew install mysql.
4. composer global require laravel/valet.
5. Por último valet install.
4. También existe la opción de usar Homestead, esto es más avanzado y requiere una configura-
ción mayor, aquí la doc https://laravel.com/docs/6.x/homestead

Yo uso la opción número tres, sin embargo XAMPP y MAMP es muy válido y rápido. Recuerda que
la idea es despreocuparnos del servidor y enfocarnos en lo importante que es la programación en
PHP usando Laravel.

Herramientas
El método de instalación de Laravel es a través de Composer, un gestor de paquetes PHP que
provee todo lo que necesitemos respecto a este lenguaje. Puedes instalarlo desde este enlace
https://getcomposer.org/download/
También es muy importante contar con Git, este es nuestro control de versiones de nuestro software
y lo podemos instalar desde su web https://git-scm.com/downloads
Para escribir código necesitaremos a Sublime Text, Visual Studio Code o el editor que prefieras. Lo
mismo aplica para el navegador web, usa el que consideres importante para ti.

Resumen
¿Qué necesitamos para que nuestra computadora sea un servidor?:

1. Lenguaje: PHP >= 7.2.0.


2. Servidor: Apache o Nginx.
3. Base de datos: MySql o MariaDB.
4. Composer.
5. Git.
6. Editor de código.
7. Navegador.
Capítulo 1: Lo que debes saber 5

Instalación de Laravel
Podemos usar composer directamente o instalar un software llamado “instalador de Laravel”.

1. Con Composer sería composer create-project --prefer-dist laravel/laravel nombre-app.


2. Con Laravel Installer sería composer global require laravel/installer.

Puedes usar el método que gustes y todo al respecto lo conseguirás en este enlace: https://laravel.com/docs/6.x/installa

En Mac
Laravel siempre nos obligará a estar actualizado, te comparto este enlace: https://rimorsoft.com/actualizar-
a-php-7-3-x-con-homebrew-en-mac, te ayudará mucho si usas Mac y un entorno de trabajo parecido
al mío.

Temas Importantes
Hay muchas cosas muy básicas que no conocemos de Laravel, veamos aquí algunos temas de interés
que definitivamente te mostrarán un panorama mucho mas claro sobre esta gran herramienta. Esto
te ayudará a entender muchas cosas.

Archivo .env
Podemos configurar muchos módulos y a Laravel directamente en la carpeta config, pero es muy
útil tener valores de configuración para producción y otros para desarrollo, por ejemplo: Para eso
sirve el archivo .env que siempre configuramos para conectarnos a una base de datos.
Para que funcione Laravel usa la librería de PHP DotEnv creada por Vance Lucas. Básicamente este
archivo lleva ese nombre porque es ahí donde configuramos datos de acuerdo al entorno, en otras
palabras de acuerdo al environment. Saber estas cosas nos hace pensar con mayor sentido.
Importante, cada programador deberá tener su propio archivo .env y en producción debe estar otro
.env con los datos propios del servidor. Esto aumenta nuestra seguridad, nadie verá los tokens ni
nada del archivo .env porque no se comparte nunca.
Para evitar problemas se comparte el archivo .env.example, este archivo incluye una estructura
y datos falsos de ejemplos para que cada programador lo personalice. Este archivo permite ver
claramente cuáles son las variables necesarias y cada programador deberá personalizarlo.
Otro dato interesante es que podemos tener un archivo llamado .env.testing y este va a sobrescribir
al archivo principal .env cuando ejecutamos las pruebas. Esto es genial porque por ejemplo en
producción podemos trabajar con MySql y a nivel de pruebas trabajamos con SQLite.
Todo lo que aquí escribamos terminará siendo un string, sin embargo, puedes tener valores
booleanos, string, valores vacíos o valores nulos y si necesitas valores con espacios debes hacerlo
encerrando el valor en comillas dobles.
Capítulo 1: Lo que debes saber 6

1 APP_NAME="Rimorsoft Online"

Técnicamente todas estas variables se guardarán en el superglobals de PHP, específicamente en la


superglobals $_ENV. Podemos acceder o utilizar el helper incorporado en Laravel env() para obtener
cualquier valor. Por ejemplo para obtener el nombre del sistema podría usar env('APP_NAME',
'Laravel'), si la variable no existe entonces se usará el valor por defecto “Laravel” porque fue
el que he configurado.

Superglobals son variables internas que estarán disponibles siempre en todos los ámbitos
del proyecto, existen las siguientes: $GLOBALS, $_SERVER, $_GET, $_POST, $_FILES,
$_COOKIE, $_SESSION, $_REQUEST y $_ENV, esto ayuda a no crear variables globales,
usamos las superglobals y resolvemos el problema deseado.

Podemos mediante un if tener diferentes comportamientos en un mismo sistema, no es lo más


común ni lo más frecuente pero es bueno saber que esto existe.

1 $environment = App::environment(); // Obtenemos el entorno

1 if (App::environment('local')) {
2 // Hacer algo en un entorno local
3 }

Es útil, saca de apuros precisamente cuando un sistema maneja varios entornos.

Carpeta de Configuración
El archivo .env trabaja muy de la mano con la carpeta config, en esta carpeta conseguimos la
configuración de Laravel en general y mucha configuración de los paquetes que instalamos. Vemos
a .env para guardar valores importantes y en la carpeta config conseguimos a las variables.
Podemos acceder fácilmente a estos valores con un helper global llamado config() desde cualquier
parte de nuestro sistema.

• config es la carpeta.
• config() es el helper.

Puedo crear un archivo llamado config/rimorsoft.php y creo lo siguiente:


Capítulo 1: Lo que debes saber 7

1 <?php
2
3 return [
4 'main-color' => '#00ACED',
5 ];

Crear este archivo hace que se integre a Laravel automáticamente a mi proyecto y podría acceder
directamente a este valor con el helper config('rimorsoft.main-color'). El estándar es nombre del
archivo, seguido por un punto y luego el nombre del key del array que en este caso es main-color.
Si el archivo es config/app.php podría acceder a un valor siguiendo el mismo estándar, por ejemplo
config('app.timezone'). Puedes agregar sin problema los key que necesites o los archivos de
configuración que consideres oportunos.

Laravel en Mantenimiento
He cometido el error de subir cambios a mi proyecto sin poner mi sistema en mantenimiento y mis
visitantes observan mil errores. Esto es grave, no debería pasar y lo ideal es que cuando nuestro
proyecto esté en modo de mantenimiento muestre una vista personalizada.
Para activarlo solo necesitamos ejecutar el comando correcto de artisan.

1 $ php artisan down

En este punto tendremos una respuesta HTTP 503 que significa “Servicio No Disponible”, al activarlo
veremos un mensaje por defecto y podemos personalizarlo de la siguiente manera:

1 $ php artisan down --message="Actualizando Módulo Usuarios"

Y para permitir solo algunas conexiones debemos especificarlas como una sola IP o un grupo de IPs.
Tenemos el siguiente ejemplo:

1 $ php artisan down --message="Actualizando el Sistema" --allow="127.0.0.1"

Observa cómo podemos combinar diferentes parámetros, en este caso el mensaje y la IP permitida.
Para un grupo podría especificar el rango 192.168.1.0/20. Tu decides.
Si el sistema ya responde como se espera podemos deshabilitar el modo de mantenimiento
cambiando down por up.

1 $ php artisan up

Recuerda que puedes personalizar las respuestas de estados HTTP creando la vista con el nombre del
error que deseas personalizar, en este caso sería resources/views/errors/503.blade.php, puedes
personalizar de la misma manera los estados 404, 500 y los que desees.
Capítulo 1: Lo que debes saber 8

Ciclo de Vida
Hablemos de algo muy importante, se trata de conocer mas al detalle cómo funcionan las herra-
mientas con las que trabajamos, esto nos proporciona por supuesto mucha seguridad y vamos con
mayor confianza en la vida. El objetivo es conocer un poco mejor a Laravel.
Anécdota: Una vez en el 2008 le pregunté a mi jefe, “¿cómo Symfony sabe que va a imprimir allí esos
datos?” y él me respondió “eso es magia”. Esto está mal, yo prefiero tener un enfoque de ingeniería
para saber exactamente el porqué de cada cosa.

Etapa inicial
En Laravel todo comienza en public/index.php. Este es el punto de partida y el resto se carga
después. Aquí vamos a encontrar el archivo vendor/autoload.php que carga las clases y espacios
de trabajo PHP, luego se inicia a Laravel. Este inicio de Laravel incluye la carga de componentes
o paquetes de base de datos, la validación, componentes de rutas y todo lo que tu sistema vaya a
utilizar.
Ahora la solicitud va al sistema de rutas y reacciona una ruta.

Resumen
Si lo definimos en pasos tenemos lo siguiente:

1. Vamos al index.php.
2. Cargan las clases PHP.
3. Se inicia Laravel y se prepara para responder vía HTTP, consola o se manejará un error.
4. Y finalmente comienza lo que apreciamos en pantalla, hablo de las rutas, controladores,
middleware, vistas, etc.

¡Es realmente así de simple!


Lo valioso de esto es que ahora conocemos claramente cómo se construye y arranca un sistema
hecho en Laravel. Nuestro trabajo comienza en el paso 4 y saberlo nos ayudará a determinar si una
falla está en nuestro código o en Laravel directamente.
Capítulo 2: Laravel es Poderoso
CRUD en Laravel
Vamos a descubrir el poder de Laravel, veamos cómo en pocos textos construimos un proyecto.

Instalación
1 $ laravel new crud

Configurar Base de datos


1. Configuración de la base de datos: Creamos la base de datos crud en nuestro cliente de base
de datos, en mi caso es SequelPro.
2. Edito el archivo .env:

1 //...
2 DB_CONNECTION=mysql
3 DB_HOST=127.0.0.1
4 DB_PORT=3306
5 DB_DATABASE=crud
6 DB_USERNAME=root
7 DB_PASSWORD=
8 //...

1. Ejecuto las migraciones: php artisan migrate


Capítulo 2: Laravel es Poderoso 10

1 Migration table created successfully.


2 Migrating: 2014_10_12_000000_create_users_table
3 Migrated: 2014_10_12_000000_create_users_table (0.04 seconds)
4 Migrating: 2014_10_12_100000_create_password_resets_table
5 Migrated: 2014_10_12_100000_create_password_resets_table (0.08 seconds)
6 Migrating: 2019_08_19_000000_create_failed_jobs_table
7 Migrated: 2019_08_19_000000_create_failed_jobs_table (0.03 seconds)

Creamos 12 usuarios con php artisan tinker y dentro ejecutamos el factory de usuarios
factory(App\User::class, 12)->create()

Tinker: Es la consola de comando que incluye Laravel con la que podremos interactuar
con las clases y métodos de nuestra aplicación, es una gran herramienta para realizar
pruebas de funcionamiento.

Route
1 Route::get('/', 'UserController@index');
2 Route::post('users', 'UserController@store')->name('users.store');
3 Route::delete('users/{user}', 'UserController@destroy')->name('users.destroy');

Tabla de Rutas

1 Método URI Nombre Acción


2 GET / -- UserController@index
3 POST users users.store UserController@store
4 DELETE users/{user} users.destroy UserController@destroy

Nota: Para ver las rutas contamos con el comando php artisan route:list

Controller: UserController
Capítulo 2: Laravel es Poderoso 11

1 <?php
2
3 namespace App\Http\Controllers;
4
5 use App\User;
6 use Illuminate\Http\Request;
7
8 class UserController extends Controller
9 {
10
11 public function index()
12 {
13 $users = User::latest()->get();
14
15 return view('users.index', [
16 'users' => $users
17 ]);
18 }
19
20 public function store(Request $request)
21 {
22 $request->validate([
23 'name' => ['required'],
24 'email' => ['required', 'email', 'unique:users'],
25 'password' => ['required', 'min:8'],
26 ]);
27
28 User::create([
29 'name' => $request->name,
30 'email' => $request->email,
31 'password' => bcrypt($request->password),
32 ]);
33
34 return back();
35 }
36
37 public function destroy(User $user)
38 {
39 $user->delete();
40
41 return back();
42 }
43 }
Capítulo 2: Laravel es Poderoso 12

View: welcome.blade.php
Colocamos el CDN de bootstrap 4 en el head.

<link rel=”stylesheet” href=”https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css”


integrity=”sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh”
crossorigin=”anonymous”>

1 <body>
2 <div class="container">
3 <div class="row">
4 <div class="col-sm-8 mx-auto">
5 <div class="card shadow my-4 border-0">
6 <!-- Formulario -->
7 </div>
8
9 <!-- Tabla de usuarios -->
10 </div>
11 </div>
12 </div>
13 </body>

1 <table class="table">
2 <thead>
3 <tr>
4 <th>#</th>
5 <th>Nombre</th>
6 <th>Email</th>
7 <th>&nbsp;</th>
8 </tr>
9 </thead>
10 <tbody>
11 @foreach($users as $user)
12 <tr>
13 <td>{{ $user->id }}</td>
14 <td>{{ $user->name }}</td>
15 <td>{{ $user->email }}</td>
16 <td>
17 <form action="{{ route('users.destroy', $user) }}" method="POST">
18 @method('DELETE')
19 @csrf
Capítulo 2: Laravel es Poderoso 13

20 <input
21 type="submit"
22 value="Eliminar"
23 class="btn btn-danger btn-sm"
24 onclick="return confirm('¿Desea eliminar... ?')"
25 >
26 </form>
27 </td>
28 </tr>
29 @endforeach
30 </tbody>
31 </table>

Formulario de usuario

1 <form action="{{ route('users.store') }}" method="POST">


2 <div class="card shadow my-4 border-0">
3 <div class="card-body">
4
5 @if($errors->any())
6 <div class="alert alert-danger">
7 @foreach($errors->all() as $error)
8 - {{ $error }} <br>
9 @endforeach
10 </div>
11 @endif
12
13 <div class="form-row">
14 <div class="col-sm-3">
15 <input
16 type="text"
17 name="name"
18 class="form-control"
19 placeholder="Nombre"
20 value="{{ old('name') }}"
21 >
22 </div>
23 <div class="col-sm-4">
24 <input
25 type="text"
26 name="email"
27 class="form-control"
Capítulo 2: Laravel es Poderoso 14

28 placeholder="Email"
29 value="{{ old('email') }}"
30 >
31 </div>
32 <div class="col-sm-3">
33 <input
34 type="password"
35 name="password"
36 class="form-control"
37 placeholder="Contraseña"
38 >
39 </div>
40 <div class="col-auto">
41 @csrf
42 <button type="submit" class="btn btn-primary">Enviar</button>
43 </div>
44
45 </div>
46 </div>
47 </form>

Aquí vemos claramente cómo el objetivo de Laravel se cumple. El objetivo es escribir una sintaxis
elegante y expresiva en PHP y además entendemos de mejor manera que también tiene un claro
enfoque comercial. En este caso vamos a imaginar que el cliente necesitaba el registro de usuarios
sencillo, fácil y manejable.
Cuando resolvemos el problema podemos cobrar nuestro dinero y todo está también organizado que
podríamos continuar en el futuro extendiendo este proyecto. Analiza, esto lo hicimos en una clase
de algunos minutos, imagina lo que pudieras construir en un proyecto de seis meses.
Entrega al cliente la solución esperada.
Parte 2: Fundamentos
Capítulo 3: Te Presento a Laravel
Estructura de Carpetas
Raíz del proyecto: app, bootstrap, config, database, public, resources, routes, storage, tests,
vendor.

Dentro de app: Broadcasting, Console, Events, Exceptions, Http, Jobs, Listeners, Mail, Notifications,
Policies, Providers, Rules.

Con el trabajo del día a día nos vamos aprendiendo el uso y la ubicación de cada carpeta, esto tiene
años evolucionando y nos proporciona un gran punto de partida para desarrollar cualquier tipo de
sistema. Con el tiempo tendrás la habilidad de crear cualquier estructura de carpetas, la que más se
adapte a ti o la que necesites implementar.
De momento mi recomendación es trabajar únicamente con lo que Laravel propone, así avanzaremos
mejor en nuestro aprendizaje.

App
Es la carpeta donde desarrollamos toda nuestra programación, allí escribimos principalmente todo
nuestro código PHP.
Aquí dentro encontramos una variedad importante de carpetas como Console, Http, Exceptions
y Providers. En Console tenemos a nuestros comandos personalizados de Artisan y en Http
conseguimos a nuestros controladores, middleware y el procesamiento de solicitudes, por eso se
llama Http.
No veremos más carpetas, el resto se genera cuando usamos el comando make de Artisan. Veamos el
listado.

1 $ php artisan make:channel


2 $ php artisan make:command
3 $ php artisan make:component
4 $ php artisan make:controller
5 $ php artisan make:event
6 $ php artisan make:exception
7 $ php artisan make:factory
8 $ php artisan make:job
9 $ php artisan make:listener
10 $ php artisan make:mail
Capítulo 3: Te Presento a Laravel 17

11 $ php artisan make:middleware


12 $ php artisan make:migration
13 $ php artisan make:model
14 $ php artisan make:notification
15 $ php artisan make:observer
16 $ php artisan make:policy
17 $ php artisan make:provider
18 $ php artisan make:request
19 $ php artisan make:resource
20 $ php artisan make:rule
21 $ php artisan make:seeder
22 $ php artisan make:test

Esta lista está en constante actualización, pero si manejas esta teoría no tendrás problemas cuando
lleguen nuevas actualizaciones. Esta lista la conseguí yendo al terminal y ejecutando el comando
php artisan list make y si deseas ver todos los comandos que existen puedes ejecutar solamente
php artisan.

Repasemos cada carpeta dentro de app y luego continuamos con las carpetas de la raíz.

Broadcasting

Esta carpeta se genera con el comando php artisan make:channel. La usaremos si necesitamos
canales de transición de eventos.

Console

Aquí encontramos a nuestros comandos personalizados de artisan. Si en el futuro creas un comando


personalizado vas a trabajar en esta carpeta. Las clases que estarán allí las puedes generar con el
comando php artisan make:command.
En esta carpeta encontramos al archivo kernel.php, es allí donde registramos a nuestros comandos.

Events

Esta carpeta se crea cuando usamos el comando php artisan event:generate y php artisan
make:event. Aquí guardamos a nuestras clases de eventos que generen alertas luego de ejecutar
una acción.

Exceptions

Aquí configuramos a nuestras clases que se dediquen a responder a cualquier cosa que ocurra.
Ya existe y cuenta con el manejador de excepciones, allí creamos cualquier control de excepción.
Cuando estamos empezando nos quedamos con la configuración estándar.
Capítulo 3: Te Presento a Laravel 18

Http

Aquí tenemos a nuestros Controllers, Middleware y Form Requests, allí vive casi todo nuestro
sistema ya que desde ahí manejamos las solicitudes HTTP.

Jobs

Esta carpeta se crea cuando usamos el comando php artisan make:job. Allí almacenamos a nuestras
clases dedicadas al control de colas de trabajo. Podemos crear una cola de las tareas pesadas para
ejecutar luego, esto ayuda muchísimo en cuanto al rendimiento de nuestro sistema.

Listeners

Esta carpeta se crea cuando usamos el comando php artisan event:generate y php artisan
make:listener. Aquí guardamos a nuestras clases que van a manejar nuestros eventos (los events y
los listeners trabajan juntos). Los listeners se ejecutan cuando un evento lo ordene. Por ejemplo, un
evento de registro de cliente puede manejar el evento de email de bienvenida.

Mail

Aquí tendremos a las clases que representan a un email, se crea cuando usamos el comando php
artisan make:mail. Por ejemplo el email de bienvenida que acabo de mencionar estaría aquí
configurado.

Notifications

Esta carpeta se crea cuando usamos el comando php artisan make:notification. Aquí tendremos
a nuestras notificaciones guardadas para que sean enviadas por nuestro sistema cuando se necesite.
Las notificaciones podrían ser un mensaje de texto, emails, guardadas en base de datos para mostrar
al usuario, etc. Cuando la campana de twitter se enciende es porque una notificación lo generó.

Policies

Esta carpeta la podemos crear con el comando php artisan make:policy. Aquí vamos a guardar a
nuestras clases dedicadas a las políticas de autorización. Podrás determinar si un usuario cuenta con
la habilidad de eliminar artículos por ejemplo.

Providers

Aquí tenemos a los famosos proveedores de servicios, estos enlazan a los componentes con Laravel.
Podemos crear nuestros propios providers en esta carpeta y usarlo desde Laravel. Por lo general
cuando instalamos un paquete, este nos dice cómo conectar a Laravel con su provider.
Capítulo 3: Te Presento a Laravel 19

Rules

La podemos crear con el comando php artisan make:rule. Aquí registramos reglas de validación
propias o personalizadas.

Bootstrap
Podría ser bootstrap o bootstrapping, siempre que veas esta palabra debes saber que hace referencia
al inicio de un sistema informático. En este caso bootstrap/app.php inicia a Laravel. Aquí también
encuentras una carpeta llamada cache que contiene archivos de rutas y servicios generados por el
sistema para optimizarlos y mejorar el rendimiento.

Config
Aquí encontraremos todos los archivos de configuración de nuestro sistema. De hecho cuando
podamos crear paquetes vamos a guardar nuestros archivos de configuración en esta carpeta. Aquí
conseguiremos los archivos de la aplicación, base de datos, cache y muchos otros.

Database
El directorio database contiene las migraciones de tu base de datos, model factories y seeders. Si lo
deseas puedes también usar este directorio para almacenar una base de datos SQLite.

Public
Aquí encontramos al archivo index.php, es el punto de acceso de todas las solicitudes y nunca
trabajamos con este archivo directamente, también podemos encontrar a las imágenes, los archivos
JS y los documentos de estilos CSS. “Todo lo público estará en esta carpeta”.

Resources
Aquí vamos a guardar a nuestras vistas y archivos originales de LESS, SASS, Stylus o JS, también
vamos a encontrar los archivos de configuración de idioma.

Routes
Aquí tendremos todas las rutas de nuestro sistema. De inmediato encontramos los siguientes
archivos:

1. web.php
2. api.php
Capítulo 3: Te Presento a Laravel 20

3. console.php
4. channels.php.

Veamos uno a uno con las explicaciones de una manera sencilla.

1. Las rutas configuradas en el archivo web.php contaran con un estado de sesión, protección de
formularios CSRF y la encriptación estándar de cookies. Siempre trabajaremos aquí.
2. En api.php vamos a configurar a las rutas que precisamente tengan que ver con el acceso a
un API, al hacerlo inmediatamente contaremos con una limitación de velocidad y la seguridad
propia y estándar de un API. Lo que aquí configuremos estará preparado para trabajar con
tokens de acceso y no el estado de sesión como en web.php.
3. En console.php definimos todos los accesos que serán basados en comandos o desde un
terminal. Cada ruta es un Closure enlazado a una acción. Configurar aquí algunas rutas nos
ayudará a trabajar de forma simple la interacción con métodos de entrada y salida.
4. En channels.php registramos canales para emitir transmisiones de eventos. Entre otras cosas
aquí trabajaremos cuando estemos interesados en configurar notificaciones del lado del cliente
cuando algo sucede en el servidor.

Storage
Storage significa “almacenamiento”, esto da una idea de su utilidad y aquí encontramos a las
plantillas compiladas de Blade, sesiones basadas en archivos, archivos de cache y otros archivos
generados por el Framework, es muy común usar esta carpeta para guardar a nuestras imágenes que
luego accedemos desde public a través de un enlace simbólico “acceso directo”.
Dentro vamos a encontrar a las carpetas app, framework y logs.

1. La carpeta app la usamos para guardar cualquier archivo generado con intención como las
imágenes, los PDF, etc.
2. En framework conseguimos a los archivos generados por Laravel y a la cache.
3. Por último logs, aquí veremos a los famosos archivos .log con la información de registro
generada.

Tests
Cuando trabajamos con la metodología TDD o usamos a PHPUnit trabajamos en esta carpeta.
Si estamos comenzando en este mundo de la programación no tocamos esta carpeta porque
programamos de una forma sencilla.

Vendor
Es una carpeta estándar en los proyectos PHP, aquí se guardan todas las dependencias generadas
por Composer.
Capítulo 3: Te Presento a Laravel 21

¿Y dónde se guardan los modelos?


Puedes crear una carpeta dentro de app llamada entities o models, o usar la configuración propia
de Laravel que lanza a nuestros modelos en app directamente, por ejemplo podemos encontrar a
app/User.php dónde User.php representa a nuestro modelo de usuarios.

No hay restricción al respecto, podrás usar la configuración que necesites.


Existe una definición simple de cada carpeta, toma en cuenta que tendrás que trabajar con algunas
y de hecho con un reducido número de carpetas, entre ellas tenemos:

1. app/Http/Controllers
2. app/Http/Middleware
3. app/Http/Requests
4. database/migrations
5. resources/views
6. routes

Esto sería lo ideal, es un buen comienzo manejarse con fluidez en estas carpetas.

Sistema de Rutas, URLs y Controladores


Para aprender sobre las rutas y controladores vamos a instalar un proyecto completamente desde
cero.

1 $ laravel new routes

Carpetas y sus conceptos:

1. /routes: Camino o dirección que se toma para algún propósito.


2. /app/Http/Controllers: Dirige y su función principal es resolver las peticiones.

Routes

Básicas

Podemos crear algo realmente sencillo en el archivo web.php.


Capítulo 3: Te Presento a Laravel 22

1 Route::get('prueba', function () {
2 return 'Hola';
3 });

Si accedemos al navegador y escribimos http://routes.test/prueba veremos el resultado. Accedo


de esta manera porque estoy usando valet, en tu caso quizás debes usar otra forma de acceder.
Veamos otra forma:

1 Route::get('/', function () {
2 return view('welcome', ['app' => 'Desde ruta raíz']);
3 });
4
5 // http://routes.test/
6
7 Route::view('vista', 'welcome', ['app' => 'Desde la URI vista']);
8
9 // http://routes.test/vista

Ambas rutas devolverán la vista welcome pero con diferentes valores en la variable $app.

1 <!DOCTYPE html>
2 <html lang="es">
3 <head>
4 </head>
5 <body>
6 <div class="flex-center position-ref full-height">
7 <div class="content">
8 <div class="title m-b-md">
9 {{ $app }}
10 </div>
11 </div>
12 </div>
13 </body>
14 </html>

Route::view() es algo que pudieras implementar en vistas estáticas, por ejemplo contáctenos, sobre
nosotros, términos, privacidad o lineamientos. Yo lo uso para la vista italomoralesf donde hablo
sobre mis redes sociales, algún texto, foto, etc. Esto no necesita mayor procesamiento así que esto
funcionaria bastante bien.
Capítulo 3: Te Presento a Laravel 23

Parámetros

Lo usamos cuando necesitamos capturar elementos o parámetros para buscar un dato en la base de
datos, podría ser un usuario, artículo del blog o cualquier cosa en general, esto es lo que se conoce
como dinamismo porque es una ruta y una misma vista pero dependiendo del parámetro vamos a
mostrar un contenido u otro.

1 //Parámetros
2 Route::get('app/{app}', function ($app) {
3 return view('welcome', ['app' => $app]);
4 });
5
6 //Opcionales: Esto lo logramos con el signo de interrogacion ?
7 Route::get('app/{app?}', function ($app = 'Rimorsoft') {
8 return view('welcome', ['app' => $app]);
9 });

Nombre de Rutas

Vamos a nombrar una ruta y vamos a vincularla con un controlador, toma en cuenta que hemos
trabajado solamente en la capa de rutas, vamos a extender y a ocupar otra capa de nuestro sistema
y es precisamente los controladores.
Creamos el controlador

1 $ php artisan make:controller PageController

Creamos la ruta

1 /**
2 Route::get('/', function () {
3 return view('welcome', ['app' => 'Desde ruta raíz']);
4 });
5 **/
6
7 Route::get('/', 'PageController@index')->name('home');

En el controlador
Capítulo 3: Te Presento a Laravel 24

1 <?php
2
3 namespace App\Http\Controllers;
4
5 use Illuminate\Http\Request;
6
7 class PageController extends Controller
8 {
9 public function index()
10 {
11 return view('welcome', ['app' => 'Desde un Controlador']);
12 }
13 }

HTML

1 <!DOCTYPE html>
2 <html lang="es">
3 <head></head>
4 <body>
5 <div class="flex-center position-ref full-height">
6 <div class="content">
7 <div class="title m-b-md">
8 {{ $app }}
9 </div>
10
11 <div class="links">
12 <a href="{{ route('home') }}">Ir al Home</a>
13 </div>
14 </div>
15 </div>
16 </body>
17 </html>

Controlador
Podemos crear un controlador con las funciones típicas de un CRUD.

1 $ php artisan make:controller PostController --resource --model=Post

Cuando usamos esta linea y Laravel detecta que no existe el modelo Post nos pregunta si deseamos
crearlo, podemos decir si aunque no lo trataremos en este ejercicio.
Capítulo 3: Te Presento a Laravel 25

1 $ php artisan make:controller UserController --resource --model=User

Aquí no nos pregunta por el modelo User porque este viene creado por defecto en Laravel, está ahí
desde su instalación.
Las rutas de recursos se crean de la siguiente forma.

1 Route::resources([
2 'posts' => 'PostController',
3 'users' => 'UserController'
4 ]);

Por lo general usamos la siguiente manera:

1 Route::resource('users', 'UserController');

Pero como tenemos varios controladores podemos apreciar que acepta un Array para no tener una
línea por cada controlador.
Otra vez queda demostrado el tema de las capas y cómo podemos usar estas grandes herramientas
para crear un sistema profesional. Estos son los fundamentos y si los conocemos bien podremos
crear cualquier cosa con Laravel y cobrar la cantidad adecuada por estos proyectos.

Capa de Middleware
Instalaré otro proyecto Laravel para que al explicarte no necesites editar lo que ya desarrollé en los
ejercicios pasados.

Setup
1 $ laravel new middleware --auth

Revisamos en el navegador para constatar que no contamos con los estilos, visita la vista de login
para comprobarlo.
Vamos al proyecto con cd middleware
Instalamos las dependencias NPM

1 $ npm install

Ejecutamos estos archivos para generar archivos finales


Capítulo 3: Te Presento a Laravel 26

1 $ npm run dev

Tabla Users

1 <?php
2
3 use Illuminate\Database\Migrations\Migration;
4 use Illuminate\Database\Schema\Blueprint;
5 use Illuminate\Support\Facades\Schema;
6
7 class CreateUsersTable extends Migration
8 {
9 //...
10 public function up()
11 {
12 Schema::create('users', function (Blueprint $table) {
13 $table->bigIncrements('id');
14 $table->string('name');
15 $table->string('email')->unique();
16 $table->timestamp('email_verified_at')->nullable();
17 $table->string('password');
18
19 $table->boolean('subscribed')->default(false);
20
21 $table->rememberToken();
22 $table->timestamps();
23 });
24 }
25 //...
26 }

1. Creo la base de datos llamada middleware.


2. Configuro el archivo .env para que apunte a esta base de datos.
3. Ejecuto php artisan migrate .
4. Uso tinker php artisan tinker.
5. Creo un usuario: App\User::create(['name' => 'Italo', 'email' => '[email protected]',
'password' => bcrypt('123456')]).

En resumen tengo:

1. Ya tengo un proyecto.
2. Una base de datos y una conexion.
3. Una tabla con el campo subscribed.
4. Y un usuario para probar el sistema.
Capítulo 3: Te Presento a Laravel 27

Middleware Predeterminado

Con el middleware protejo mi ruta: Este es un middleware que ya viene en Laravel y podemos usar
de inmediato.

1 Route::get('/home', 'HomeController@index')->name('home')->middleware('auth');

Middleware Personalizado

Laravel tiene middleware por defecto, sin embargo, podemos crear el que queramos para cubrir
cualquier necesidad.

1 $ php artisan make:middleware Subscribed

Este se crea en app/Http/Subscribed.php.


Ahí escribimos el siguiente código.

1 <?php
2
3 namespace App\Http\Middleware;
4
5 use Closure;
6
7 class Subscribed
8 {
9 //...
10 public function handle($request, Closure $next)
11 {
12 if ( ! $request->user()->subscribed) {
13 return abort(403, 'Sin suscripción activa');
14 }
15
16 return $next($request);
17 }
18 }

403: La solicitud fue legal, fue correcta, pero el servidor no la responderá porque el cliente no tiene
los privilegios o permisos.
Registro el middleware
Capítulo 3: Te Presento a Laravel 28

1 <?php
2
3 namespace App\Http;
4
5 use Illuminate\Foundation\Http\Kernel as HttpKernel;
6
7 class Kernel extends HttpKernel
8 {
9 //...
10 protected $middleware = [];
11
12 //...
13 protected $middlewareGroups = [];
14
15 //...
16 protected $routeMiddleware = [
17 'auth' => \App\Http\Middleware\Authenticate::class,
18 'subscribed' => \App\Http\Middleware\Subscribed::class,
19 ];
20
21 //...
22 protected $middlewarePriority = [];
23 }

Actualizo la ruta.

1 Route::get('/home', 'HomeController@index')
2 ->name('home')
3 ->middleware('auth', 'subscribed');

Acá vemos la forma correcta de proteger a nuestras rutas, lo importante es definir qué queremos
proteger y crear la lógica en un archivo aparte. Otra cosa importante es que creando un middleware
podemos proteger haciendo un llamado y no copiando este if condicional en cada parte del código.
Una persona con poca experiencia usaría este mismo if en las vistas o en cada método de un
controlador. Esto funcionaria pero no es la manera correcta de trabajar, si tienes esta lógica de
protección en muchas partes tendrás un fuerte dolor de cabeza cuando te toque modificarla.

Validación de datos (vistas, formularios y


controladores)
La validación es algo importante en todo sistema web, toma en cuenta que cada cosa que estás
aprendiendo en este libro involucra una nueva capa, un nuevo archivo que aísla cierta lógica. En
Capítulo 3: Te Presento a Laravel 29

este caso por ejemplo aislamos el código de una validación.

Setup
1 $ laravel new formrequest

Vamos a esa carpeta

1 $ cd formrequest

Preparamos la ruta
1 Route::get('/', function () {
2 return view('post');
3 });
4
5 Route::post('posts', 'PostController@store')->name('posts.store');

Vista
Esta se crea con el nombre post.blade.php dentro de resources/views.

1 <!DOCTYPE html>
2 <html lang="es">
3 <head>
4 <meta charset="utf-8">
5 <meta name="viewport" content="width=device-width, initial-scale=1">
6
7 <title>Laravel</title>
8
9 <link
10 rel="stylesheet"
11 href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap\
12 .min.css"
13 integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9M\
14 uhOf23Q9Ifjh"
15 crossorigin="anonymous"
16 >
17 </head>
18 <body>
Capítulo 3: Te Presento a Laravel 30

19 <div class="container">
20 <div class="row">
21 <div class="col-6 mx-auto">
22 <h1>Crear Post</h1>
23
24 <form action="{{ route('posts.store') }}" method="POST">
25 <div class="form-group">
26 <label>Tema</label>
27 <input type="text" name="title" class="form-control">
28 </div>
29 <div class="form-group">
30 <label>Contenido</label>
31 <textarea name="body" class="form-control"></textarea>
32 </div>
33 @csrf
34 <button type="submit" class="btn btn-primary">Enviar</button>
35 </form>
36 </div>
37 </div>
38 </div>
39 </body>
40 </html>

Enlace a Bootstrap: https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css


Atributo integrity: Se usa para incluir un metadato que será usado por el “user agent”
del navegador, esto ayuda a verificar si el CSS está libre de manipulación. Se usa en las
etiquetas <script> y <link>.

Controlador
1 $ php artisan make:controller PostController

Podemos avanzar tranquilos porque ya las rutas y el formulario existen.


Capítulo 3: Te Presento a Laravel 31

1 <?php
2
3 namespace App\Http\Controllers;
4
5 use Illuminate\Http\Request;
6
7 class PostController extends Controller
8 {
9
10 public function store(Request $request)
11 {
12 return $request->all(); //que recibimos para luego validar
13 }
14
15 }

Hago las prácticas

1. Presiono guardar y vemos que podemos recibir los datos vacios.


2. Ahora hago la práctica de validación.

1 <?php
2
3 namespace App\Http\Controllers;
4
5 use Illuminate\Http\Request;
6
7 class PostController extends Controller
8 {
9
10 public function store(Request $request)
11 {
12 $request->validate([
13 'title' => ['required'],
14 'body' => ['required']
15 ]);
16
17 return $request->all(); //guardado
18 }
19
20 }
Capítulo 3: Te Presento a Laravel 32

1. Ahora veo que no puedo llegar al controlador, entonces configuro los campos de recordar con
el helper old() incluido en Laravel.

1 <form action="{{ route('posts.store') }}" method="POST">


2 <div class="form-group">
3 <label>Tema</label>
4 <input
5 type="text"
6 name="title"
7 class="form-control"
8 value="{{ old('title') }}"
9 >
10 </div>
11 <div class="form-group">
12 <label>Contenido</label>
13 <textarea
14 name="body"
15 class="form-control">{{ old('body') }}</textarea>
16 </div>
17 @csrf
18 <button type="submit" class="btn btn-primary">Enviar</button>
19 </form>

1. Ahora como vemos en la vista el feedback, configuro en pantalla a los errores.

1 @if ($errors->any())
2 <div class="alert alert-danger">
3 @foreach ($errors->all() as $error)
4 - {{ $error }} <br>
5 @endforeach
6 </div>
7 @endif
8
9 <!-- formulario -->

Form Request
Esto está funcionando muy bien pero no es correcto dejar la validación en el controlador, con dos
campos funciona muy bien pero con varios campos mas empezaran los problemas, así que la aislamos
en otro archivo todo el tema de la validación.
Capítulo 3: Te Presento a Laravel 33

1 $ php artisan make:request PostRequest

Archivo de validación

1 <?php
2
3 namespace App\Http\Requests;
4
5 use Illuminate\Foundation\Http\FormRequest;
6
7 class PostRequest extends FormRequest
8 {
9 //...
10 public function authorize()
11 {
12 return true;
13 }
14
15 //...
16 public function rules()
17 {
18 return [
19 'title' => ['required'],
20 'body' => ['required']
21 ];
22 }
23 }

Controlador final

1 <?php
2
3 namespace App\Http\Controllers;
4
5 use App\Http\Requests\PostRequest;
6
7 class PostController extends Controller
8 {
9
10 public function store(PostRequest $request)
11 {
12 return $request->all(); //guardado
Capítulo 3: Te Presento a Laravel 34

13 }
14
15 }

Esto es interesante porque la validación del proyecto del CRUD la hicimos en el controlador y
funcionó, precisamente de esa forma Laravel aumentó su popularidad, teniendo dentro de sí las
buenas prácticas pero no obliga a nadie a usar todas estas reglas.
Hacer la validación en los controladores es muy fácil, pero si estas mismas reglas las vas a usar en
varias partes no deberías hacerlo en el controlador sino en un archivo independiente de validación.
También es recomendable aislarlo cuando necesitamos validar muchos campos.
Como nota final tenemos lo siguiente:

CSRF: Es un tipo de ataques, donde formularios de extraños buscan alterar nuestros


datos. Laravel sabe que la plataforma es confiable porque hemos generado un token en el
formulario. Sin el toquen no podríamos hacer nada y así mantenemos nuestra seguridad.
Si quitamos la protección del toquen nos devolverá un estatus HTTP no oficial 419. Es
usado por Laravel precisamente cuando falta un token CSRF o ha caducado.
Capítulo 4: Sistema de Plantilla
Esto es un sistema avanzado de plantillas. Blade, el sencillo y poderoso sistema de plantillas
de Laravel. Las vistas deben tener la extensión .blade.php y estar almacenada en la carpeta
resources/views.

Existen cosas básicas como los comentarios: {{- Este es un comentario, no se imprimirá en
nuestras vistas -}} y también conceptos avanzados, veamos de que trata.

Herencia
Con este motor de plantillas podemos crear herencia y secciones, es una forma interesante de
reutilizar los archivos y crear plantillas visuales.
Ejemplo simple: Archivo app.blade.php

1 <!DOCTYPE html>
2 <html>
3 <head>
4 <meta charset="utf-8">
5 <title>@yield('title', 'Rimorsoft Online')</title>
6 </head>
7 <body>
8 <div class="container">
9 @yield('content')
10 </div>
11 </body>
12 </html>

Ejemplo simple: Archivo home.blade.php página hija


Capítulo 4: Sistema de Plantilla 36

1 @extends('app')
2
3 @section('title', 'Bienvenido a Rimorsoft Online')
4
5 @section('content')
6
7 <p>
8 Contenido de mi página Home
9 </p>
10
11 @endsection

Elimino la página welcome y configuro la ruta para que apunte al home.

1 Route::get('/', function () {
2 return view('home');
3 });

Podemos extender con la directiva @extends, allí indicamos quien es la vista padre. Trabajamos
con secciones con @section. Las secciones se mostrarán en la plantilla padre que usa a @yield, un
ejemplo común sería el siguiente.

1 @extends('layouts')
2
3 @section('title', 'Rimorsoft Online')
4
5 @section('content')
6 <p>
7 La estructura HTML de mi página web...
8 </p>
9 @endsection

Hay una directiva interesante llamada @parent que sirve para agregar y no sobrescribir el contenido
de nuestra plantilla, es útil cuando queremos agregar por ejemplo Javascript a nuestra vista hija pero
no quiero eliminar el Javascript de mi plantilla principal. Veamos un ejemplo:
Layout
Capítulo 4: Sistema de Plantilla 37

1 <!DOCTYPE html>
2 <html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
3 <head>
4 <meta charset="utf-8">
5 <meta name="viewport" content="width=device-width, initial-scale=1">
6
7 <title>@yield('title')</title>
8 </head>
9 <body>
10
11 @section('header')
12 El menú por defecto de mi plantilla
13 @show
14
15 @yield('content')
16
17 </body>
18 </html>

La vista hija (Home)

1 @extends('layout')
2
3 @section('title', 'Rimorsoft Online')
4
5 @section('header')
6 @parent
7
8 <p>
9 Mi contenido adicional para el Home
10 </p>
11 @endsection
12
13 @section('content')
14 <p>
15 La estructura HTML de mi página web...
16 </p>
17 @endsection

Por supuesto toma en cuenta que la ruta debe estar apuntando a la página hija.
Capítulo 4: Sistema de Plantilla 38

1 <?php
2
3 //...
4
5 Route::get('/', function () {
6 return view('home');
7 });

Puedes ver que algunas veces terminamos nuestras secciones con @endsection y a veces @show. La
diferencia es muy sencilla con @endsection finalizamos una sección mientras que @show crea un
yield y por ello podemos básicamente extenderla.

Magia de Yield
@yield acepta un segundo parámetro. Este puede ser una vista.

1 <!DOCTYPE html>
2 <html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
3 <head>
4 <meta charset="utf-8">
5 <meta name="viewport" content="width=device-width, initial-scale=1">
6
7 <title>@yield('title')</title>
8 </head>
9 <body>
10
11 @section('header')
12 El menú por defecto de mi plantilla
13 @show
14
15 @yield('content', View::make('default'))
16
17 </body>
18 </html>

Para la prueba creamos una vista llamada default.

1 <p>
2 Contenido por defecto
3 </p>

Y una vista llamada about para probar esta funcionalidad.


Capítulo 4: Sistema de Plantilla 39

1 @extends('layout')
2
3 @section('title', 'Sobre nosotros')

Como no especificamos el sidebar ni el contenido en content vemos como carga la vista con los
valores por defecto. Para que puedas probar todo este sistema en un proyecto te muestro las rutas
finales.

1 <?php
2
3 //...
4
5 Route::get('/', function () {
6 return view('home');
7 });
8
9 Route::get('about', function () {
10 return view('about');
11 });

Estructuras de Control
Como vimos en el ejercicio del CRUD, blade cuenta con directivas de control interesantes.

IF
1 @if ()
2 //...
3 @elseif ()
4 //...
5 @else
6 //...
7 @endif

Hay otras formas interesantes de llegar a un resultado, podemos con IF hacer cualquier consulta
pero veamos con Laravel que otras cosas podemos hacer.
Capítulo 4: Sistema de Plantilla 40

1 @unless ()
2 //...
3 @endunless
4
5 @isset ()
6 //...
7 @endisset
8
9 @empty()
10 //...
11 @endempty

Ahí podemos ver que rápidamente podemos verificar si un elemento está vacío, si no está declarado
o consultar una negación como cuando hacemos un IF con el signo !… Podemos también preguntar
rápidamente si el usuario actual está logueado o no.

1 @auth
2 //...
3 @endauth
4
5 @guest
6 //...
7 @endguest

For, Foreach y While


He usado estas directivas en muchos videos en mi canal, vamos a repasarlos rápidamente porque
siempre hay algo nuevo que aprender.

1 @for ()
2 //...
3 @endfor
4
5 @foreach ()
6 //...
7 @endforeach
8
9 @forelse ()
10 //...
11 @empty
12 <p>Sin datos</p>
Capítulo 4: Sistema de Plantilla 41

13 @endforelse
14
15 @while ()
16 //...
17 @endwhile

Algo interesante es que cuando estamos dentro de un ciclo podemos usar una variable llamada $loop
y esta nos ayuda a obtener información interna del bucle.

1 @foreach ()
2 @if ($loop->first)
3 //...
4 @endif
5
6 @if ($loop->last)
7 //...
8 @endif
9 @endforeach

Hay métodos para acceder al index, número del ciclo actual y mucho más. Veamos una lista muy
útil proporcionada por Laravel directamente.

1. $loop->index Ciclo actual y comienza en 0 como los arrays.


2. $loop->iteration Ciclo actual y comienza en 1.
3. $loop->count Total de elementos.
4. $loop->first Primera vuelta.
5. $loop->last Última vuelta.
6. $loop->even Pares.
7. $loop->odd Impares.

Switch
Es igual que en PHP, solo debemos agregar el arroba en cada directiva.
Capítulo 4: Sistema de Plantilla 42

1 @switch()
2 @case()
3 //...
4 @break
5
6 @default
7 //...
8 @endswitch

PHP puro y duro


Si necesitas insertar código PHP (aunque no lo recomiendo) podemos usar @php.

1 @php
2 // No lo hagas :)
3 @endphp

Inclusión y Sub Vistas Sencillas


App

1 <!DOCTYPE html>
2 <html>
3 <head>
4 <meta charset="utf-8">
5 <title>@yield('title', 'Rimorsoft Online')</title>
6 </head>
7 <body>
8 @include('header')
9 <div class="container">
10 @yield('content')
11 </div>
12 @include('footer')
13 </body>
14 </html>

Header (header.blade.php)
Capítulo 4: Sistema de Plantilla 43

1 <header>
2 Este es mi menú
3 </header>

Footer (footer.blade.php)

1 <footer>
2 Este es mi pie de página
3 </footer>

De esta forma podemos mantener nuestra página Home por ejemplo bastante vacía o con lo necesario
sin tener que hacer mucho scroll al momento de hacer alguna modificación. El menú, el pie de página
tienden a ser exageradamente largo, de hecho la información de SEO que colocamos en head también
podemos aislarla y así mantener archivos muy cortos fáciles de mantener.
Si incluimos una vista que no existe, Laravel nos lanzará un error diciendo que efectivamente no
existe esa vista. View [sidebar] not found y para evitarlo podemos usar @includeIf().

1 <!DOCTYPE html>
2 <html>
3 <head>
4 <meta charset="utf-8">
5 <title>@yield('title', 'Rimorsoft Online')</title>
6 </head>
7 <body>
8 @include('header')
9 <div class="container">
10 @includeIf('sidebar')
11
12 @yield('content')
13 </div>
14 @include('footer')
15 </body>
16 </html>

Este sería nuestro resultado final, estas son las técnicas usadas para evitar copiar y pegar en nuestras
vistas. Toma en cuenta algo, cuando hablamos de middleware buscamos 1). proteger áreas de nuestro
sistema y 2). no copiar y pegar la lógica de seguridad.
Es la misma filosofía de reutilizar y no copiar y pegar.
Capítulo 4: Sistema de Plantilla 44

Directivas Personalizadas
Podemos extender a blade agregando nuestras propias estructuras o directivas, esto es muy
interesante si detectamos que estamos llenando de mucha lógica nuestras vistas.
Quiero usar una directiva personalizada en mis vistas. Por ejemplo @to('https://twitter.com/italomoralesf')
para construir enlaces rápidamente.

1 <?php
2
3 namespace App\Providers;
4
5 use Illuminate\Support\Facades\Blade;
6 use Illuminate\Support\ServiceProvider;
7
8 class AppServiceProvider extends ServiceProvider
9 {
10 //...
11 public function register()
12 {
13 Blade::directive('to', function ($link) {
14
15 return "<a href=$link target='_black'>Clic aquí</a>";
16
17 });
18 }
19
20 //...
21 public function boot()
22 {
23 //
24 }
25 }

En AppServiceProvider importamos la clase Blade con la línea use Illuminate\Support\Facades\Blade;


La magia ocurre dentro del método register, allí se ve claramente que mi nueva directiva se llama
to y espera un enlace. Con esto conseguimos extender a blade y retornar un enlace en base a mi
nueva directiva llamada to(), es un pequeño ejemplo que ilustra bastante bien cómo funciona esta
tecnología.
Te puedes estar preguntando ¿por qué hacerlo así y no crear un helper?, esta pregunta es muy válida
pero si pensamos únicamente en nuestras vistas debemos crear una directiva, si vamos a usar alguna
utilidad así en otras partes del proyecto como modelos, controladores, rutas etc entonces debemos
crear un helper.
Capítulo 4: Sistema de Plantilla 45

1. Directivas solo para las vistas.


2. Helper para utilidades parecidas que usaremos en todo el sistema.

La puedes probar en la vista home que hemos venido trabajando en este capítulo.

1 @extends('layout')
2
3 @section('title', 'Rimorsoft Online')
4
5 @section('header')
6 @parent
7
8 <p>
9 Mi contenido adicional para el Home
10 </p>
11 @endsection
12
13 @section('content')
14 @component('alert')
15 <strong>Un error en el home</strong>
16 @endcomponent
17
18 <p>
19 La estructura HTML de mi página web...
20 </p>
21
22 <p>
23 @to('https://twitter.com/italomoralesf')
24 </p>
25 @endsection

Configuración de Formularios

Cross-site request forgery


Me has visto en varios videos crear un campo oculto con la directiva @csrf y es precisamente la
protección requerida para evitar que cualquier formulario se haga pasar por uno propio. Con el
CSRF en realidad creamos un token para decirle a Laravel “hola, soy yo, soy un amigo”.
Cada vez que vayamos a crear un formulario en nuestras vistas debemos colocar dentro a
la directiva @csrf, este token es obligatorio, existe un middleware que valida esta solicitud
app/Http/Middleware/VerifyCsrfToke.php.
Capítulo 4: Sistema de Plantilla 46

1 <?php
2
3 namespace App\Http\Middleware;
4
5 use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as BaseVerifier;
6
7 class VerifyCsrfToken extends BaseVerifier
8 {
9 //...
10
11 protected $except = [
12 // Aquí irían las rutas que quieres saltar
13 ];
14 }

No recomiendo, yo prefiero tener exceso control sobre todas mis rutas.


En cuando al formulario, debemos simplemente escribir nuestra directiva.

1 <form method="POST">
2 @csrf
3
4 <!-- Resto de campos -->
5 </form>

Yo escribo estas directivas justo al lado del botón, el orden no importa. Lo único importante es
incluirlo, que esté dentro del formulario.

Método al actualizar o eliminar


En HTML solo puedes usar POST y GET, nunca podrías usar directamente PUT, PATCH o DELETE.
Nota que nuestro formulario sigue teniendo en el atributo método el valor “POST” pero dentro
debes especificar si deseas actualizar o eliminar usanto la directiva @method.

1 <form method="POST">
2 @method('DELETE')
3
4 <!-- Resto de campos -->
5 </form>

Usé DELETE pero como puedes imaginar también existe la opción de usar PUT y PATCH, además debes
saber que debes mantener a la directiva @csrf. Un ejemplo completo sería el siguiente:
Capítulo 4: Sistema de Plantilla 47

1 <form method="POST">
2 @csrf
3 @method('DELETE')
4
5 <!-- Resto de campos -->
6 </form>

Mensajes de errores
Hay varias opciones, veamos un par de ellas.

1. Debes saber que para que esto se active debes crear la lógica de validación en tu controlador
directamente o usando un Request que haga esto en una clase aparte. Lo importante es hacerlo
para tener errores que mostrar.

Usando el método validate:

1 public function store(Request $request)


2 {
3 //Validación
4 $request->validate([
5 'title' => 'required',
6 'body' => 'required'
7 ]);
8
9 //lógica de guardado
10 }

Usando la Validator:

1 <?php
2
3 namespace App\Http\Controllers;
4
5 use Illuminate\Support\Facades\Validator;
6
7 class Post extends Controller
8 {
9 public function store(Request $request)
10 {
11 //Validación
Capítulo 4: Sistema de Plantilla 48

12 $validator = Validator::make($request->all(), [
13 'title' => 'required',
14 'body' => 'required'
15 ]);
16 if ($validator->fails()) {
17 //retornar con los errores
18 }
19
20 //lógica de guardado
21 }
22 }

O usando una clase Requests personalizada para su validación:

1 <?php
2
3 namespace App\Http\Requests;
4
5 use Illuminate\Foundation\Http\FormRequest;
6
7 class PostRequest extends FormRequest
8 {
9 public function authorize()
10 {
11 return true;
12 }
13
14 //
15 public function rules()
16 {
17 return [
18 'title' => 'required',
19 'body' => 'required'
20 ];
21 }
22 }

No importa el método que elijas, lo importante es que tengas la lógica de validación creada. Ahora
aprendamos cómo crear la impresión de errores en la vista.

1. Mostrar errores
Capítulo 4: Sistema de Plantilla 49

Podemos hacer uso de la variable llamada $errors. Esta variable es pasada automáticamente a la
vista, a partir de aquí podemos utilizar diferentes métodos.
Para comprobar si existe o no algún error podemos usar el método any():

1 @if ($errors->any())
2 <!-- si hay errores mostramos este contenido -->
3 @endif

Podemos revisar todos los mensajes de errores usando el método all() recorriéndolo con un foreach.
Es el que típicamente uso en mis videos.

1 <ul>
2 @foreach ($errors->all() as $error)
3 <li>{{ $error }}</li>
4 @endforeach
5 </ul>

Básicamente podemos combinar any() con all(), con el primero preguntamos si hay errores y con
el otro los mostramos en pantalla.
Hay mas métodos:

• get(): El argumento de este método es el nombre del campo, por ejemplo $errors->get('phone').
• first(): Si tienes muchos mensajes de error podemos obtener el primero usando este método,
por ejemplo $errors->first('phone').
• has(): Podemos preguntar si tenemos un mensaje de validación usanto este método, por
ejemplo $errors->has('phone').

Y puedes combinarlos de acuerdo a tu necesidad. Si tienes un mensaje de validación entonces


imprime el primero o todos.
Veamos un ejemplo:

1 @if (count($errors))
2 <div class="alert alert-danger">
3 <button type="button" class="close" data-dismiss="alert">
4 <span>&times;</span>
5 </button>
6
7 <h4>¡Errores encontrados!</h4>
8 <ul>
9 @foreach($errors->all() as $error)
10 <li>{{ $error }}</li>
Capítulo 4: Sistema de Plantilla 50

11 @endforeach
12 </ul>
13 </div>
14 @endif

Aquí te muestro cómo trabajo con ella, si tenemos errores entonces los imprimimos, uso bootstrap
y mostramos de mejor manera cada uno de los errores.
También tenemos a la mano la directiva @error que básicamente verifica si existe un mensaje de
validación, veamos un ejemplo.

1 <label>Título</label>
2 <input type="text">
3
4 @error('title')
5 <span>{{ $message }}</span>
6 @enderror

Un ejemplo con otras opciones.

1 <!-- manera larga -->


2 @if ($errors->has('title'))
3 <span>{{ $errors->first('title') }}</span>
4 @endif
5
6 <!-- manera corta -->
7 @error('title')
8 <span>{{ $message }}</span>
9 @enderror

Componentes

Historia
Los componentes han causado mucha confusión, es una necesidad real pero al mismo tiempo era
algo casi resuelto. Antes para crear componentes usábamos una directiva interesante de blade.
Vamos a crear un archivo llamado alert.blade.php.
Capítulo 4: Sistema de Plantilla 51

1 <div>
2 <!-- Clases boostrap -->
3 {{ $slot }}
4 </div>

La clave estaba en la variable $slot, esta se usaba para inyectar el contenido.

1 @extends('layout')
2
3 @section('title', 'Rimorsoft Online')
4
5 @section('header')
6 @parent
7
8 <p>
9 Mi contenido adicional para el Home
10 </p>
11 @endsection
12
13 @section('content')
14 @component('alert')
15 <strong>Un error en el home</strong>
16 @endcomponent
17
18 <p>
19 La estructura HTML de mi página web...
20 </p>
21 @endsection

Allí hacemos uso de @component('alert') donde alert es el nombre del archivo, se usa la misma
metodología que aprovechamos para incluir vistas con otras directivas.

Laravel 7
Podemos ver la misma metodología pero de una manera exageradamente fácil y clara. Entendamos
que los componentes proporcionan un beneficio parecido a la creación de una sección pero el enfoque
debe de ser componente realmente.
Una sección es un espacio para incluir cualquier cosa, un componente es un elemento HTML que
puede o no existir en la vista y sí se le necesita entonces se invoca, como por ejemplo mensajes
de alertas, errores o informativos, también pudiéramos tener como componente a un elemento de
promoción en el top de la web y elementos así.
Podemos crear un componente basado en una clase, para ello usamos php artisan make:component.
Haré un ejemplo con un componente llamado SALUDAR Greet.php.
Capítulo 4: Sistema de Plantilla 52

1 $ php artisan make:component Greet

Con ello conseguimos crear nuestro primer componente ubicado en app/View/Components/Greet.php.

1 <?php
2
3 namespace App\View\Components;
4
5 use Illuminate\View\Component;
6
7 class Greet extends Component
8 {
9 /**
10 * Create a new component instance.
11 *
12 * @return void
13 */
14 public function __construct()
15 {
16 //
17 }
18
19 /**
20 * Get the view / contents that represent the component.
21 *
22 * @return \Illuminate\View\View|string
23 */
24 public function render()
25 {
26 return view('components.greet');
27 }
28 }

Esto también nos crea la carpeta y vista inicial dentro de resources/views.

1 <div>
2 <!-- Well begun is half done. - Aristotle -->
3 </div>

Siempre nos crea esta estructura en nuestra vista con una pequeña frase. Nosotros en este archivo
debemos construir a nuestro componente.
El siguiente paso es personalizar nuestro componente.
Capítulo 4: Sistema de Plantilla 53

1 <div>
2 <h1>¡Mi primer componente!</h1>
3 <p>Texto o contenido de mi componente</p>
4 <!-- cualquier contenido -->
5 </div>

Y para usar el componente hacemos uno de una etiqueta muy particular. Lo genial de esta tecnología
es que podemos de inmediato usarlo como si estuvieramos invocando cualquier elemento HTML.
En cualquier vista, en mi caso welcome.blade.php.

1 <!DOCTYPE html>
2 <html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
3 <head>
4 <meta charset="utf-8">
5 <meta name="viewport" content="width=device-width, initial-scale=1">
6
7 <title>Laravel</title>
8 </head>
9 <body>
10 <x-greet />
11 </body>
12 </html>

Esto hará que nuestro componente renderice correctamente en nuestra vista.


Para ilustrarlo de una manera mas clara podemos hacer uso de alguna variable. Para ello preparamos
nuestra clase en app/View/Components/Greet.php.

1 <?php
2
3 namespace App\View\Components;
4
5 use Illuminate\View\Component;
6
7 class Greet extends Component
8 {
9 public $text;
10
11 //
12 public function __construct($text)
13 {
14 $this->text = $text;
15 }
Capítulo 4: Sistema de Plantilla 54

16
17 //
18 public function render()
19 {
20 return view('components.greet');
21 }
22 }

En el componente haríamos la siguiente configuración.

1 <div>
2 <h1>¡Mi primer componente!</h1>
3 <p>{{ $text }}</p>
4 <!-- cualquier contenido -->
5 </div>

Por definir una propiedad en nuestra clase podemos usarla en nuestro componente. Ahora veamos
cómo guardar información en ella.

1 <!DOCTYPE html>
2 <html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
3 <head>
4 <meta charset="utf-8">
5 <meta name="viewport" content="width=device-width, initial-scale=1">
6
7 <title>Laravel</title>
8 </head>
9 <body>
10 <x-greet text="Mensaje para mi componente" />
11 </body>
12 </html>

Nuestro componente es solo una etiqueta HTML, el atributo es una variable y por supuesto esta es
la definida en nuestra clase.
Nota que para mostrar al componente usamos x- seguido del nombre del componente: El nombre
del componente debe seguir reemplazar los espacios por un guión, esto se conoce como Kebab Case:

1. Mi componente sería mi-componente.


2. MiComponente de igual forma sería mi-componente.

Básicamente es el mis estilo usado en las direcciones web miejemplo.com/mi-post. Es una forma
limpia y legible de combinar las palabras.
Capítulo 4: Sistema de Plantilla 55

Ingeniería
El motor de plantillas blade no nos impide utilizar código PHP directamente. De hecho, esto funciona
de la siguiente manera, Blade compila todo en PHP plano y las almacena en caché hasta que hagamos
alguna modificación, esto es interesante porque significa que Blade no genera una sobrecarga o una
carga adicional a nuestro sistema.
Básicamente nosotros escribimos un bonito Blade, este se convierte en PHP puro y en el navegador
finalmente veremos una página hecha en PHP.
El resultado de nuestras vistas estará en storage/framework/views
Esto es interesante, hemos comprobado que blade es un sistema plantillas sencillo pero muy poderoso
y lo mas importante es que lo podemos aplicar.
Piensa en tus vistas, identifica que es una plantilla y créala, qué es un componente como header por
ejemplo y así con cada cosa. Al final conseguimos mucho orden y poco código qué leer a la hora de
hacer mantenimiento o extensión de nuestros proyectos.
Respecto a blade hay mucho que aprender, lo importante es tener aquí una noción básica. Debes
estar atento al canal, todo sobre blade lo compartiré en video.
Capítulo 5: Componente de Login y
Registro
Laravel/UI
Vamos a instalar un proyecto para tocar en detalle el paquete de login y registro de usuario. En
nuestra carpeta de vistas no contamos con los archivos de acceso ni de registro de usuario.
Este paquete Laravel/UI instala en nuestro proyecto:

1. Las Rutas.
2. El Controller Home “de ejemplo”.
3. Las vistas: Home, layouts/app y login, registros y otras vistas para recuperar la contraseña y
verificar email.

Puedes instalar este componente con estilos preestablecidos de VUE, React y Bootstrap.
¿Por qué esto es aparte? Porque podemos querer instalar desde cero nuestro propio sistema de login,
es interesante que no te obliguen a usar paquetes de este estilo. Si tu fuerte es React no sería muy
cómodo ver que por defecto el sistema Laravel incluye plantillas de VUE.
Instalación:

1 $ composer require laravel/ui --dev

Laravel desde su versión 6 no te obliga a tener un set inicial para el frontend; por ejemplo si vamos
a trabajar con un API simplemente no lo instalamos.
Al finalizar la instalación tendrás disponibles dos comandos en la terminal.

• ui: Puedes instalar desde aquí bootstrap solo, vue y bootstrap, react y bootstrap.
• ui:auth: No instala ningún framework javascript ni estilos, netamente instalaría las vistas con
las clases de bootstrap.
Capítulo 5: Componente de Login y Registro 57

El comando ui y ui:auth

Comando ui:auth
Este comando te permite instalar las rutas y las vistas necesarias para trabajar con el login, registro,
recuperación de contraseñas y verificación de E-mail. Se resume en vistas y rutas básicas de inicio
de sesión y registro básico. Las vistas por defecto tendrán las clases de bootstrap.
Importante: No se instalarán estilos, ni ningún framework de Javascript.

1 $ php artisan ui:auth

Comando ui
Este comando nos ayuda a agregar todos los assets necesario para tener bootstrap, vuejs o react. Su
uso es muy simple, solo tienes que ejecutar el comando y decirle qué es lo que quieres instalar.

1 $ php artisan ui bootstrap //quiero solo bootstrap, no vue, no react


2 $ php artisan ui vue //instala vue y boostrap
3 $ php artisan ui react //instala react y bootstrap

Después de ejecutar el comando necesitas instalar las dependencias y compilar los archivos
necesarios usando npm.

1 $ npm install

1 $ npm run dev

Todo en uno
Laravel es increíblemente, también puedes instalar todo de una vez si así lo requieres.

1 $ php artisan ui bootstrap --auth


2 $ php artisan ui vue --auth
3 $ php artisan ui react --auth

Los pasos necesarios para tener todo funcionando son los siguientes:

1. Instalar laravel/ui.
Capítulo 5: Componente de Login y Registro 58

2. Ejecutar por ejemplo el comando php artisan ui vue --auth.


3. Ejecutar npm install y npm run dev.

En el paso #2 conseguimos tener instalado el sistema básico de login y registro, y además el sistema
básico de vue instalado para crear nuestros componentes. Esto es interesante, podemos empezar
desde cero un sistema de login y registro de usuarios pero hemos visto que en pocos minutos podemos
instalar una base de este sistema y a partir de allí avanzar.
Recuerda lo que hablamos antes, el enfoque comercial es muy importante y está presente. Un cliente
paga para ver su negocio funcionando no porque cuenta con un login de usuarios.
Parte 3: Base de datos
Capítulo 6: Fundamentos
Curso en Video
Aquí en este capítulo hago un breve resumen, sin embargo te recomiendo ver en detalle los 26 video
que tengo preparados en mi canal. Es una guía avanzada sobre las relaciones de base de datos usando
Laravel, aprovéchala.

1. Curso de Eloquent ORM: https://youtube.com/watch?v=efocZNA5T_A


2. Barra de depuración en Laravel: https://youtube.com/watch?v=707D4_D4CMU
3. Base de datos relacional: https://youtube.com/watch?v=3YcwIGq1jEY
4. Relación uno a uno: https://youtube.com/watch?v=1qKiWkyH9n4
5. Relación uno a muchos: https://youtube.com/watch?v=TLhz-bbyyLc
6. Relación muchos a muchos: https://youtube.com/watch?v=25e24tSawwQ
7. Edición de vista Welcome: https://youtube.com/watch?v=DVP80Ku1D74
8. Relación uno a uno a través de…: https://youtube.com/watch?v=C7bLS79DOvw
9. Todas las tablas: Category, Tag, Taggables, Post: https://youtube.com/watch?v=cjq8qGHuy5E
10. Todas las relaciones: https://youtube.com/watch?v=-uwOrNz1-TI
11. Relaciones y configuración de entidades: https://youtube.com/watch?v=uT-2pB43vXM
12. Repaso: Relaciones en Eloquent ORM y entidades: https://youtube.com/watch?v=El87zcFA5uQ
13. Convención *able en relaciones polimorficas: https://youtube.com/watch?v=zcOwRYkyjvc
14. Qué es Polimorfismo: https://youtube.com/watch?v=XKYdVmui-uc
15. Relación Polimorfica uno a uno: https://youtube.com/watch?v=-nVbHHSwblk
16. Relación Polimorfica uno a muchos: https://youtube.com/watch?v=PD6RmE7ADQ0
17. Relación Polimorfica muchos a muchos: https://youtube.com/watch?v=wKOFUzqSh74
18. Factory en Laravel: https://youtube.com/watch?v=UILn48af2PY
19. Seeders (Profile, Location, Image & Groups): https://youtube.com/watch?v=GNNqhyHrBUE
20. Seeder (Category, Tags & Comments): https://youtube.com/watch?v=-PdnFalK6Ik
21. Datos polimorficos: https://youtube.com/watch?v=0iByExuMfVs
22. Vista de Perfil de Usuario: https://youtube.com/watch?v=wgwEDgS99Ck
23. Vista de Perfil de Usuario con diseño en Bootstrap 4: https://youtube.com/watch?v=1LWAPzzEazA
24. Vista de Perfil Completa (Videos y Posts del Usuario): https://youtube.com/watch?v=QFM5AKSNlIg
25. Level (uno a muchos a través de…) Has Many Through: https://youtube.com/watch?v=YKATVb7FukE
26. Resumen final del Curso Eloquent ORM: https://youtube.com/watch?v=IaVmfb-f6TE
Capítulo 6: Fundamentos 61

Introducción a Eloquent
Eloquent, para ello creamos un nuevo proyecto laravel new eloquent.
Eloquent está incluido en Laravel y proporciona una genial y simple forma de trabajar con una base
de datos. La filosofía es, cada tabla tiene un correspondiente “Modelo”, es un archivo que usamos
para interactuar con una tabla.
Estos archivos llamados modelos nos permiten hacer consultas, insertar registros, eliminar y
actualizar.

Paso 1
config/database.php, es allí donde tenemos la configuración de acceso y conexión a nuestra base
de datos. Pero dónde realmente guardamos los datos es en el archivo .env. Nunca configuramos
“aunque lo podemos hacer” el archivo config/database.php.

Paso 2
Los modelos residen en la carpeta app, y para crearlos usamos php artisan make:model Nombre.
Para generar una migración al mismo tiempo que generamos al modelo podemos usar php artisan
make:model Nombre -m o php artisan make:model Nombre --migration.

Para crear un factory necesitamos usar el parámetro --factory.

1 $ php artisan make:model Post --migration --factory


2 Model created successfully.
3 Factory created successfully.
4 Created Migration: 2020_01_29_183225_create_posts_table

Paso 3
Hablemos de las convenciones. Deben ser en inglés y en singular. Con esto conseguimos que el
modelo sea singular y la tabla en plural. La tabla para el ejemplo quedaría de la siguiente forma.
Capítulo 6: Fundamentos 62

1 <?php
2
3 use Illuminate\Database\Migrations\Migration;
4 use Illuminate\Database\Schema\Blueprint;
5 use Illuminate\Support\Facades\Schema;
6
7 class CreatePostsTable extends Migration
8 {
9 //...
10 public function up()
11 {
12 Schema::create('posts', function (Blueprint $table) {
13 $table->bigIncrements('id');
14
15 $table->string('title');
16 //...
17
18 $table->timestamps();
19 });
20 }
21
22 //...
23 }

Paso 4
Hagamos la práctica usando los datos de los post.

1. Configuramos la base de datos en .env.


2. Ejecutamos php artisan migrate.
3. Creamos 30 posts para practicar usando tinker.

1 $ php artisan tinker


2 Psy Shell v0.9.12 (PHP 7.3.9 — cli) by Justin Hileman
3 >>> factory(App\Post::class, 30)->create()
4 //
5 >>> exit
6 Exit: Goodbye

Paso 5
Ya tenemos datos, tablas y entendimos un poco sobre las convenciones. Ahora vamos a usar Eloquent
directamente en el archivo de rutas.
Capítulo 6: Fundamentos 63

1 use App\Post;
2
3 Route::get('eloquent', function () {
4 $posts = Post::all();
5
6 foreach ($posts as $post) {
7 echo "$post->id $post->title <br>";
8 }
9 });

Vemos en el navegador y están los 30 datos,


Eloquent sabe que se trata de la tabla posts porque mantenemos la convención, este es nuestro
modelo y es el representante de mi tabla. Post == posts.

1 use App\Post;
2
3 Route::get('eloquent', function () {
4 $posts = Post::where('id', '>=', '20')->get();
5
6 foreach ($posts as $post) {
7 echo "$post->id $post->title <br>";
8 }
9 });

1 use App\Post;
2
3 Route::get('eloquent', function () {
4 $posts = Post::where('id', '>=', '20')
5 ->orderBy('id', 'desc')
6 ->get();
7
8 foreach ($posts as $post) {
9 echo "$post->id $post->title <br>";
10 }
11 });
Capítulo 6: Fundamentos 64

1 use App\Post;
2
3 Route::get('eloquent', function () {
4 $posts = Post::where('id', '>=', '20')
5 ->take(3)
6 ->orderBy('id', 'desc')
7 ->get();
8
9 foreach ($posts as $post) {
10 echo "$post->id $post->title <br>";
11 }
12 });

Para finalizar quiero hacer énfasis en lo siguiente, nosotros necesitamos entender que una tabla
estará representada por un archivo en mi sistema. Ese archivo está dentro de app y la convención
es, modelo singular y la tabla en plural.
Y otra cosa importante es que al usarlo necesitamos definir ruta, crear controlador, hacer consulta,
imprimir esos datos en una vista. Pero por cuestiones de ejemplo trabajamos directamente en la capa
de las rutas.

ActiveRecord
ActiveRecord es un patrón de arquitectura usado en las bases de datos relacionales, la idea principal
es acceder a una tabla a través de una clase. Mediante esta clase debemos poder insertar, actualizar,
consultar y eliminar datos. Eloquent simplemente es ActiveRecord para trabajar con tu base de datos
desde Laravel.

Relaciones de Base de datos


Con frecuencia las tablas de las bases de datos están relacionadas. Por ejemplo, el post de un
blog pertenece a un usuario, un post pudiera tener una categoría, un post podría tener muchos
comentarios, etc. Te invito a ver en detalle los enlaces que te compartí para profundizar en esa área.
En nuestro ejemplo ya configuramos una entidad llamada Post, deberíamos relacionarlas a los
usuarios para saber por quién fue escrito dicho post.

Relación uno a muchos


Creamos el nuevo campo en la migración de posts
Capítulo 6: Fundamentos 65

1 <?php
2
3 use Illuminate\Database\Migrations\Migration;
4 use Illuminate\Database\Schema\Blueprint;
5 use Illuminate\Support\Facades\Schema;
6
7 class CreatePostsTable extends Migration
8 {
9 //...
10 public function up()
11 {
12 Schema::create('posts', function (Blueprint $table) {
13 $table->bigIncrements('id');
14
15 $table->unsignedBigInteger('user_id');
16
17 $table->string('title');
18
19 $table->timestamps();
20
21 $table->foreign('user_id')->references('id')->on('users');
22 });
23 }
24
25 //...
26 }

1 $ php artisan migrate // no funcionará porque no hay nuevas migraciones...

1 $ php artisan migrate:fresh // este comando elimina todas las tablas y ejecuta de nu\
2 evo a migrate, lo malo es que ahora nuestra tabla posts estará vacía

Configuremos un archivo para crear datos falsos, datos semillas sería el nombre correcto.
Capítulo 6: Fundamentos 66

1 <?php
2
3 use Illuminate\Database\Seeder;
4 use App\User;
5 use App\Post;
6
7 class DatabaseSeeder extends Seeder
8 {
9 /**
10 * Seed the application's database.
11 *
12 * @return void
13 */
14 public function run()
15 {
16 factory(App\User::class, 4)->create();
17 factory(App\Post::class, 40)->create();
18 }
19 }

Modificamos el factory

1 <?php
2
3 /** @var \Illuminate\Database\Eloquent\Factory $factory */
4
5 use App\Post;
6 use Faker\Generator as Faker;
7
8 $factory->define(Post::class, function (Faker $faker) {
9 return [
10 'user_id' => rand(1, 4),
11 'title' => $faker->sentence
12 ];
13 });

Y en el terminal debemos ejecutar

1 $ php artisan migrate:refresh --seed //este comando reversa todas las migraciones, l\
2 as instala de nuevo y por último siembra los datos en la tabla.
Capítulo 6: Fundamentos 67

Repaso

1. Factory: Forma parte del setup, la usamos como molde para crear datos.
2. Seed: Es la configuración de la semilla o del dato falso en sí, aquí dentro podemos usar el
factory o insertar directamente datos usando otra lógica.
3. Migrations: Es la estructura inicial de la tabla, es nuestra tabla hecha código para compartirla
con nuestros compañeros programadores.

Avisar a Laravel que esa relación existe


La relación existe en la base de datos, los campos están y se conectan pero Laravel no sabe y esto es
algo que debemos configurar.
Post

1 <?php
2
3 namespace App;
4
5 use Illuminate\Database\Eloquent\Model;
6
7 class Post extends Model
8 {
9 public function user()
10 {
11 return $this->belongsTo(User::class);
12 }
13 }

User

1 <?php
2
3 namespace App;
4
5 use Illuminate\Contracts\Auth\MustVerifyEmail;
6 use Illuminate\Foundation\Auth\User as Authenticatable;
7 use Illuminate\Notifications\Notifiable;
8
9 class User extends Authenticatable
10 {
11 use Notifiable;
12
Capítulo 6: Fundamentos 68

13 //...
14
15 public function posts()
16 {
17 return $this->hasMany(Post::class);
18 }
19 }

El archivo de rutas para ver el resultado.

1 <?php
2
3 //...
4
5
6 use App\Post;
7
8 //...
9
10 Route::get('posts', function () {
11 $posts = Post::all();
12
13 foreach ($posts as $post) {
14 echo "
15 $post->id
16 <strong>{$post->user->name}</strong>
17 $post->title
18 <br>
19 ";
20 }
21 });
22
23 use App\User;
24
25 Route::get('users', function () {
26 $users = User::all();
27
28 foreach ($users as $user) {
29 echo "
30 $user->id
31 <strong>$user->name</strong>:
32 {$user->posts->count()} posts
33 <br>
Capítulo 6: Fundamentos 69

34 ";
35 }
36 });

Lo importante es entender que lo que tenemos en la carpeta database es lo que nos ayudará en la
etapa inicial (los factories, seeds y las migraciones). Esta carpeta podemos verla como la encargada de
configurar la base de datos para empezar a desarrollar. Luego de que las tablas existen nos dedicamos
a trabajar con los modelos, allí están las clases para administrar nuestros datos en el transcurso de
toda la aplicación.

Collections y Serialización
Una colección es un conjunto de cosas del mismo tipo. Si traemos usuarios entonces podemos decir
que estamos trabajando con una colección de usuarios. Un dato o un usuario no es una colección,
diez usuarios es una colección de usuarios.
Esto es importante porque cuando usamos Eloquent heredamos muchos métodos para trabajar
fluidamente con arreglos o con un conjunto de datos. El objetivo es poder iterar de manera sencilla
como si fueran arreglos simples de PHP.

Iterar significa repetir.

Vamos a confirmar que iniciamos a collections cuando usamos a Eloquent.

1 Route::get('collections', function () {
2 $users = User::all();
3
4 dd($users);
5 // En el navegador podemos ver claramente que iniciamos a la clase collections
6 });

Resto de ejercicios
Capítulo 6: Fundamentos 70

1 Route::get('collections', function () {
2 $users = User::all();
3
4 dd($users); // miramos que se carga la clase collections
5 dd($users->contains(4)); // true o false de si contiene o no el dato
6 dd($users->diff(User::whereIn('id', [1, 2])->get())); // ver diferencias
7 dd($users->except([1, 2, 3])); // muestra todos los usuarios excepto el que diga\
8 mos.
9 dd($users->only(2)); // lo contrario de excepto, puede ser array o no si es uno \
10 solo
11 dd($users->find(1)); // busqueda dentro de la colección un elemento
12 dd($users->load('posts')); // carga por adelantado las relaciones
13 });

Resto de ejercicios en serialización

1 Route::get('serialization', function () {
2 $users = User::all();
3
4 dd($users); // por defecto el resultado
5 dd($users->toArray()); // nuestros datos en un array
6
7 $user = $users->find(1);
8 dd($user); // para ver que imprime
9 dd($user->attributesToArray()); // retorna el resultado del registro en array
10 dd($user->toJson()); // retorna el resultado del registro en JSON
11 });

Serializar es convertir un dato en algo que se pueda transferir por la red. Hablando de la web,
necesitamos saber convertir a nuestras colecciones en arrays o json. Llevar a nuestra información a
estos formatos es serializar. Esto lo usa PHP y otros lenguajes de programación.
Es fundamental saber manipular la información, buscar, listar y entender en qué formato vienen
para poder hacer uso de ella correctamente. Ese es el objetivo de estos textos.

Formato de valores en Tablas


Veamos cómo dar formato a los valores de los atributos de Eloquent, hablo básicamente a formatos
de texto cuando guardamos un dato o cuando imprimimos un dato. Podemos desde CSS ver texto
en mayúscula, minúscula, etc. Pero en este punto pudiera querer guardar todo en minúscula para
mantener un estándar, pero al mostrar en pantalla podemos mostrar todo en mayúscula.
Capítulo 6: Fundamentos 71

• Accessors: Son los métodos que dan formato al valor que se recupera.
• Mutators: Son los métodos que dan formato al valor cuando son guardados.

Ambos sirven para provocar alteración al dato, ya sea a la hora de obtener o a la hora de guardar.

Accessors
Lo conseguimos creando métodos que comiencen en get y terminen en attribute. Veamos un
ejemplo:

1 <?php
2
3 namespace App;
4
5 use Illuminate\Contracts\Auth\MustVerifyEmail;
6 use Illuminate\Foundation\Auth\User as Authenticatable;
7 use Illuminate\Notifications\Notifiable;
8
9 class User extends Authenticatable
10 {
11 use Notifiable;
12
13 //...
14
15 public function getGetNameAttribute()
16 {
17 return strtoupper($this->name);
18 }
19
20 }

La ruta la podemos probar de la siguiente manera.


Capítulo 6: Fundamentos 72

1 use App\User;
2
3 Route::get('users', function () {
4 $users = User::all();
5
6 foreach ($users as $user) {
7 echo "
8 $user->id
9 <strong>$user->get_name</strong>:
10 {$user->posts->count()} posts
11 <br>
12 ";
13 }
14 });

En posts podemos hacer la siguiente configuración.

1 <?php
2
3 namespace App;
4
5 use Illuminate\Database\Eloquent\Model;
6
7 class Post extends Model
8 {
9 //...
10
11 public function getGetTitleAttribute()
12 {
13 return ucfirst($this->title);
14 }
15
16 }

Seguimos agregando el prefijo get porque se entiende muy bien cuando necesitamos obtener.
Capítulo 6: Fundamentos 73

1 use App\Post;
2
3 Route::get('posts', function () {
4 $posts = Post::all();
5
6 foreach ($posts as $post) {
7 echo "
8 $post->id
9 <strong>{$post->user->get_name}</strong>
10 $post->get_title
11 <br>
12 ";
13 }
14 });

Mantenemos el get y notamos que esta configuración en la entidad altera como funciona nuestro
sitio en todo el sistema.

Mutators
Usamos igual un inicio y un fin, empezamos en set y terminamos con attribute, en este caso no
usamos ningún prefijo porque es algo que no vamos a manipular directamente, dentro colocamos
el nombre del campo. Esto se ejecutará automáticamente cuando la entidad detecte que estamos
guardando un dato.

1 <?php
2
3 namespace App;
4
5 use Illuminate\Contracts\Auth\MustVerifyEmail;
6 use Illuminate\Foundation\Auth\User as Authenticatable;
7 use Illuminate\Notifications\Notifiable;
8
9 class User extends Authenticatable
10 {
11 use Notifiable;
12
13 //...
14
15 public function setNameAttribute($value)
16 {
17 $this->attributes['name'] = strtolower($value);
Capítulo 6: Fundamentos 74

18 }
19
20 }

En el modelo Post lo hacemos de la siguiente manera:

1 <?php
2
3 namespace App;
4
5 use Illuminate\Database\Eloquent\Model;
6
7 class Post extends Model
8 {
9 //...
10
11 public function setTitleAttribute($value)
12 {
13 $this->attributes['title'] = strtolower($value);
14 }
15 }

Y para probar necesitamos refrescar los datos, observamos ahora que tendremos allí todos los
registros en minúscula.

1 $ php artisan migrate:refresh --seed

Esto se debe usar con criterio y responsabilidad, por ejemplo el contenido de un articulo no
deberíamos manipularlo pero otros datos si… En un banco, sistema administrativo, registro de
usuarios es muy común que se maneje todo a nivel visual en mayúscula pero lo guardamos realmente
en minúscula.

Convenciones en Eloquent
Esto es muy importante, he tenido la experiencia de enseñar un curso donde por ejemplo creo el
modelo o entidad Category y la tabla categories, me escriben muchos alumnos diciendo que no les
funciona nada de lo que enseño y cuando observo su código me doy cuenta de que crean la tabla
con el nombre categorias_autos y al modelo Category.
Este tipo de cosas pueden hacerse pero también hay que configurar cosas adicionales para decirle a
Laravel que nuestra configuración es diferente.
Capítulo 6: Fundamentos 75

1 <?php
2
3 namespace App;
4
5 use Illuminate\Database\Eloquent\Model;
6
7 class Post extends Model
8 {
9 //...
10 }

Este es el modelo estándar y podemos personalizar varias cosas respecto a él.

Nombre de Tabla
Si el modelo es Post la tabla debe ser en minúscula y en plural, es decir, debe llamarse posts. La
convención dice que debe ser con el formato “snake_case”, si nos queremos salir de la convención
debemos usar la propiedad $table para personalizarlo.

1 <?php
2
3 namespace App;
4
5 use Illuminate\Database\Eloquent\Model;
6
7 class Post extends Model
8 {
9 protected $table = 'articles'; // Con esto altero el estándar
10 //protected $table = 'my_articles'; // Otro ejemplo
11 }

Campo ID
La clave primaria debe llamarse id. Pero si lo prefieres puedes cambiarlo.
Capítulo 6: Fundamentos 76

1 <?php
2
3 namespace App;
4
5 use Illuminate\Database\Eloquent\Model;
6
7 class Post extends Model
8 {
9 protected $primaryKey = 'post_id';
10 }

Esta debe ser autoincremental lo que quiere decir que por defecto será del tipo int y se va a
incrementar automáticamente.

1 <?php
2
3 namespace App;
4
5 use Illuminate\Database\Eloquent\Model;
6
7 class Post extends Model
8 {
9 public $incrementing = false; // Así desactivamos que se incremente automáticame\
10 nte
11 }

Y aunque no lo creas puedes cambiar el tipo de dato, no recomiendo para nada este tipo de cambios
pero si lo llegas a necesitar sabrás cómo hacerlo.

1 <?php
2
3 namespace App;
4
5 use Illuminate\Database\Eloquent\Model;
6
7 class Post extends Model
8 {
9 protected $keyType = 'string';
10 }
Capítulo 6: Fundamentos 77

Campos Timestamps
Si te llegaste a preguntar cómo desactivar los campos por defecto de fechas, pues es muy fácil. Hablo
de los campos created_at y updated_at.

1 <?php
2
3 namespace App;
4
5 use Illuminate\Database\Eloquent\Model;
6
7 class Post extends Model
8 {
9 public $timestamps = false;
10 }

También podemos cambiar sus nombre si lo deseamos.

1 <?php
2
3 namespace App;
4
5 use Illuminate\Database\Eloquent\Model;
6
7 class Post extends Model
8 {
9 const CREATED_AT = 'created';
10 const UPDATED_AT = 'updated';
11 }

Valores Predeterminados
Quizás me has visto usar la propiedad $attributes en alguno de mis videos, esta propiedad también
te sirve para establecer valores por defecto.
Capítulo 6: Fundamentos 78

1 <?php
2
3 namespace App;
4
5 use Illuminate\Database\Eloquent\Model;
6
7 class Post extends Model
8 {
9 protected $attributes = [
10 'subscribed' => false,
11 ];
12 }

Y como mensaje final te puedo comentar que desde las migraciones también es posible muchas de
estas configuraciones. Yo te recomiendo trabajar con el estándar y convención propuesta por Laravel
para evitar mayores enredos.

Carpeta de Base de Datos

Carpeta Factories
Hemos usado muchas veces este tipo de archivo para hacer test o para hacer nuestra configuración
inicial de algún proyecto. Siempre los creo al mismo tiempo que creo los modelos.

1 $ php artisan make:model Post --factory

Pero podemos crearlos directamente con el siguiente comando.

1 $ php artisan make:factory PostFactory

Su ubicación es database/factories.
Podemos crear un factory y conectarlo rápidamente a un modelo usando la opción --model, en
Laravel hay mucha maneras de llegar a un resultado.

1 $ php artisan make:factory PostFactory --model=Post

Y conseguimos eso precisamente, un factory con la configuración inicial conectado al modelo


deseado.
Capítulo 6: Fundamentos 79

1 use App\Post;
2 use Faker\Generator as Faker;
3
4 $factory->define(Post::class, function (Faker $faker) {
5 return [
6 //
7 ];
8 });

La función de este archivo es crear un molde de estructura predeterminada para llenar de datos
falsos nuestras tablas.

1 <?php
2
3 /** @var \Illuminate\Database\Eloquent\Factory $factory */
4
5 use App\Post;
6 use Faker\Generator as Faker;
7
8 $factory->define(Post::class, function (Faker $faker) {
9 return [
10 'title' => $faker->sentence,
11 'body' => $faker->text
12 ];
13 });

En el Closure realmente usamos a Faker (https://github.com/fzaninotto/Faker) quien se encarga de


generar datos falsos o aleatorios para probar nuestro sistema.
Todos los factories Laravel los cargará automáticamente, y podemos acceder a ellos usando el helper
o función factory() que me has visto usar en mis archivos semillas o seeds.
En nuestra pruebas o archivos semillas podemos crear datos de la siguiente manera.

1. Con make creamos la estructura sin guardarlos en la base de datos.


2. Con create creamos el dato de prueba directamente en la base de datos.

1 factory(App\Post::class)->make();

O creamos varios.
Capítulo 6: Fundamentos 80

1 factory(App\Post::class, 15)->make();

Nota que usamos make esto es bastante útil al hacer pruebas, digamos que necesitamos crear solo la
estructura para enviar y guardar, etc.
Podemos usar make y sobrescribir algunos datos.

1 $post = factory(App\Post::class)->make([
2 'title' => 'Post de PHP',
3 ]);

Así sabemos que estamos guardando, esto podría ser útil precisamente para testear usando PHPUnit
partes de nuestro sistema.
Y para guardar en nuestra base de datos usamos create.

1 factory(App\Post::class)->create();

O guardar varios.

1 factory(App\Post::class, 15)->create();

Y por supuesto, también podemos sobrescribir los datos. Esto lo hago siempre que quiero probar
mediante testing la actualización de algún CRUD, se te hará familiar si adquiriste el curso de TDD
en Laravel

1 $post = factory(App\Post::class)->create([
2 'title' => 'Post de PHP',
3 ]);

Carpeta Migrations
Las migraciones son archivos que representan en PHP la estructura de nuestras tablas, esto ayuda a
que los programadores hagan sus modificaciones allí y la compartan con el resto sin mayor problema.
Usamos las migraciones al momento de iniciar un proyecto y en el transcurso cuando queremos hacer
alguna modificación a cualquier tabla.

1 $ php artisan make:migration create_posts_table

Esto crea la migración correspondiente.


Con este comando creamos a una migración que representará en este caso a la tablas llamada posts.
El archivo se guardará en database/migrations. Las migraciones deben crearse con un orden lógico
porque todas tendrán en el nombre una marca que hace referencia al tiempo y eso determinará el
orden.
Capítulo 6: Fundamentos 81

1 <?php
2
3 use Illuminate\Database\Migrations\Migration;
4 use Illuminate\Database\Schema\Blueprint;
5 use Illuminate\Support\Facades\Schema;
6
7 class CreatePostsTable extends Migration
8 {
9 //...
10 public function up()
11 {
12 Schema::create('posts', function (Blueprint $table) {
13 $table->bigIncrements('id');
14 $table->timestamps();
15 });
16 }
17
18 //...
19 public function down()
20 {
21 Schema::dropIfExists('posts');
22 }
23 }

Cuando solo queremos agregar una columna a alguna tabla creamos la migración con un nombre
bastante explicito y usamos el siguiente comando.

1 $ php artisan make:migration add_views_to_posts_table --table=posts

Allí decimos en el nombre que sirve para agregar el campo views a la tabla llamada posts. Este sería
el resultado.

1 <?php
2
3 use Illuminate\Database\Migrations\Migration;
4 use Illuminate\Database\Schema\Blueprint;
5 use Illuminate\Support\Facades\Schema;
6
7 class AddViewsToPostsTable extends Migration
8 {
9 //...
10 public function up()
Capítulo 6: Fundamentos 82

11 {
12 Schema::table('posts', function (Blueprint $table) {
13 //
14 });
15 }
16
17 //...
18 public function down()
19 {
20 Schema::table('posts', function (Blueprint $table) {
21 //
22 });
23 }
24 }

La diferencia está en Schema::create y cuando usamos el parámetro --table tenemos como


resultado Schema::table, ahí está la clave, uno sirve para crear una tabla y el otro sirve para alterar
una tabla que ya existe.
En una migración conseguimos dos métodos: up y down.

1. up levanta una nueva acción como la creación o alteración de una tabla.


2. Y down se usa para revertir lo construido en el método up.

1 <?php
2
3 use Illuminate\Database\Migrations\Migration;
4 use Illuminate\Database\Schema\Blueprint;
5 use Illuminate\Support\Facades\Schema;
6
7 class CreatePostsTable extends Migration
8 {
9 //...
10 public function up()
11 {
12 Schema::create('posts', function (Blueprint $table) {
13 $table->bigIncrements('id');
14
15 $table->string('title');
16 $table->string('body');
17
18 $table->timestamps();
Capítulo 6: Fundamentos 83

19 });
20 }
21
22 //...
23 public function down()
24 {
25 Schema::dropIfExists('posts');
26 }
27 }

Para llevar nuestros archivos de migraciones a la base de datos usamos el terminal y el comando
migrate:

1 $ php artisan migrate

Podemos revertir esta operación usando migrate:rollback. Este comando reversa la última migra-
ción pero podemos incluir varias usando el parámetro --step.

1 $ php artisan migrate:rollback // La última migración

Para revertir varias migraciones recientes podemos usar el siguiente comando.

1 $ php artisan migrate:rollback --step=3

Un comando que uso a menudo es migrate:refresh, este revierte todas las migraciones (hace
rollback) y ejecuta inmediatamente el comando migrate.

1 $ php artisan migrate:refresh

Y podemos mezclarla con los seeds.

1 $ php artisan migrate:refresh --seed

Existe también el comando migrate:fresh, omite el rollback y simplemente elimina todas las tablas
y después ejecuta el comando migrate:

1 $ php artisan migrate:fresh

Y lo podemos combinar con --seed.


Capítulo 6: Fundamentos 84

1 $ php artisan migrate:fresh --seed

Y el resto de elementos posibles las enseñaré en videos, no te pierdas ningún video en el canal. Esta
es la base necesaria para que entiendas cualquier tema sobre las migraciones.

Carpeta Seeds
Los Seeder se guardan en la carpeta database/seeds. Es una manera sencilla de llenar nuestras
tablas de datos falsos. Existe por defecto la clase DatabaseSeeder pero puedes crear las clases que
desees.
Los podemos crear usando make:seeder, por ejemplo:

1 $ php artisan make:seeder PostsTableSeeder

Allí veremos el método run, método que se ejecutará cuando desde el terminal hacemos referencia
a que queremos ejecutar los seeders.
Podemos ver un archivo que he usado en videos para el canal.

1 <?php
2
3 use Illuminate\Database\Seeder;
4
5 class DatabaseSeeder extends Seeder
6 {
7 //...
8 public function run()
9 {
10 // $this->call(UsersTableSeeder::class);
11
12 App\User::create([
13 'name' => 'Italo Morales F',
14 'email' => '[email protected]',
15 'password' => bcrypt('123456')
16 ]);
17
18 factory(App\Post::class, 24)->create();
19 }
20 }

Hablo específicamente del archivo DatabaseSeeder, pero puedes trabajar de la misma manera con
PostsTableSeeder.
Puedes notar como usamos Eloquent directamente y un factory. Y recuerda, esto es algo que nos
ayudará al principio de un proyecto.
Capítulo 7: Query Builder
Lo conocemos también como constructor de consultas, al usarlo no hay necesidad de limpiar las
cadenas que están siendo recibidas ya que este sistema cuenta con todas las protecciones necesarias.
He hecho diferentes pruebas y he podido ver Query Builder es más veloz que Eloquent, lo malo
es que no podemos trabajar con eventos ni otros beneficios que Eloquent incluye. El consumo de
Eloquent es mayor y esto es lógico porque nos permite manejar eventos y otras maravillas.
Eloquent es la implementación de Laravel del patrón ActiveRecord como vimos en el capítulo de
base de datos y viene por supuesto con todas sus fortalezas y debilidades. Es una buena solución
para operaciones sencillas y para aprovechar los eventos de los modelos, alertas, softdelete y muchas
otras bondades. Pero debemos pagar el precio del rendimiento. Para casos pesados es mejor usar DB
directamente, al momento de trabajar eres tú quien decide qué usar.
Por ejemplo yo uso Eloquent en mis formularios y cosas básicas pero para exportar datos en Excel
o PDF, consultas extensas mediante fechas, etc uso DB (Query Builder).

Su Uso
Logramos usarlo mediante el método table de la clase facade DB. Para usarlo debes incluir en tu
controlador a la clase DB usando la siguiente línea: use Illuminate\Support\Facades\DB; o \DB en
la consulta.

1 $posts = DB::table('posts')->get();

Podemos combinar y hacer cosas parecidas a Eloquent.

1 $post = DB::table('posts')->where('id', 1)->first();

Podemos extraer valores y no el registro completo.

1 $post = DB::table('posts')->where('id', 1)->value('title');

Y al igual que con Eloquent disponemos del método find:

1 $post = DB::table('posts')->find(1);

Para trabajar con una colección de datos de alguna columna hacemos lo siguiente:
Capítulo 7: Query Builder 86

1 $posts = DB::table('posts')->pluck('title');

Si vamos a trabajar con miles de registros, podemos usar el método chunk.

1 DB::table('posts')->chunk(50, function ($posts) {


2 foreach ($posts as $post) {
3 //
4 }
5 });

Depuración
Es interesante saber qué aunque podemos instalar la barra de depuración de Laravel o usar los
mismos paquetes de depuración construidos por Taylor Otwell disponemos de los métodos dd o
dump.

Con dd vemos la información de depuración y con dump veremos de igual forma la información de
depuración pero lograremos hacer que la solicitud continue.

1 DB::table('posts')->dd();

1 DB::table('posts')->dump();

Cómo Agrupar
Esto es increíble, veamos esta gran variedad de métodos.

1 $posts = DB::table('posts')->count();

1 $posts = DB::table('posts')->max('view');

1 $posts = DB::table('posts')->avg('view');

Y puedes revisar los diferentes métodos para agrupar como min y sum.
A veces por no saber usamos count sin embargo permíteme mostrarte dos métodos interesantes.
Capítulo 7: Query Builder 87

1 return DB::table('posts')->where('id', 1)->exists();

1 return DB::table('posts')->where('id', 1)->doesntExist();

Selects
Siempre ha sido un problema obtener todo un registro cuando solo necesitamos algunas columnas.

1 $posts = DB::table('posts')->select('title', 'body')->get();

Uniones
Esto quiere decir que podemos unir fácilmente dos consultas.

1 $before = DB::table('posts');
2
3 $posts = DB::table('posts')->union($before)->get();

Where
Hay diferentes formas de aplicarla, veamos a continuación algunos ejemplos.

1 $posts = DB::table('posts')->where('view', 100)->get();

1 $posts = DB::table('posts')->where('view', '=', 100)->get();

Y puedes usar diferentes métodos de comparación:

1. >=.
2. <>.
3. like.

Otra forma interesante es trabajar con un arreglo.


Capítulo 7: Query Builder 88

1 $posts = DB::table('posts')->where([
2 ['active', 1],
3 ['view', '>', '1000'],
4 ])->get();

Y contamos con un conjunto de alternativas bastante interesantes.

1. orWhere.
2. whereBetween, orWhereBetween.
3. whereNotBetween, orWhereNotBetween.
4. whereIn, whereNotIn, orWhereIn, orWhereNotIn.
5. whereNull, whereNotNull, orWhereNull, orWhereNotNull.
6. whereDate, whereMonth, whereDay, whereYear, whereTime.
7. whereColumn, orWhereColumn

Otros Métodos
1. orderBy: Para ordenar los resultados con asc o desc:
2. latest: Para ordenar fácilmente los resultados por fecha.
3. inRandomOrder: Se usa para ordenar los resultados de manera aleatoria.
4. groupBy: Se usa para agrupar los resultados de una consulta.
5. increment: Incremente uno increment('view').
6. decrement: Disminuye o resta uno decrement('view').

En el caso 5 y 6 podemos pasar un segundo parámetro que indicará cuantos deseamos sumar, por
ejemplo “increment(‘view’, 3)‘ y sumará de tres en tres.

Crear Registros
Para ello usamos el método insert y un arreglo con las columnas y valores.

1 DB::table('posts')->insert([
2 'title' => 'Título del Post'
3 ]);

Podemos pasar un arreglo con varios arreglos y cada uno representará una fila.
Capítulo 7: Query Builder 89

1 DB::table('posts')->insert([
2 ['title' => 'Título del Post 1'],
3 ['title' => 'Título del Post 2']
4 ]);

Actualizar un Registro
Para ello combinamos el método update y el método where.

1 DB::table('posts')
2 ->where('id', 1)
3 ->update(['titlr' => 'Nuevo Título']);

Existe el método updateOrInsert para verificar si deseamos actualizar o insertar si no existe el valor.

Eliminar un Registro
Al igual que en Eloquent contamos con el método delete():

1 DB::table('posts')->delete();

1 DB::table('posts')->where('id', 1)->delete();

Para truncar una tabla usamos el método truncate:

1 DB::table('posts')->truncate();
Parte 4: API con TDD
Capítulo 8: Introducción al Testing
Testing en Laravel
Laravel nos permite crear proyectos realmente profesionales y por ello está construido pensando en
las pruebas. Podemos ver que lo instala directamente y además tenemos el archivo de configuración
phpunit.xml correctamente creado.

Puedes trabajar con todo lo que te permite PHPUnit y además con los métodos de ayuda que
incluye Laravel. Todo lo desarrollaremos en la carpeta tests, dentro existen dos carpetas más: Unit
y Feature.

1. Las pruebas unitarias (Unit): Se enfocan en una muy pequeña porción aislada de tu código.
2. Las pruebas funcionales (Feature): Prueban una función completa del sistema o una porción
grande de tu código como por ejemplo las solicitudes HTTP.

Creando Pruebas
1 // Crea un test en la carpeta Feature...
2 $ php artisan make:test UserTest
3
4 // Crea un test en la carpeta Unir...
5 $ php artisan make:test UserTest --unit

Ejemplo
1 $ vendor/bin/phpunit

Revisar lo que sale en consola, vamos entendiendo cómo funciona este sistema. Es interesante
entender el flujo actual y el flujo usando el sistema de pruebas.

Sin Tests

1. Creo la ruta
2. Preparo controlador y métodos: Creo diseño (boostrap, html, etc).
3. Reviso la validación y voy probando desde el navegador.
4. Entro con frecuencia a la base de datos, voy probando …Y así, es un proceso de ensayo, error y
muchos clics.
Capítulo 8: Introducción al Testing 92

Con Tests

1. Desarrollo la prueba (crear archivo): Estructuro que necesito y mi resultado final.


2. Pienso en varias pruebas (una para validación, otra sobre login, base de datos, etc).
3. Después de tener mi método de prueba la ejecuto y obtengo mi error esperado.
4. Ahora desarrollo guiándome desde mi prueba.

Reflexión Final
Este es un extracto del libro gratuito: Te invito a descargarlo. TDD - Lo que debes saber:
https://rimorsoft.com/curso-de-tdd-en-laravel
Te cuento rápidamente una experiencia con números reales. En una entrevista laboral me hicieron
ver los diferentes niveles de salarios.

• Programador Junior: 600 USD.


• Programador que sabe TDD: 1400 USD.
• Programador que sabe TDD e Inglés: 2200 USD.

Yo por no saber TDD ni Inglés terminé ganando 600 mensual, obviamente lo agradezco porque fue mi
escuela básicamente, pero yo cumplo con alertarte… Sí sabemos usar Laravel somos usuarios Laravel
pero sí sabemos programación somos programadores y usamos cómo herramienta a Laravel.

Los conocimientos nos llevan lejos si los aplicamos.

Metodología TDD

El ciclo de TDD
Son tres niveles que la verdad me gustan mucho, el ciclo es Rojo, Verde, Refactor que se repiten
constantemente. ¿Vas a programar una mínima funcionalidad? Ok comienza en Rojo luego Verde y
por último pasa a Refactor.

Rojo

Este color por sí mismo indica que algo no está bien, todo lo peligroso tiene el color rojo. En
programación no es diferente todo lo que vayas a programar empieza fallando, empieza en rojo.
Si tienes un login sencillo y luego quieres hacer un login social, es normal que a la primera esto no
vaya bien. Toma en cuenta que va a fallar, debes esperar que esto suceda para poder solucionarlo.
Capítulo 8: Introducción al Testing 93

Verde

Ya sabemos que nuestro código ha fallado, ahora debemos hacer todo lo necesario para que funcione,
tenemos que llevarlo a verde. Aquí hacemos copia y pega, código estructurado y lo que sea para que
sirva y funciona. En otras palabras, el código necesario para que la prueba pase.

1. Rojo: No pasó la prueba.


2. Verde: La prueba pasó.

Sabemos entonces que el código actual no es necesariamente óptimo, puede incluso ser difícil de leer
y mantener, así que viene la fase de Refactor.

Refactor

Es aquí donde nos volvemos artistas, es mejorar la estructura del código, es agregar comentarios, es
borrar lo innecesario y crear código reutilizable… Todo lo necesario para facilitar el mantenimiento
futuro.

1. ¿Qué código se repite?.


2. ¿Es legible?.

Este es el paso mas poderoso porque es ordenar y al mismo tiempo que la prueba siga pasando sin
alterar la prueba (siga en verde).
Capítulo 9: API y nada mas
Los verbos HTTP son: GET, POST, PUT, PATCH y DELETE, y esto junto a los estados HTTP es
lo que quisiera explicarte antes de continuar con la construcción de un API. Un API es un código
preparado en el servidor para dar respuestas precisas en JSON, usar Laravel es ahorrar tiempo de
desarrollo y nos ayuda a no reinventar la rueda.
Para describir mejor a un API vamos a imaginar el sistema de https://rimorsoft.com. El frontend del
proyecto es el área visual, y el backend está preparado para dar datos. Un API brinda datos, hace
posible que un programador frontend solicite una tarea o recurso específico.
Los verbos HTTP juegan un papel muy importante. Este le dice al servidor la forma en que queremos
manejar los datos que con mucha frecuencia se observan desde una perspectiva CRUD.

Verbos HTTP

GET
Usamos GET para leer datos. La dirección (endpoint) va a determinar si estamos obteniendo un dato
o una colección de datos.

POST
Una solicitud con el verbo HTTP POST es para crear un recurso. Usamos POST para alterar una base
de datos, en este caso para guardar un nuevo registro del cliente al servidor.

PUT / PATCH
PUT y PATCH son para actualizar datos en una base de datos:

1. PUT se utilizan cuando queremos reemplazar por completo el registro.


2. Usamos PATCH para una modificación parcial, es decir algunos campos y no todo el registro.

El uso de PUT o PATCH depende exclusivamente de ti.

DELETE
Este verbo es bastante explícito, lo usamos para eliminar un recurso.
Capítulo 9: API y nada mas 95

Estados HTTP
Estos estados se usan para informar al cliente sobre la solicitud, esto puede ser solicitudes de éxito,
error y muchos otros.
Los estados son cinco grupos, veamos cada uno:

2XX Éxito
En el grupo 2XX encontramos a las solicitudes exitosas.

1. 200 OK.
2. 201 Recurso creado.
3. 204 Sin contenido.

3XX Redirección
En el grupo 3XX informamos al cliente sobre las diferentes redirecciones.

1. 301 Movido Permanentemente.


2. 307 Redirección Temporal.
3. 308 Redirección Permanente.

4XX Errores del Cliente


En el grupo 4XX tenemos los estados que tratan con el cliente directamente.

1. 400 Petición Incorrecta.


2. 401 No Autorizado.
3. 403 Acceso Prohibido.
4. 404 No Encontrado.
5. 405 Método no Permitido.
6. 422 No Procesable.

5XX Errores del Servidor


En este grupo 5XX tenemos todos los estados relacionados con el servidor.

1. 501 No Implementado.
2. 502 Puerta de enlace no válida.
3. 503 Servicio no Disponible.
4. 504 Tiempo de espera de puerta de enlace

Hemos comenzado bien, un API trata de enlaces (endpoint) y estados HTTP.


Capítulo 9: API y nada mas 96

Proyecto
Instalación de Laravel laravel new api.
Creación de mi archivo de pruebas php artisan make:test Http/Controllers/Api/PostTest.
Reviso el test con código por defecto:

1 $ vendor/bin/phpunit
2 PHPUnit 8.5.1 by Sebastian Bergmann and contributors.
3
4 ... 3 / 3 (100%)
5
6 Time: 138 ms, Memory: 16.00 MB

Borro los dos archivos de prueba por defecto en Feature y en Unit y al ejecutar el comando tengo:

1 $ vendor/bin/phpunit
2 PHPUnit 8.5.1 by Sebastian Bergmann and contributors.
3
4 . 1 / 1 (100%)
5
6 Time: 104 ms, Memory: 16.00 MB

Store

Etapa de Guardar
Para trabajar con el resto de métodos necesitamos configurar base de datos y el resto de elementos
para nuestras pruebas, en el libro de TDD en Laravel usamos MySql y SQLite… Vamos directamente
a trabajar con SQLite.
Creamos dicho archivo en database/database.sqlite
Puedes hacer clic derecho en la carpeta y das crear archivo o hacerlo desde el terminal $ nano
database/database.sqlite

Si revisamos el contenido de esta carpeta podemos ver que lo tenemos creado.

1 $ ls database
2 database.sqlite factories migrations seeds
Capítulo 9: API y nada mas 97

En el libro de TDD en Laravel te comente que debemos agregar la línea <server name="DB_-
CONNECTION" value="sqlite"/> en nuestro archivo PHPUnit.xml, pero ya esto está configurado en
Laravel 6, puedes ir y confirmarlo.
Luego podemos ir a nuestro archivo config/database.php y decir cuál es nuestro archivo.

1 <?php
2
3 use Illuminate\Support\Str;
4
5 return [
6
7 //...
8
9 'connections' => [
10
11 'sqlite' => [
12 'driver' => 'sqlite',
13 'url' => env('DATABASE_URL'),
14 'database' => database_path('database.sqlite'),
15 'prefix' => '',
16 'foreign_key_constraints' => env('DB_FOREIGN_KEYS', true),
17 ],
18
19 ],
20
21 //...
22 ];

De env('DB_DATABASE', database_path('database.sqlite')) solo dejamos env('DATABASE_URL').


Podemos escribir la prueba y esta nos dirá que falta la conexión a la base de datos y así poco a poco
nos irá guiando, pero lo hacemos de una vez porque considero que forma parte de la configuración
inicial. Vamos con la prueba. Dejaré el método anterior para que lo tengas de referencia, en próximas
impresiones del código solo verás el método con el que estaremos trabajando.
Capítulo 9: API y nada mas 98

1 <?php
2
3 namespace Tests\Feature\Http\Controllers\Api;
4
5 use Illuminate\Foundation\Testing\RefreshDatabase;
6 use Illuminate\Foundation\Testing\WithFaker;
7 use Tests\TestCase;
8
9 use App\User;
10
11 class PostTest extends TestCase
12 {
13 use RefreshDatabase;
14
15 /**
16 * Los usuarios no autenticados no pueden acceder al api de post.
17 */
18 public function test_a_user_can_create_a_post()
19 {
20 $user = factory(User::class)->create();
21 dd($user);
22 }
23 }

Nota cómo creamos a un usuario, esto es importante porque necesitamos uno para iniciar sesión y
probar su acceso. Lo imprimo en pantalla usando dd() para que de esta manera veas qué sucede en
el terminal.
Hay varias cosas aqui.

1. Configuramos la base de datos en SQLite.


2. Usamos use Illuminate\Foundation\Testing\RefreshDatabase; con use RefreshDatabase;
esto nos permite ejecutar las migraciones, es decir, esto crea las tablas, las vacía, las usa y así
cada vez que ejecuto las pruebas. Todo esto en SQLite, jamas en Mysql ni en producción.
3. Usamos use App\User; porque la necesitamos para crear el usuario de prueba.

Cuando ejecutamos el comando vemos entre otras cosas los datos del usuario falso o de prueba que
se ha creado, esto es importante, cada vez que ejecutemos las pruebas tendremos un nuevo usuario
ya que es un dato solo para realizar tests.
Capítulo 9: API y nada mas 99

1 $ vendor/bin/phpunit
2 PHPUnit 8.5.1 by Sebastian Bergmann and contributors.
3
4 .App\User^ {
5 #attributes: array:8 [
6 "name" => "Lafayette Towne"
7 "email" => "[email protected]"
8 "email_verified_at" => "2020-01-07 19:35:23"
9 "password" => "$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi"
10 "remember_token" => "z83NgmvsBT"
11 "updated_at" => "2020-01-07 19:35:23"
12 "created_at" => "2020-01-07 19:35:23"
13 "id" => 1
14 ]
15 }

La prueba completa sería

1 <?php
2
3 namespace Tests\Feature\Http\Controllers\Api;
4
5 use Illuminate\Foundation\Testing\RefreshDatabase;
6 use Illuminate\Foundation\Testing\WithFaker;
7 use Tests\TestCase;
8
9 use App\User;
10
11 class PostTest extends TestCase
12 {
13 use RefreshDatabase;
14
15 /**
16 * Los usuarios no autenticados no pueden acceder al api de post.
17 */
18 public function test_a_user_can_create_a_post()
19 {
20 //$this->withoutExceptionHandling();
21
22 $user = factory(User::class)->create();
23
24 $response = $this->actingAs($user, 'api')->json('POST', '/api/posts', [
25 'title' => 'Post de prueba'
Capítulo 9: API y nada mas 100

26 ]);
27
28 $response->assertJsonStructure(['id', 'title', 'created'])
29 ->assertJson(['title' => 'Post de prueba'])
30 ->assertStatus(201);
31
32 $this->assertDatabaseHas('posts', [
33 'title' => 'Post de prueba'
34 ]);
35 }
36 }

1. Allí inicio sesión como en un API $this->actingAs($user, 'api') y creo un post.


2. Luego quiero revisar si retorno la estructura 'id', 'title', 'created'.
3. Y confirmo que reviso una llave title con el valor guardado.
4. Reviso que retorno el estatus 201 de HTTP que quiere decir que hemos guardado un dato.
5. Y finalmente quiero revisar si esto lo tengo guardado en la base de datos con la afirmación
assertDatabaseHas.

Aqui vemos que necesitamos nuestro método store configurado y algo para formatear la forma en
que retornamos los datos (esto lo haremos en otra clase no en el controlador).
Creo el recurso para el formateo de datos php artisan make:resource Post.
Creo el modelo, la migración y el factory php artisan make:model Post -mf (no era necesario crear
el factory en este momento pero lo usaremos).

Ruta
En el archivo api.php configuro mis cinco rutas posibles.

1 Route::apiResource('posts', 'Api\PostController')->middleware('auth:api');

Modelo POST
Capítulo 9: API y nada mas 101

1 <?php
2
3 namespace App;
4
5 use Illuminate\Database\Eloquent\Model;
6
7 class Post extends Model
8 {
9 protected $fillable = ['title'];
10 }

Migracion
1 <?php
2
3 use Illuminate\Database\Migrations\Migration;
4 use Illuminate\Database\Schema\Blueprint;
5 use Illuminate\Support\Facades\Schema;
6
7 class CreatePostsTable extends Migration
8 {
9 /**
10 * Run the migrations.
11 *
12 * @return void
13 */
14 public function up()
15 {
16 Schema::create('posts', function (Blueprint $table) {
17 $table->bigIncrements('id');
18
19 $table->string('title');
20
21 $table->timestamps();
22 });
23 }
24
25 /**
26 * Reverse the migrations.
27 *
28 * @return void
29 */
Capítulo 9: API y nada mas 102

30 public function down()


31 {
32 Schema::dropIfExists('posts');
33 }
34 }

Recurso POST
1 <?php
2
3 namespace App\Http\Resources;
4
5 use Illuminate\Http\Resources\Json\JsonResource;
6
7 class Post extends JsonResource
8 {
9 /**
10 * Transform the resource into an array.
11 *
12 * @param \Illuminate\Http\Request $request
13 * @return array
14 */
15 public function toArray($request)
16 {
17 return [
18 'id' => $this->id,
19 'title' => $this->title,
20 'created' => (string) $this->created_at
21 ];
22 }
23 }

Controlador PostController
Creamos el controlador $ php artisan make:controller Api/PostController --api --model=Post.
Capítulo 9: API y nada mas 103

1 <?php
2
3 namespace App\Http\Controllers\Api;
4
5 use App\Http\Controllers\Controller;
6 use Illuminate\Http\Request;
7
8 use App\Post;
9 use App\Http\Resources\Post as PostResource;
10
11 class PostController extends Controller
12 {
13 protected $post;
14
15 public function __construct(Post $post)
16 {
17 $this->post = $post;
18 }
19
20 //...
21
22 /**
23 * Store a newly created resource in storage.
24 *
25 * @param \Illuminate\Http\Request $request
26 * @return \Illuminate\Http\Response
27 */
28 public function store(Request $request)
29 {
30 $post = $this->post->create($request->all());
31
32 return response()->json(new PostResource($post), 201);
33 }
34
35 //...
36 }

Realizamos la prueba
Capítulo 9: API y nada mas 104

1 $ vendor/bin/phpunit --filter test_a_user_can_create_a_post


2 PHPUnit 8.5.1 by Sebastian Bergmann and contributors.
3
4 . 1 / 1 (100%)
5
6 Time: 265 ms, Memory: 22.00 MB
7
8 OK (1 test, 6 assertions)

Y si revisamos todas las pruebas, esto funciona.

1 $ vendor/bin/phpunit
2 PHPUnit 8.5.1 by Sebastian Bergmann and contributors.
3
4 .. 2 / 2 (100%)
5
6 Time: 273 ms, Memory: 22.00 MB
7
8 OK (2 tests, 11 assertions)

ahi vemos la ejecucion de dos metodos y once afirmaciones.

Validar al guardar un post


Veamos cómo podemos crear una validación usando TDD.

1 <?php
2
3 namespace Tests\Feature\Http\Controllers\Api;
4
5 use Illuminate\Foundation\Testing\RefreshDatabase;
6 use Illuminate\Foundation\Testing\WithFaker;
7 use Tests\TestCase;
8
9 use App\User;
10
11 class PostTest extends TestCase
12 {
13 use RefreshDatabase;
14
15 //...
Capítulo 9: API y nada mas 105

16
17 /**
18 * Validación si crea un post con el título vacío.
19 */
20 public function test_validation_if_you_create_a_post_with_the_empty_title()
21 {
22 //$this->withoutExceptionHandling();
23
24 $user = factory(User::class)->create();
25
26 $response = $this->actingAs($user, 'api')->json('POST', '/api/posts', [
27 'title' => ''
28 ]);
29
30 $response->assertStatus(422)
31 //->assertJsonValidationErrors('title')
32 ->assertExactJson([
33 'message' => 'The given data was invalid.',
34 'errors' => [
35 'title' => ['The title field is required.']
36 ]
37 ]);
38 }
39 }

Creo el archivo de validacion php artisan make:request Post


Archivo de validación

1 <?php
2
3 namespace App\Http\Requests;
4
5 use Illuminate\Foundation\Http\FormRequest;
6
7 class Post extends FormRequest
8 {
9 /**
10 * Determine if the user is authorized to make this request.
11 *
12 * @return bool
13 */
14 public function authorize()
Capítulo 9: API y nada mas 106

15 {
16 return true;
17 }
18
19 /**
20 * Get the validation rules that apply to the request.
21 *
22 * @return array
23 */
24 public function rules()
25 {
26 return [
27 'title' => 'required',
28 ];
29 }
30 }

Actualizacion en el controlador

1 <?php
2
3 namespace App\Http\Controllers\Api;
4
5 use App\Http\Controllers\Controller;
6 use Illuminate\Http\Request;
7
8 use App\Post;
9 use App\Http\Requests\Post as PostRequest;
10 use App\Http\Resources\Post as PostResource;
11
12 class PostController extends Controller
13 {
14 protected $post;
15
16 public function __construct(Post $post)
17 {
18 $this->post = $post;
19 }
20
21 //...
22
23 /**
24 * Store a newly created resource in storage.
Capítulo 9: API y nada mas 107

25 *
26 * @param \Illuminate\Http\Request $request
27 * @return \Illuminate\Http\Response
28 */
29 public function store(PostRequest $request)
30 {
31 $post = $this->post->create($request->all());
32
33 return response()->json(new PostResource($post), 201);
34 }
35
36 //...
37 }

Aquí básicamente incluyo esta clase de validación y con este nuevo método confirmo que valido
correctamente al guardar un post.

1 $ vendor/bin/phpunit --filter test_validation_if_you_create_a_post_with_the_empty_ti\


2 tle
3 PHPUnit 8.5.1 by Sebastian Bergmann and contributors.
4
5 . 1 / 1 (100%)
6
7 Time: 287 ms, Memory: 22.00 MB
8
9 OK (1 test, 2 assertions)

Y si reviso todas las pruebas

1 $ vendor/bin/phpunit
2 PHPUnit 8.5.1 by Sebastian Bergmann and contributors.
3
4 ... 3 / 3 (100%)
5
6 Time: 389 ms, Memory: 24.00 MB
7
8 OK (3 tests, 13 assertions)

Show

Obteniendo un Post
Capítulo 9: API y nada mas 108

1 <?php
2
3 namespace Tests\Feature\Http\Controllers\Api;
4
5 use Illuminate\Foundation\Testing\RefreshDatabase;
6 use Illuminate\Foundation\Testing\WithFaker;
7 use Tests\TestCase;
8
9 use App\User;
10 use App\Post;
11
12 class PostTest extends TestCase
13 {
14 use RefreshDatabase;
15
16 //...
17
18 /**
19 * Puedo acceder y ver un post.
20 */
21 public function test_can_get_a_post()
22 {
23 //$this->withoutExceptionHandling();
24
25 $user = factory(User::class)->create();
26 $post = factory(Post::class)->create();
27
28 $response = $this->actingAs($user, 'api')->json('GET', "/api/posts/$post->id\
29 ");
30
31 $response->assertJsonStructure(['id', 'title', 'created'])
32 ->assertJson(['title' => $post->title])
33 ->assertStatus(200);
34 }
35 }

Aquí vemos que hacemos uso de un factory que aún no está configurado, si ejecuto las pruebas
obtendré un error que me indica exactamente cómo eso me afecta.
Capítulo 9: API y nada mas 109

1 $ vendor/bin/phpunit --filter test_can_get_a_post


2 PHPUnit 8.5.1 by Sebastian Bergmann and contributors.
3
4 E 1 / 1 (100%)
5
6 Time: 311 ms, Memory: 22.00 MB
7
8 There was 1 error:
9
10 1) Tests\Feature\Http\Controllers\Api\PostTest::can_get_a_post
11 Illuminate\Database\QueryException: SQLSTATE[23000]: Integrity constraint violation:\
12 19 NOT NULL constraint failed: posts.title (SQL: insert into "posts" ("updated_at",\
13 "created_at") values (2020-01-08 14:38:18, 2020-01-08 14:38:18))
14
15 //...
16
17 Caused by
18 PDOException: SQLSTATE[23000]: Integrity constraint violation: 19 NOT NULL constrain\
19 t failed: posts.title

El error muestra que no se puede crear un post si título, nuestro factory está así. El resultado final
seria:

1 <?php
2
3 /** @var \Illuminate\Database\Eloquent\Factory $factory */
4
5 use App\Post;
6 use Faker\Generator as Faker;
7
8 $factory->define(Post::class, function (Faker $faker) {
9 return [
10 'title' => $faker->sentence
11 ];
12 });

Ahora mi prueba de show está completa, si ejecuto mis pruebas dará el error esperado para dedicarme
a resolverlo. Nota que siempre necesito inicialmente algunos archivos o configuraciones adicionales
y luego nos dedicamos a resolver nuestro código.
Capítulo 9: API y nada mas 110

1 vendor/bin/phpunit --filter test_can_get_a_post


2 PHPUnit 8.5.1 by Sebastian Bergmann and contributors.
3
4 F 1 / 1 (100%)
5
6 Time: 261 ms, Memory: 22.00 MB
7
8 There was 1 failure:
9
10 1) Tests\Feature\Http\Controllers\Api\PostTest::can_get_a_post
11 Invalid JSON was returned from the route.
12
13 /opt/lampp/htdocs/api/vendor/laravel/framework/src/Illuminate/Foundation/Testing/Tes\
14 tResponse.php:809
15 /opt/lampp/htdocs/api/vendor/laravel/framework/src/Illuminate/Foundation/Testing/Tes\
16 tResponse.php:656
17 /opt/lampp/htdocs/api/tests/Feature/Http/Controllers/Api/PostTest.php:95
18
19 FAILURES!
20 Tests: 1, Assertions: 1, Failures: 1.

El código de nuestro show es el siguiente:

1 <?php
2
3 namespace App\Http\Controllers\Api;
4
5 use App\Http\Controllers\Controller;
6 use Illuminate\Http\Request;
7
8 use App\Post;
9 use App\Http\Requests\Post as PostRequest;
10 use App\Http\Resources\Post as PostResource;
11
12 class PostController extends Controller
13 {
14 //...
15
16 /**
17 * Display the specified resource.
18 *
19 * @param int $id
20 * @return \Illuminate\Http\Response
Capítulo 9: API y nada mas 111

21 */
22 public function show(Post $post)
23 {
24 return response()->json(new PostResource($post));
25 }
26
27 //...
28 }

Esto nos ayudará a retornar los datos con el formato planificado hace un momento con el recurso:

1. Buscamos el recurso.
2. Damos formato.
3. Retornamos.

Y el resultado es evaluado por nuestro test.

1 $ vendor/bin/phpunit --filter test_can_get_a_post


2 PHPUnit 8.5.1 by Sebastian Bergmann and contributors.
3
4 . 1 / 1 (100%)
5
6 Time: 300 ms, Memory: 22.00 MB
7
8 OK (1 test, 5 assertions)

Y todas las pruebas

1 $ vendor/bin/phpunit
2 PHPUnit 8.5.1 by Sebastian Bergmann and contributors.
3
4 .... 4 / 4 (100%)
5
6 Time: 290 ms, Memory: 24.00 MB
7
8 OK (4 tests, 18 assertions)

Aquí pause, quiero que comprendas cómo es que esto funciona.


Estamos en teoría avanzando lento, pero no es así, estamos respaldando nuestro trabajo con pruebas
automaticas que en el futuro te ayudarán a ti y a otros a entender mejor el código. De esta manera
es díficil que se nos escapen algunas configuraciones.
Siempre verás a la línea $this->withoutExceptionHandling(); la utilizo para revisar mejor mis
errores y luego la comento.
Capítulo 9: API y nada mas 112

Prueba de 404
Esto funciona, no necesitamos probarlo, es así cuando usamos la inyeccion de modelos implicita, sin
embargo podemos usar un test que respalde esa funcionalidad que no necesitamos programar.

1 <?php
2
3 namespace Tests\Feature\Http\Controllers\Api;
4
5 use Illuminate\Foundation\Testing\RefreshDatabase;
6 use Illuminate\Foundation\Testing\WithFaker;
7 use Tests\TestCase;
8
9 use App\User;
10 use App\Post;
11
12 class PostTest extends TestCase
13 {
14 use RefreshDatabase;
15
16 //...
17
18 /**
19 * Si el post no existe recibiré un 404.
20 */
21 public function test_get_404_if_the_post_is_not_found()
22 {
23 //$this->withoutExceptionHandling();
24
25 $user = factory(User::class)->create();
26
27 $response = $this->actingAs($user, 'api')->json('GET', '/api/posts/1000');
28
29 $response->assertStatus(404);
30 }
31 }

1. Creo a un usuario.
2. Accedo a un post que no existe “Al número 1000”.
3. Recibo 404.

Genial!
Capítulo 9: API y nada mas 113

Tengo allí la línea //$this->withoutExceptionHandling(); que no usé pero ya es costumbre dejarla


en cada método, la puedes eliminar si deseas.

Update

Actualización de un post
1 <?php
2
3 namespace Tests\Feature\Http\Controllers\Api;
4
5 use Illuminate\Foundation\Testing\RefreshDatabase;
6 use Illuminate\Foundation\Testing\WithFaker;
7 use Tests\TestCase;
8
9 use App\User;
10 use App\Post;
11
12 class PostTest extends TestCase
13 {
14 use RefreshDatabase;
15
16 //...
17
18 /**
19 * Los usuarios autenticados pueden actualizar un post.
20 */
21 public function test_a_user_can_update_a_post()
22 {
23 //$this->withoutExceptionHandling();
24
25 $user = factory(User::class)->create();
26 $post = factory(Post::class)->create();
27
28 $response = $this->actingAs($user, 'api')->json('PUT', "/api/posts/$post->id\
29 ", [
30 'title' => 'Nuevo título'
31 ]);
32
33 $response->assertJsonStructure(['id', 'title', 'created'])
34 ->assertJson(['title' => 'Nuevo título'])
35 ->assertStatus(200);
Capítulo 9: API y nada mas 114

36
37 $this->assertDatabaseHas('posts', [
38 'title' => 'Nuevo título'
39 ]);
40 }
41 }

1. Creamos un usuario.
2. Creamos un post para luego actualizar su título.
3. Esperamos entonces retornar la estructura, el nuevo título y un estatus HTTP 200.
4. Finalmente revisamos si el dato esta correctamente guardado en la base de datos.

1 $ vendor/bin/phpunit --filter test_a_user_can_update_a_post


2 PHPUnit 8.5.1 by Sebastian Bergmann and contributors.
3
4 F 1 / 1 (100%)
5
6 Time: 251 ms, Memory: 22.00 MB
7
8 There was 1 failure:
9
10 1) Tests\Feature\Http\Controllers\Api\PostTest::a_user_can_update_a_post
11 Invalid JSON was returned from the route.
12
13 /opt/lampp/htdocs/api/vendor/laravel/framework/src/Illuminate/Foundation/Testing/Tes\
14 tResponse.php:809
15 /opt/lampp/htdocs/api/vendor/laravel/framework/src/Illuminate/Foundation/Testing/Tes\
16 tResponse.php:656
17 /opt/lampp/htdocs/api/tests/Feature/Http/Controllers/Api/PostTest.php:132
18
19 FAILURES!
20 Tests: 1, Assertions: 1, Failures: 1.

Resolvemos la actualizacion con el siguiente codigo


Capítulo 9: API y nada mas 115

1 <?php
2
3 namespace App\Http\Controllers\Api;
4
5 use App\Http\Controllers\Controller;
6 use Illuminate\Http\Request;
7
8 use App\Post;
9 use App\Http\Requests\Post as PostRequest;
10 use App\Http\Resources\Post as PostResource;
11
12 class PostController extends Controller
13 {
14 //...
15
16 /**
17 * Update the specified resource in storage.
18 *
19 * @param \Illuminate\Http\Request $request
20 * @param int $id
21 * @return \Illuminate\Http\Response
22 */
23 public function update(PostRequest $request, Post $post)
24 {
25 $post->update($request->all());
26
27 return response()->json(new PostResource($post));
28 }
29
30 //...
31 }

Al revisar la prueba obtenemos un mensaje hermoso de que la prueba ha pasado.


Capítulo 9: API y nada mas 116

1 $ vendor/bin/phpunit --filter test_a_user_can_update_a_post


2 PHPUnit 8.5.1 by Sebastian Bergmann and contributors.
3
4 . 1 / 1 (100%)
5
6 Time: 266 ms, Memory: 24.00 MB
7
8 OK (1 test, 6 assertions)

Y revisamos todo, no pasamos filtros para verificar que no hemos dañado nada de nada.

1 $ vendor/bin/phpunit
2 PHPUnit 8.5.1 by Sebastian Bergmann and contributors.
3
4 ...... 6 / 6 (100%)
5
6 Time: 286 ms, Memory: 24.00 MB
7
8 OK (6 tests, 25 assertions)

No revisamos la validación porque usa la misma clase Request que en la creación, puedes crear ese
test si deseas.
Vamos ahora a crear el codigo de index y destroy.

Delete

Eliminar un post
1 <?php
2
3 namespace Tests\Feature\Http\Controllers\Api;
4
5 use Illuminate\Foundation\Testing\RefreshDatabase;
6 use Illuminate\Foundation\Testing\WithFaker;
7 use Tests\TestCase;
8
9 use App\User;
10 use App\Post;
11
12 class PostTest extends TestCase
13 {
Capítulo 9: API y nada mas 117

14 use RefreshDatabase;
15
16 //...
17
18 /**
19 * Los usuarios autenticados pueden eliminar un post.
20 */
21 public function test_can_delete_a_post()
22 {
23 //$this->withoutExceptionHandling();
24
25 $user = factory(User::class)->create();
26 $post = factory(Post::class)->create();
27
28 $response = $this->actingAs($user, 'api')->json('DELETE', "/api/posts/$post-\
29 >id",[
30 'title' => 'Nuevo título'
31 ]);
32
33 $response->assertStatus(204)->assertSee(null);
34
35 $this->assertDatabaseMissing('posts', ['id' => $post->id]);
36 }
37 }

Al probar

1 $ vendor/bin/phpunit --filter test_can_delete_a_post


2 PHPUnit 8.5.1 by Sebastian Bergmann and contributors.
3
4 F 1 / 1 (100%)
5
6 Time: 257 ms, Memory: 22.00 MB
7
8 There was 1 failure:
9
10 1) Tests\Feature\Http\Controllers\Api\PostTest::can_delete_a_post
11 Expected status code 204 but received 200.
12 Failed asserting that false is true.
13
14 /opt/lampp/htdocs/api/vendor/laravel/framework/src/Illuminate/Foundation/Testing/Tes\
15 tResponse.php:185
16 /opt/lampp/htdocs/api/tests/Feature/Http/Controllers/Api/PostTest.php:157
Capítulo 9: API y nada mas 118

17
18 FAILURES!
19 Tests: 1, Assertions: 1, Failures: 1.

Recibimos 200 y esperamos 204, el codigo correcto del test es el siguiente.

1 <?php
2
3 namespace App\Http\Controllers\Api;
4
5 use App\Http\Controllers\Controller;
6 use Illuminate\Http\Request;
7
8 use App\Post;
9 use App\Http\Requests\Post as PostRequest;
10 use App\Http\Resources\Post as PostResource;
11
12 class PostController extends Controller
13 {
14 //...
15
16 /**
17 * Remove the specified resource from storage.
18 *
19 * @param int $id
20 * @return \Illuminate\Http\Response
21 */
22 public function destroy(Post $post)
23 {
24 $post->delete();
25
26 return response()->json(null, 204);
27 }
28 }

Al confirmar en el terminal vemos que la prueba pasa.


Capítulo 9: API y nada mas 119

1 $ vendor/bin/phpunit --filter test_can_delete_a_post


2 PHPUnit 8.5.1 by Sebastian Bergmann and contributors.
3
4 . 1 / 1 (100%)
5
6 Time: 297 ms, Memory: 22.00 MB
7
8 OK (1 test, 3 assertions)

Todos los test

1 $ vendor/bin/phpunit
2 PHPUnit 8.5.1 by Sebastian Bergmann and contributors.
3
4 ....... 7 / 7 (100%)
5
6 Time: 295 ms, Memory: 24.00 MB
7
8 OK (7 tests, 28 assertions)

Index

Metodo Index
Aqui esperamos retornar una coleccion de datos paginada. Ademas me interesa que individualmente
cada registro tenga el mismo formato que en los post individual, me refiero a que por ejemplo
created_ad llegue como string y se llame created.
La prueba es.

1 <?php
2
3 namespace Tests\Feature\Http\Controllers\Api;
4
5 use Illuminate\Foundation\Testing\RefreshDatabase;
6 use Illuminate\Foundation\Testing\WithFaker;
7 use Tests\TestCase;
8
9 use App\User;
10 use App\Post;
11
Capítulo 9: API y nada mas 120

12 class PostTest extends TestCase


13 {
14 use RefreshDatabase;
15
16 //...
17
18 /**
19 * Los usuarios autenticados pueden acceder al listado de posts.
20 */
21 public function test_can_see_paginated_post_list()
22 {
23 //$this->withoutExceptionHandling();
24
25 $user = factory(User::class)->create();
26 factory(Post::class, 5)->create();
27
28 $response = $this->actingAs($user, 'api')->json('GET', '/api/posts');
29
30 $response->assertJsonStructure([
31 'data' => [
32 '*' => ['id', 'title', 'created']
33 ],
34 'links' => ['first', 'last', 'prev', 'next'],
35 ])->assertStatus(200);
36 }
37
38 //...
39 }

Básicamente quiero la estructura que Laravel provee para un listado paginado de datos.

1. Creo un usuario para loguearme.


2. Creo cinco post para probar.
3. Me conecto.
4. Reviso la estructura que obtengo.
5. Finalmente reviso si realmente obtengo estatus HTTP 200.

Necesito crear una colección de datos como cuando trabajamos con un recurso individual, ya lo
haremos.
Capítulo 9: API y nada mas 121

1 $ vendor/bin/phpunit --filter test_can_see_paginated_post_list


2 PHPUnit 8.5.1 by Sebastian Bergmann and contributors.
3
4 F 1 / 1 (100%)
5
6 Time: 272 ms, Memory: 22.00 MB
7
8 There was 1 failure:
9
10 1) Tests\Feature\Http\Controllers\Api\PostTest::can_see_paginated_post_list
11 Invalid JSON was returned from the route.
12
13 /opt/lampp/htdocs/api/vendor/laravel/framework/src/Illuminate/Foundation/Testing/Tes\
14 tResponse.php:809
15 /opt/lampp/htdocs/api/vendor/laravel/framework/src/Illuminate/Foundation/Testing/Tes\
16 tResponse.php:656
17 /opt/lampp/htdocs/api/tests/Feature/Http/Controllers/Api/PostTest.php:48
18
19 FAILURES!
20 Tests: 1, Assertions: 1, Failures: 1.

Alli podemos ver que falla porque realmente no estamos obteniendo nada.
Vamos a trabajar en el controlador.

1 <?php
2
3 namespace App\Http\Controllers\Api;
4
5 use App\Http\Controllers\Controller;
6 use Illuminate\Http\Request;
7
8 use App\Post;
9 use App\Http\Requests\Post as PostRequest;
10 use App\Http\Resources\Post as PostResource;
11 use App\Http\Resources\PostCollection;
12
13 class PostController extends Controller
14 {
15 protected $post;
16
17 public function __construct(Post $post)
18 {
Capítulo 9: API y nada mas 122

19 $this->post = $post;
20 }
21
22 /**
23 * Display a listing of the resource.
24 *
25 * @return \Illuminate\Http\Response
26 */
27 public function index()
28 {
29 return new PostCollection($this->post->paginate());
30 }
31
32 //...
33 }

Esto es nuevo use App\Http\Resources\PostCollection;, sé que lo necesito y lo programo de una


vez.

1 $ php artisan make:resource PostCollection


2 Resource collection created successfully.

El mensaje es diferente a cuando creamos un recurso para Post. Recordemos.

1 $ php artisan make:resource Post


2 Resource created successfully.

Nota que desde ya nos conseguimos con la diferencia, cuando usamos la palabra Collection Laravel
entiende que se trata de un listado o muchos datos, y cuando no la usamos entonces entiende que
se trata del formato individual del recurso.
Este archivo lo creamos para no configurarlo porque como viene por defecto nos funciona.

1 <?php
2
3 namespace App\Http\Resources;
4
5 use Illuminate\Http\Resources\Json\ResourceCollection;
6
7 class PostCollection extends ResourceCollection
8 {
9 /**
10 * Transform the resource collection into an array.
Capítulo 9: API y nada mas 123

11 *
12 * @param \Illuminate\Http\Request $request
13 * @return array
14 */
15 public function toArray($request)
16 {
17 return parent::toArray($request);
18 }
19 }

1. Tenemos el test.
2. Tenemos el metodo index configurado.
3. Finalmente existe el recurso que me va a formatear la coleccion.

Testeamos el metodo de pruebas

1 $ vendor/bin/phpunit --filter can_see_paginated_post_list


2 PHPUnit 8.5.1 by Sebastian Bergmann and contributors.
3
4 . 1 / 1 (100%)
5
6 Time: 277 ms, Memory: 22.00 MB
7
8 OK (1 test, 23 assertions)

Todos los tests

1 $ vendor/bin/phpunit
2 PHPUnit 8.5.1 by Sebastian Bergmann and contributors.
3
4 ........ 8 / 8 (100%)
5
6 Time: 392 ms, Memory: 24.00 MB
7
8 OK (8 tests, 51 assertions)

Tenemos ocho tests:

1. Acceso prohibido para quien no este logueado.


2. Store
3. Validacion si se intenta guardar un post sin titulo.
Capítulo 9: API y nada mas 124

4. Show
5. 404 si no hay post
6. Update
7. Index
8. Destroy

Ademas que cuando creamos el recurso Post y PostCollection mantenemos un formato que solo se
configuró en el recurso Post, ya eso es suficiente, debido a que mantenemos el nombre PostCollection
usa lo configurado en Post.

Usuarios Invitados
Esto ya está preparado, sin embargo es importante respaldarlo mediante una prueba.

1 <?php
2
3 namespace Tests\Feature\Http\Controllers\Api;
4
5 use Illuminate\Foundation\Testing\RefreshDatabase;
6 use Illuminate\Foundation\Testing\WithFaker;
7 use Tests\TestCase;
8
9 class PostTest extends TestCase
10 {
11 /**
12 * Los usuarios no autenticados no pueden acceder al api de post.
13 */
14 public function test_unauthenticated_users_cannot_access_the_post_api()
15 {
16 //$this->withoutExceptionHandling();
17
18 $this->json('GET', '/api/posts')->assertStatus(401);
19 $this->json('POST', '/api/posts')->assertStatus(401);
20 $this->json('GET', '/api/posts/1000')->assertStatus(401);
21 $this->json('PUT', '/api/posts/1000')->assertStatus(401);
22 $this->json('DELETE', '/api/posts/1000')->assertStatus(401);
23 }
24 }

Dice que espera 401 “no autorizado”, esto es así porque hemos protegido a nuestras rutas con el
middleware auth:api.
Capítulo 9: API y nada mas 125

La idea es proteger a Index, Store, Show, Update y Destroy.


En el terminal podemos ver que lo hemos logrado, he logrado proteger a mis rutas.

1 $ vendor/bin/phpunit --filter test_unauthenticated_users_cannot_access_the_post_api \


2
3 PHPUnit 8.5.1 by Sebastian Bergmann and contributors.
4
5 . 1 / 1 (100%)
6
7 Time: 111 ms, Memory: 16.00 MB
8
9 OK (1 test, 5 assertions)

Ahi vemos que se hizo un test (un metodo) y cinco afirmaciones (cada una de los asserts), son cinco
porque hemos testeado cinco rutas.
Resultado: Controlador y Rutas protegidas.
Parte 5: Ingeniería de Software
Capítulo 10: PHP
Yo solo enseño PHP, es un lenguaje que me ha dado de comer a mí y a mi familia, espero le tengas
mucho cariño como yo y formalices tu relación con este super lenguaje; de hecho quiero que tú
próxima aplicación sea hecha en PHP.
Saber PHP es aprender al mismo tiempo Laravel. Veamos algunos conceptos.

Función como Parámetro


Esto quiere decir, pasar pequeñas secciones o bloqués de código a funciones. No parámetro comunes,
sino más bien lógica pura.
Además decimos el tipo de parámetro usando la palabra Closure delante del parámetro función,
esto es para asegurarnos de que unicamente es permitido pasar funciones anónimas y no variable
común. Esto es un objeto en PHP.

1 <?php
2
3 function greet(Closure $gender, $name) {
4 return $gender($name);
5 }
6
7 $female = function ($name) {
8 return "Hola señora, {$name}";
9 };
10
11 $male = function ($name) {
12 return "Hola señor, {$name}";
13 };
14
15 echo greet($female, 'Luisa Fantone');
16 echo '<br>';
17 echo greet($male, 'Italo Morales');

Explicación:

• Primero tenemos una función llamada greet(), pero en realidad no está saludando a nadie.
Sin embargo su utilidad es recibir una función anónima y ahí está la magía… Porque desde ahí
llamamos a la Closure y le pasamos el nombre para que salude a quien deseamos saludar.
Capítulo 10: PHP 128

• Mas abajo tenemos dos funciones anónimas asignadas a las variables $female y $male. Ambas
reciben el parámetro $name y tienen la lógica para saludar correctamente.
• Por último tenemos el uso y llamado a la función greet().

Y con esto culminamos lo que para muchos es díficil de entender, las funciones anónimas o closure.
Las clases nos ayudan a definir una estructura manejable y entendible de nuestro sistema, este
termino da vida a los que conocemos como programación orientada a objetos (POO en español,
OOP en inglés). La teoría dice, “esto significa que tratas a tu código o partes de él como objetos de la
vida real y esto podría resultar muy familiar para nosotros porque nos acerca al mundo tal y como
lo conocemos”. Aunque parece que esto siempre es confuso. Para entender, podríamos empezar con
nuestra primera clase.
Luego de esta introducción, veamos conceptos propios de la programación orientada a objetos.

Clases en PHP
Podemos iniciar con código, definiendo un propósito y pensando en que éste archivo represente
algo… Digamos a una persona, aunque pudiera ser un libro, fruta, email, etc. Llamaremos a nuestra
clase Person.

1 <?php
2
3 /**
4 * this class represents a person
5 */
6 class Person
7 {
8
9 }

• Solo para que puedas familiarizarte con la sintaxis, es bastante similar a una función. Todo su
bloque o código está entre { llaves }
• Todo comienza con la palabra reservada class y luego el nombre de la clase que queremos
crear, en este caso Person
• Lo correcto es crear un archivo solo para tu clase con el nombre de la clase, en este caso nuestro
archivo se llamaría Person.php

Es una buena práctica nombrar a las clases con la primera letra en mayúsculas, esto se
llama CamelCase y es un estilo de escritura que se aplica a frases o palabras compuestas.
El nombre se debe a que las mayúsculas a lo largo de una palabra en CamelCase se
asemejan a las jorobas de un camello.
Capítulo 10: PHP 129

De momento no podemos hacer nada con esta clase pero para que vaya tomando forma podemos
crear propiedades. El objetivo de una propiedad es añadir características y en cada una de ellas
almacenar datos. Ejemplo: Un libro puede tener título, una persona nombre, una fruta puede tener
sabor, un email tiene un asunto y texto, y así…
Vamos a trabajar solo con nombre y apellido.

1 <?php
2
3 /**
4 * this class represents a person
5 */
6 class Person
7 {
8 var $name;
9 var $lastname;
10 }

Como puedes ver, las propiedades comienzan con la palabra var, en este caso son variables pero
las variables de una clase se llaman propiedades. Aquí usaremos var, sin embargo, mas adelante en
Rimorsoft conocerás todas las alternativas.
Hasta aquí terminamos con las clases, veamos el siguiente paso:

Instancias
Imagina a una clase como un plano o un molde… A partir de aquí nacen los objetos. Y quiero que
solo aprendas esto, instanciar es crear un objeto a partir de una clase, para ello usamos la palabra
reservada new. Veamos:
Archivo Person.php

1 <?php
2
3 /**
4 * this class represents a person
5 */
6 class Person
7 {
8 var $name;
9 var $lastname;
10 }

Archivo index.php
Capítulo 10: PHP 130

1 <?php
2
3 require 'Person.php';
4
5 $person = new Person;

Crear un objeto o crear una instancia es lo mismo y se logra usando la palabra new, toma en cuenta
que esto sucede gracias a que ya contamos con la clase Person. En este ejemplo, nuestro objeto se
llama $person… Ya el objeto vive, existe al escribir $person = new Person.
Lo interesante es que ya dentro de $person están disponibles las propiedades y podemos usarlas.

1 <?php
2
3 require 'Person.php';
4
5 $person = new Person;
6 $person->name;

Usar una propiedad solo consiste en hacer uso del operador de objeto ->, que es un guión - seguido
por un mayor que > (forma una flechita hacia la derecha). Luego escribimos el nombre de la
propiedad que deseamos usar, en este caso name y queda así $person->name;.

NOTA: De momento, al escribir $person->name; no verás nada en el navegador.

Hasta el momento solo sintaxis, aunque intento que sea fácil y ameno, quiero que estés con
buena base para los cursos que vienen en el canal.

Método
En una clase, una función común y corriente se le llama método y es donde vamos a colocar nuestro
código o lógica. Veamos como se define:
Archivo Person.php
Capítulo 10: PHP 131

1 <?php
2
3 /**
4 * this class represents a person
5 */
6 class Person
7 {
8 var $name;
9 var $lastname;
10
11 function greet()
12 {
13 return 'Hola, cómo estás?';
14 }
15 }

Archivo index.php

1 <?php
2
3 require 'Person.php';
4
5 $person = new Person;
6 echo $person->greet();

De nuevo usamos la palabra reservada function, pero en este caso para definir un método. Recuerda:
Las funciones en nuestras clases se les llaman métodos, Aquí podemos ver que nuestro método
se llama greet() y solo retorna un Hola, cómo estás?.
Al crear un objeto podemos ejecutar al método usando a nuestro operador “flechita” -> (este sirve
para acceder a variables, asignar valor y acceder a métodos).

$this
Nuestra clase tiene propiedades y métodos, así que es muy probable que necesitemos acceder a ellas.
Y si, están disponibles para nosotros, y podemos acceder a ellas usando al gran $this.
$this es una referencia a la instancia actual, si escribimos $this->name es como decir mi nombre.
Su uso es para acceder a propiedades y métodos desde dentro de un método de la clase.
Archivo Person.php
Capítulo 10: PHP 132

1 <?php
2
3 /**
4 * this class represents a person
5 */
6 class Person
7 {
8 var $name;
9 var $lastname;
10
11 function greet()
12 {
13 return "Hola, {$this->name} cómo estás?";
14 }
15 }

Archivo index.php

1 <?php
2
3 require 'Person.php';
4
5 $person = new Person;
6 echo $person->greet();

La sección interesante de este apartado es return "Hola, {$this->name} cómo estás?"; de la clase
Person, ahí vemos claramente la idea y el propósito de $this… Accedemos a la propiedad name desde
el método greet().
En este caso no hay mucho sentido, si ejecutas el código no habrá un nombre impreso en pantalla.
Pero avancemos, ya verás un nombre en pantalla.

En el método greet() usamos ahora comillas dobles y es porque en el texto hemos incluido
una variable.

Constructor - Método especial __construct()


Un constructor forma parte de una serie de métodos especiales. Este se ejecuta al momento de crear
una nueva instancia de la clase (al crear un objeto). Lo interesante es que podemos comenzar nuestro
objeto con datos básicos, por ejemplo en Person podemos empezar dando de alta el nombre y apellido
justo en el momento de instanciar. En otras palabras, es la gran oportunidad de establecer valores a
las propiedades de la clase para que nuestra clase tenga con que trabajar.
Archivo Person.php
Capítulo 10: PHP 133

1 <?php
2
3 /**
4 * this class represents a person
5 */
6 class Person
7 {
8 var $name;
9 var $lastname;
10
11 public function __construct($name, $lastname)
12 {
13 $this->name = $name;
14 $this->lastname = $lastname;
15 }
16
17 function greet()
18 {
19 return "Hola, {$this->name} cómo estás?";
20 }
21 }

Archivo index.php

1 <?php
2
3 require 'Person.php';
4
5 $person = new Person('Italo', 'Morales');
6 echo $person->greet();

Aquí toma en cuenta lo siguiente, usamos el método especial __construct() cuando necesitamos
iniciar con algo de datos, ejemplo: La clase email necesita para enviar el mensaje un asunto, un
remitente, un destinatario y un texto final… Entonces iniciamos esta clase con estos datos y luego
procedemos a enviar el mensaje.
Aquí si veremos un nombre impreso en pantalla, porque lo hemos grabado en la clase justo en el
momento en que creamos el objeto $person = new Person('Italo', 'Morales');

Varias instancias, (varios objetos, una clase)


Esto quiere decir, tener varios objetos a partir de una única clase, siguiendo con lo anterior, hablo
de dos o más personas.
Archivo index.php
Capítulo 10: PHP 134

1 <?php
2
3 require 'Person.php';
4
5 $client = new Person('Italo', 'Morales');
6 echo $client->greet();
7
8 $seller = new Person('Luisa', 'Fantone');
9 echo $seller->greet();

En este caso los objetos se llaman $client y $seller, cada uno es una persona y nacen a partir de
la clase Person y eso es reutilización de código, puedes notar que hay una sola clase y dos objetos.
¡Esto es magía!.
Esto es lo que debemos conocer de las clases y objetos.

• Una clase es un molde


• Un objeto es formado a partir de un molde (una clase)
• La estructura de una clase es: Inicia con la palabra class, propiedades, constructor y métodos.

Programación Orientada a Objetos


¿PHP es un lenguaje orientado a objetos? La respuesta es SI, con PHP contamos con todo lo que se
requiere; podemos por supuesto crear clases, objetos, estos por supuesto pueden heredar y mantener
una comunicación.
Cuando hablamos de paradigma nos referimos a “modelo”, “forma” o “ejemplo”, con esto queremos
decir que para hacer una acción se toma como modelo o ejemplo otra ya establecida. En otras
palabras, tenemos el paradigma de programación estructurada o el paradigma de la programación
orientada a objetos.
Esto es importante mencionarlo porque existen diferentes paradigmas y aquí¹ puedes ampliar esa
información.
Existen muchos paradigma pero hablemos de programación estructurada y programación orientada
a objetos.

1. Programación estructurada: Es lo que aprendemos en la universidad en la materia lógica de


programación, computación 1, etc… Se trata de programar mediante rutinas básicas como if,
switch, for, while, etc. (crearé un curso sobre esto para que todos pasen esa materia con éxito).
2. Programación Orientada a Objetos: Cómo ya mencionamos está basada en varios conceptos:
herencia, abstracción, polimorfismo y otras. Todo esto lo veremos en esta serie. Esto no es
nuevo, desde la década de 1990 se viene usando este paradigma.
¹https://es.wikipedia.org/wiki/Lenguaje_de_programación#Paradigmas
Capítulo 10: PHP 135

Con PHP podemos trabajar con ambos paradigmas… ¿es un lenguaje estructurado? SI, ¿es un
lenguaje orientado a objetos? SI, también lo es.
La mala fama que alguna vez tubo PHP y que aún mantiene “un poco” se debe precisamente a
que muchas personas creaban un index.php, dentro tenían mucho código estructurado y buscaban
trabajo como programador. Su misma flexibilidad ayudó a que sea el lenguaje mas usado en el
mundo y al mismo tiempo se ganó esa mala fama.
Pero vamos poco a poco ayudando a que trabajemos mejor. Yo enseñando hago mi parte y tu haces
la tuya aprendiendo. ¡Somos un buen equipo!.
Entonces, PHP al permitir clases, herencia, objetos y todo lo mencionado anteriormente lo convierte
en un lenguaje orientado a objetos.
Antes de continuar te comento que es recomendable estudiar nuestra serie PHP para principiantes²,
podría decirse que esta serie es la continuación de PHP para principiantes.
Tenemos elementos fundamentales, esto es en realidad lo que vamos a aprender en esta serie,
aclaremos todo al respecto:

1. Abstracción.
2. Encapsulamiento.
3. Modularidad.
4. Herencia.
5. Polimorfismo.

Te invito a seguir este material de cerca.


Aquí verás los conceptos de programación orientada a objetos.

Abstraccion
La definición de diccionario: Consideración aislada de las cualidades esenciales de un objeto, o del
mismo objeto en su pura esencia o noción: es un ejercicio de abstracción.
Definición de programación: Esta característica es esencial, nos ayuda a expresar claramente que
queremos lograr como resultado final. La abstracción es una técnica usada para el análisis y diseño
orientado a objetos, mediante ella detallamos el problema que se quiere atacar para resolverlo
fácilmente.
Un dato clave seria decir que la interfaz es sinónimo de aislar, separar y sacar, si es así ¿cuando lo
hacemos?.
Hablando de inmediato de temas prácticos podemos decir que es describir una clase a través de
propiedades y métodos, crear una interfaz, usar una clase abstracta, etc. Todo esto expresa este
principio, veamos a continuación ejemplos:

Interfaz
²https://rimorsoft.com/curso/php-para-principiantes
Capítulo 10: PHP 136

1 <?php
2
3 namespace App\Connection;
4
5 interface Store
6 {
7 public function get();
8
9 public function increment($value = 1);
10
11 public function decrement($value = 1);
12 }

Implementemos esta interfaz en nuestra clase:

1 <?php
2
3 namespace App\Connection;
4
5 class Database implements Store
6 {
7 public function get()
8 {
9 //...
10 }
11
12 public function increment($value = 1)
13 {
14 //...
15 }
16
17 public function decrement($value = 1)
18 {
19 //...
20 }
21 }

Aquí vemos una clase con tres métodos, toma en cuenta que estos métodos son obligatorios porque
la interfaz lo ha definido… Cuando tu implementas una interfaz es porque usarás todos sus métodos.
Crear y usar una interfaz es abstracción.
En términos mas amplios, una interfaz nos permite crear código en los métodos de la clase que la
implemente. Nota que todos los métodos escritos en la interfaz son y deben ser públicos, es ésta es la
Capítulo 10: PHP 137

naturaleza de una interfaz. Una interfaz solo se encargará de mostrar el comportamiento específico
de la clase que la implemente.

• El ¿Qué hace? es la interfaz.


• El ¿Cómo lo hace? corresponde a la clase que es quien desarrolla cada método.

Clase Abstracta

1 <?php
2
3 namespace App;
4
5 abstract class Lock
6 {
7 abstract public function acquire();
8
9 public function get()
10 {
11 //...
12 }
13 }

Veamos cómo extender de una clase abstracta.

1 <?php
2
3 namespace App;
4
5 class Cached extends Lock
6 {
7 public function acquire()
8 {
9 //...
10 }
11 }

Reglas de una clase abstracta:

1. Las clases abstractas no se pueden instanciar.


2. Si una clase abstracta contiene un método abstracto, este debe definirse de forma obligatoria
en la clase hija.
Capítulo 10: PHP 138

3. Los métodos abstractos solo se declaran en la clase abstracta, pero se desarrolla en la clase que
lo implemente.

Observa que nuestra clase abstracta Lock declara el método acquire() pero no lo desarrolla.
Observa también que desde la clase Cached extendemos de la clase abstracta Lock, lo que quiere decir
es que todos los métodos definidos como abstractos en Lock deben ser desarrollados en Cached. Por
otro lado, toma en cuenta que el método get() no es abstracto, por ello no es obligatorio desarrollarlo
en la clase Cached.
Sobre clases abstracta e interfaces haremos futuras lecciones, de momento solo vamos a ocuparnos
del concepto de abstracción.

Una Clase

1 <?php
2
3 namespace App;
4
5 class Auth
6 {
7 protected $email;
8 protected $password;
9
10 public function login()
11 {
12 //...
13 }
14
15 protected function validate()
16 {
17 //...
18 }
19
20 protected function attempt()
21 {
22 //...
23 }
24
25 protected function failed()
26 {
27 //...
28 }
29
Capítulo 10: PHP 139

30 protected function response()


31 {
32 //...
33 }
34 }

Aquí ilustramos un punto de vista válido, la abstracción muestra las características o detalles de
un objeto, quiero decir que no nos importan los detalles. Mira que en el ejemplo solo declaré los
métodos (eso es abstracción).
… ¿Cuales son las acciones comunes y qué quiero como resultado final?

1. Abstracción de Persona: Hablar, reír, comer, ir al baño, etc.


2. Abstracción de Animal: Comer, dormir, caminar, correr, etc.
3. Abstracción de Usuario: Registrarse, iniciar sesión, actualizar perfil, etc.

Y así, podemos listar todo acerca de cualquier cosa. Al hacerlo debemos incluir las características y
comportamientos.
La abstracción es un concepto propio de la programación orientada a objetos, esto puede ser aplicado
en Java, PHP y muchos otros lenguajes de programación.
En esta lección vimos interfaces, clases abstractas y una clase; tres ejemplos válidos para ver cómo
implementar este concepto en PHP. Abstracción es aislar, separar y sacar… Partiendo de ahí nacieron
estos ejemplos.
Si llevamos a un papel alguna solicitud de este tipo podríamos pensar en lo común y no en el detalle.
Esto ayuda a solucionar los problemas.

Encapsulamiento
Sobre esto hablé en la serie llamada PHP para principiantes pero en ese curso hablamos de temas
prácticos respecto a PHP, aquí veremos el termino desde el punto de vista de la programación
orientada a objetos. Aquí el enlace a la serie que te comento³.
Con el encapsulamiento garantizamos la integridad de los datos o propiedades de un objeto, y por
integridad quiero decir que los datos se mantengan correctos y estén completos, al mismo tiempo
evitamos que se acceda a cualquier dato si no queremos.
Imagina desarrollar diferentes propiedades y decidir que quieres que sea público, protegido o
privado… OK, eso que imaginas es el encapsulamiento.
¿Qué logramos?

1. Proteges propiedades.
³https://rimorsoft.com/alcance-public-private-y-protected-en-php
Capítulo 10: PHP 140

2. Proteger métodos.

Esto es un concepto de programación orientada a objetos, PHP nos permite encapsular y ya veremos
un ejemplo.
¿Cuando lo usamos?
Al pensar que nuestros métodos o propiedades necesitan un poco de seguridad extra. Las preguntas
que te ayudarán a tomar esta decisión son las siguiente:

1. ¿Esta propiedad o método será usada solo en esta clase?.


2. ¿Esta propiedad o método será usada desde una clase externa?.
3. ¿Esta propiedad o método será usada solo por quienes hereden de mi?.

En otras palabras, este concepto o principio habla propiamente del nivel de acceso que podemos
tener hacia una propiedad o método de una clase y como has podido notar nos da un nivel extra de
seguridad restringiendo el acceso de acuerdo a la decisión que tomemos.

1. Acceso público (public): Se resume en “No hay restricciones”.


2. Acceso privado (private): Este nivel solo permite el accedo desde nuestra misma clase.
3. Acceso protegido (protected): Con este nivel permitimos el acceso desde nuestra misma clase
y de quienes hereden de mi.

¿Qué puedes encapsular?: Hablando de PHP podrías encapsular propiedades, constantes y métodos.
Veamos a continuación un ejemplo:

1 <?php
2
3 class User
4 {
5 public const PAGINATE = 25;
6 //private const PAGINATE = 25;
7 //protected const PAGINATE = 25;
8
9 public $username;
10 //private $username;
11 //protected $username;
12
13 public function getUsername()
14 {
15 //...
16 }
17 //...
18 }
Capítulo 10: PHP 141

Así definimos nuestra estructura, siempre será bajo nuestro criterio.


Generalmente conseguimos el acceso a nuestros métodos usando el prefijo get y set que necesaria-
mente son public, en nuestro ejemplo escribí getUsername().
Nota como todo va de la mano, en este caso podemos tranquilamente abstraer y a medida que
redactamos a la clase podemos ir encapsulando.
En Laravel tenemos por defecto en la entidad User.php algunos ejemplos:

1 <?php
2
3 namespace App;
4
5 use Illuminate\Foundation\Auth\User as Authenticatable;
6
7 class User extends Authenticatable
8 {
9 /**
10 * The attributes that are mass assignable.
11 *
12 * @var array
13 */
14 protected $fillable = [];
15
16 /**
17 * The attributes that should be hidden for arrays.
18 *
19 * @var array
20 */
21 protected $hidden = [
22 'password', 'remember_token',
23 ];
24
25 //...
26 }

Ahí vemos dos propiedades definidas como protected y nuestras relaciones las creamos siempre
como public.
Sabiendo esto podemos entender rápidamente un proyecto hecho por otra persona, “escribir buen
código es al mismo tiempo una escribir una buena documentación”.
Capítulo 10: PHP 142

Ocultación o aislamiento

Principio de ocultación: Toma en cuenta que le llamamos “principio” y aquí es donde quiero hacer
énfasis. Es probable que sobre la ocultación esperes un capítulo entero, lo malo es que te diría lo
mismo que escribí aquí en encapsulamiento.
Según mi experiencia, ambos términos se relacionan y básicamente van de la mano: Podemos decir
que la ocultación es el principio y la encapsulación es la técnica o el cómo se hace.
La definición técnica es: Un objeto debe estar aislado y ser un módulo natural. Esto se cumple
aplicando la protección a las propiedades impidiendo su modificación y básicamente controlar el
acceso. Por eso, luego de leer este principio podemos decir que la técnica o la aplicación es el
encapsulamiento.

Modularidad
Este es un concepto muy sencillo; podemos imaginarlo como un módulo que unido a otros módulos
forman un proyecto. Crear todo un sistema en un index.php no tiene nada que ver con la
modularidad. Ahora pensemos en todas las partes de nuestros sistema, cada pequeña parte (módulo)
independiente ayuda a que nuestro sistema realmente funcione.
Si vemos a Laravel podemos entender que tiene este concepto tan en su esencia que lo usamos y
manejamos sin saber que esto existe. Laravel aplica este principio al pie de la letra.
Siendo más técnicos podemos definir que la modularidad consiste en dividir un sistema en módulos,
donde cada módulo debe ser lo mas independiente posible del resto. La idea es probar por separado
cada módulo y dar garantía de su funcionamiento individual y entre ellos.
Este principio básicamente nos ayuda a tener cada vez piezas de código mas pequeñas y mas
entendibles, digamos por ejemplo: Es mejor atender netamente el módulo de usuarios que es un
archivo de cuarenta (40) líneas de código que todo el proyecto. Esto es capacidad de “descomponer”.
El concepto nos lleva a que también se debe permitir la composición y esto simplemente indica que
cualquier programador pueda crear, completar o resolver problemas con el menor trauma posible.
Con todo esto tenemos un sistema separado y organizado y los beneficios son palpables:

1. Mejor lectura del código.


2. Rápido mantenimiento.
3. Estándar.

La modularidad es un concepto de programación orientada a objetos, ahora cómo aplicamos esto en


PHP. Tomando en cuenta que el único elemento que es posible componer y descomponer es una clase,
pero podemos llevar esto a un nivel superior y pensar que organizar las vistas, controladores, helpers,
entidades y clases propias aplicando patrones de diseño es una forma acertada de implementar la
modularidad.
Capítulo 10: PHP 143

En la explicación de Programación Estructurada y OOP de Código espagueti se ilustró muy bien


este ejemplo. Allí empezamos con un controlador llamado LoginController.php y dentro el método
login().

Logramos sacar adelante la solicitud de iniciar sesión pero luego dividimos en varios métodos a esta
solución login(), validate(), attempt(), failed() y response().
Sin embargo, vimos también la necesidad final de crear a una clase llamada Auth.php y mudamos
todos nuestros métodos allá, teniendo como resultado a LoginController.php con un solo método
llamado login() y a una clase Auth.php con su responsabilidad y organización.
El concepto de modularidad debe ser parte de nuestro día a día, incluso fuera del mundo de la
programación.

Polimorfismo
Este tema podría no ser difícil, vamos a tratarlo con un par de ejemplos bastantes claros para
lograr comprenderlo con éxito. La palabra polimorfismo tiene como definición “varias formas” y
en programación orientada a objetos puede aplicarse de varias maneras.
Con varias formas quiero decir que un método al interactuar con diferentes objetos tendrá diferentes
comportamiento o diferentes resultados.

Ejemplo con clase abstracta

Tenemos una clase madre y algunas clases hijas. La idea es demostrar como cada hija usando el
mismo método de su clase madre obtendrá un resultado diferente.
Básicamente un método podrá tener diferentes resultados, al ser esto posible hablamos de polimor-
fismo.
Vamos a trabajar con los siguientes archivos:

• Base.php: Clase madre.


• Admin.php: Clase hija de Base.
• User.php: Clase hija de Base.
• Guest.php: Clase hija de Base.
• index.php: Desde aquí ejecutaremos nuestro proyecto.

Clase abstracta Base.php


Capítulo 10: PHP 144

1 <?php
2
3 abstract class Base
4 {
5 protected $name = '';
6
7 private function className()
8 {
9 return get_called_class();
10 }
11
12 public function login(){
13 return "Mi nombre es {$this->name}: desde la clase {$this->className()} y me\
14 encuentro iniciando sesion... <br>";
15 }
16 }

Tengo a la propiedad $name y el método login() que aprovecharemos desde las clases hijas. Toma
en cuenta el concepto de “un método, varios resultados”.

Clase hija Admin.php

1 <?php
2
3 class Admin extends Base
4 {
5 public function __construct($name)
6 {
7 $this->name = $name;
8 }
9 }

Solo damos de alta el nombre del administrador a través de un constructor.

Clase hija User.php


Capítulo 10: PHP 145

1 <?php
2
3 class User extends Base
4 {
5 public function __construct($name)
6 {
7 $this->name = $name;
8 }
9 }

Mantenemos la misma estructura lógica que con Admin.php. Ambas dicen claramente que pueden
dar de alta su nombre en la propiedad definida en la clase abstracta.

Clase hija Guest.php

1 <?php
2
3 class Guest extends Base
4 {
5 protected $name = 'Invitado';
6 }

Esta sería la clase usada para permitir el paso a usuarios invitados, toma en cuenta que damos de
alta a un nombre por defecto que en este caso es “Invitado”.
Las tres clases pueden por supuesto usar el método login().
Usemos todo esto en nuestro index.php.

Archivo index.php

1 <?php
2
3 require_once('Base.php');
4
5 require_once('User.php');
6 require_once('Admin.php');
7 require_once('Guest.php');
8
9 $guest = new Guest();
10 echo $guest->login();
11
12 $user = new User('Italo Morales');
13 echo $user->login();
Capítulo 10: PHP 146

14
15 $admin = new Admin('Lynda Morales');
16 echo $admin->login();
17
18 ## Al ejecutar este código tendremos en pantalla el siguiente mensaje. ##
19
20 //Mi nombre es Invitado: desde la clase Guest y me encuentro iniciando sesion...
21 //Mi nombre es Italo Morales: desde la clase User y me encuentro iniciando sesion...
22 //Mi nombre es Lynda Morales: desde la clase Admin y me encuentro iniciando sesion..\
23 .

Y aquí vemos claramente el concepto…

• Cada mensaje me dice el nombre de la clase de donde nos conectamos gracias a get_called_-
class().
• Los mensajes son diferentes.
• Veo en cada mensaje al nombre del usuario conectado.
• Y lo mas importante, en todos los casos uso el método login() y la propiedad $name.

Ejemplo con interfaz

• Una única interfaz.


• Varias clases implementan esta interfaz.
• Cada clase usa y desarrolla como quiera a cada método.

Usar una interfaz, es decir, crearla da como resultado el principio de polimorfismo. Es un recurso
válido a la hora de implementar polimorfismo.
¿Qué es una interfaz?: Es un archivo que tiene dentro métodos públicos y de esa manera la clase que
la implemente se encargará de desarrollar cada método. Sus características son las siguiente:

1. La interfaz solo declara los métodos.


2. Todos los métodos deben ser públicos.
3. Una interfaz no contiene atributo alguno.
4. Los métodos allí definidos de desarrollan en la clase que la implemente.
5. La clase está obligada a usar la estructura definida en la interfaz.
6. Es posible que una clase implemente varias interfaces.
7. Una interfaz no se puede instanciar.

¿Aplica el concepto?: De hecho si, porque cada clase que implemente a una interfaz tendrá dentro
de si los mismos métodos pero no necesariamente el mismo comportamiento ni el mismo resultado.

Interfaz Search.php
Capítulo 10: PHP 147

1 <?php
2
3 interface Search
4 {
5 public function all();
6 }

Tiene lo necesario, un método público y nada mas.

Clase User.php

1 <?php
2
3 class User implements Search
4 {
5 public function all()
6 {
7 return "Obteniendo todos los usuarios... <br>";
8 }
9 }

Tenemos una clase que implementa la interfaz y al hacerlo nos obliga a desarrollar el método all().

Clase Post.php

1 <?php
2
3 class Post implements Search
4 {
5 public function all()
6 {
7 return "Obteniendo todos los posts... <br>";
8 }
9 }

Archivo index.php
Capítulo 10: PHP 148

1 <?php
2
3 require_once('Search.php');
4
5 require_once('User.php');
6 require_once('Post.php');
7
8 $user = new User();
9 echo $user->all();
10
11 $post = new Post();
12 echo $post->all();
13
14 ## Al ejecutar, vemos el siguiente resultado. ##
15
16 //Obteniendo todos los usuarios...
17 //Obteniendo todos los posts...

Cuando hablamos de polimorfismo nos referimos a una capacidad o virtud que tienen los métodos,
donde por ejemplo un mismo método puede tener diferentes comportamientos y dar diferentes
resultados.
El concepto de polimorfismo trata precisamente de que una misma cosa termina comportándose
de diferentes maneras. Aquí hemos visto ejemplos con PHP, toma en cuenta que otros lenguajes
podrían tener diferentes método o maneras de implementación. Es probable que en otros lenguajes
se logre de igual forma o aplicando una jerarquía de clases y nada mas.

Diferencia entre interfaces y clases abstractas

Esto requiere un post entero, pero te puedo adelantar lo siguiente:


En una interfaz definimos métodos sin códigos, en clase abstracta puede definir métodos y
desarrollarlos. Lo interesante es crear una clase abstracta y hacer que esta clase implemente una
interfaz. Una interfaz provee los métodos a implementar y una clase abstracta proporciona en la
mayoría de los casos una funcionalidad base o por defecto.
Es importante dedicarle un poco mas a este tema en particular, los patrones de diseño proporcionan
en estos casos responsabilidades y organización que nos ayuda a entender bien cada rol. Cuando
profundicemos en esta área comprenderás realmente cuando usar cada cosa.

Herencia
Esto es probable que lo hayas escuchado como jerarquía, ese termino también es válido. Podemos
heredar una clase o podemos relacionar objetos. En ambos casos significa herencia y si detallamos
en características observamos lo siguiente:
Capítulo 10: PHP 149

• Clase 1: Tengo 5 métodos.


• Clase 2: Tengo 4 métodos.
• Si la Clase 2 hereda de la Clase 1 podré disponer de 9 métodos.

Básicamente es: Usaré mis métodos más los métodos heredados.


En los ejercicios realizados en los capítulos anteriores vemos cómo heredamos de una clase abstracta.
¿eso es herencia?. La respuesta es SI.
Estudia este capítulo llamado Herencia de clases⁴, encontrarás allí mayor detalle práctico, toma
en cuenta que aquí hablamos del principio de la herencia como principio de desarrollo o de
programación orientada a objetos. Veamos a continuación el ejemplo:

Clase User.php

1 <?php
2
3 class User
4 {
5 public $name;
6
7 public function __construct($name)
8 {
9 $this->name = $name;
10 }
11
12 public function getName()
13 {
14 return $this->name;
15 }
16 }

Esta sería mi clase principal, quiero que Admin.php herede de User.php. Suena lógico cuando
pensamos que los administradores son usuarios también.

Clase Admin.php

⁴https://rimorsoft.com/herencia-de-clases-php
Capítulo 10: PHP 150

1 <?php
2
3 class Admin extends User
4 {
5 //...
6 }

Aquí no desarrollamos ningún método, quiero simplemente usar los métodos desarrollados en
User.php.

Archivo index.php

1 <?php
2
3 require_once('User.php');
4 require_once('Admin.php');
5
6 $admin = new Admin('Italo Morales');
7 echo $admin->getName();
8
9 ## Al ejecutar tenemos el siguiente resultado ##
10 //Italo Morales

Esto es nuestro día a día, en Laravel podemos ver como nuestra entidad User extiende de
Authenticatable y así muchos ejemplos, esto dice claramente que desde la entidad de usuarios
podré usar todos los métodos desarrollados en Authenticatable.
Podemos por supuesto crear la jerarquía necesaria, no hay límites al respecto. Básicamente es posible
crear una escalera de clases sin ningún problema.
También es posible manejar la herencia relacionando objetos, imagina los siguientes casos.

1. Tengo una clase que dentro de sus métodos requiere instanciar otro objeto y usar sus métodos,
esto sería herencia o relación directa.
2. Tengo dos objetos y paso un objeto por parámetro para que a partir de allí pueda usar sus
métodos.

Hay muchas formas de usar métodos o funciones heredadas, en cualquier caso estarías aplicando
este principio de programación orientada a objetos en tus proyectos.
Esto no tiene porque ser complejo. Cuando creas una clase solo debes tener en cuenta que cumplas
con lo siguiente:

1. Herencia: Básicamente usaré mis métodos más los heredados.


Capítulo 10: PHP 151

2. Abstracción: Es aislar, separar y sacar… Si llevamos a un papel alguna solicitud de este tipo
podríamos pensar en lo común y no en el detalle.
3. Polimorfismo: Capacidad o virtud que tienen los métodos, donde por ejemplo un mismo
método puede tener diferentes comportamientos y dar diferentes resultados..
4. Modularidad: Este principio básicamente nos ayuda a tener cada vez piezas de código mas
pequeñas y entendibles, donde cada pieza es un módulo.
5. Encapsulamiento: Un objeto debe estar aislado y ser un módulo natural. Esto se cumple
aplicando la protección a las propiedades impidiendo su modificación y básicamente controlar
el acceso según nuestro criterio.

Cada concepto te ayudará a desarrollarte mejor en este valioso mundo, esto que has estudiado trata
sobre los principios de la programación orientada a objetos y vemos por supuesto ejemplos con PHP.
Es importante recordar lo comentado anteriormente:

• Programación orientada a objetos: Es la técnica o principio de desarrollo.


• PHP: Hace referencia al lenguaje de programación.

El primero te habla sobre su importancia y detalla profesionalmente su uso, y el segundo detalla la


implementación.
En muchos videos y posts aquí en rimorsoft he descrito la estructura de una clase y cómo esta se
puede convertir en un objeto, eso esta bien y nos ayuda a avanzar en gran medida. Aquí tenemos
los conceptos y dominar este tema definitivamente da un plus profesional.
Capítulo 11: SOLID
Bases Sólidas de un Proyecto
Antes que nada quiero agradecerte por leer este capítulo, muchas personas solo quieren aprender a
exportar datos en un archivo PDF o Excel así que te agradezco y te felicito por entrar en este mundo.
Esto es programación de verdad y te va a servir en PHP o en cualquier otro lenguaje.
Cuando estamos comenzando solo importa lo que funciona y lo que nos hace sentir satisfecho. Cosas
como escribir comentarios, código legible y entendible, evitar la duplicidad es algo aparentemente
inútil. Porque la idea es que “funcione”, si funciona entonces está bien y terminé con éxito mi trabajo.
Usar nuestro tiempo en tests, calidad del código parece equivalente a “demorar más”.
“Nos pagan para que el código funcione y está funcionando”, esto es igual a que un albañil rellene
las paredes de tu casa con arena mojada. Las paredes están ahí, se ve bien por fuera y cumple con la
función de un muro de protección. Sin embargo pagaste para que tus paredes sean de concreto, no
pagaste por cofres de plástico rellenos de arena mojada.
¿Se entiende la idea?…
“El cliente pidió el software para ayer por eso lo fabriqué así sin tests ni orden ni buenas prácticas”.
De nuevo parece que lo que importa es entregar sin importar cómo esté ese software por dentro, te
hablo de esto porque quiero que evitarte una mala situación, puedes avanzar así por un buen tiempo
hasta que consigas un cliente buena onda pero con abogados que usará contra ti si sigues con este
tipo de mentalidad.

1. Si el cliente quiere el software para ayer entonces cobro tres mil dólares y no trecientos para
pagar a dos programadores más que me ayuden.
2. Si el cliente no acepta el precio te habrás ahorrado grandes problemas.
3. Si un cliente está muy apurado es mejor decirle NO.
4. El código debe funcionar siempre, no se trata de que lo importante es que funcione.
5. Debes tener cómo objetivo poder mantener el código en el futuro.

El dinero en esta carrera está en el mantenimiento y en las actualizaciones. Un programador fabrica


un software en Enero, lo entrega en Febrero y en Noviembre podría ser algo completamente diferente
a lo entregado hace diez meses. De ahí la siguiente chistosa frase:

Si la depuración es el proceso de eliminar errores, entonces la programación debe ser el


proceso de introducirlos.
Edsger Dijkstra Científico de la Computación Neerlandés.
Capítulo 11: SOLID 153

Un sistema requiere tiempo, mentalízate en ganar de acuerdo al proyecto. Sí dedicas tres meses a un
sistema estamos hablando de miles de dólares. Averigua cuánto gana un programador en tu país, el
promedio es 1800 USD. Esto se gana porque tu empresa vendió un software quizás por 15000 USD y
prometió entregarlo en 60 días, nota que para ti son 3600 USD, en otras palabras el 24% del total.
Es importante ser consiente de ello, probablemente ganes 400 USD y debas analizar que te falta
aprender para subir a esos niveles de sueldo. Todo esto aplica a Latinoamérica porque en Estados
Unidos es otra historia.
De nuevo, un sistema requiere tiempo, no hagas las cosas mal por fabricarlo rápido. Debes construir
un software en el 30% del tiempo prometido y el otro 70% debes estar leyendo, mejorando,
organizando, refactorizando y reparando.
Una nueva función a la vez respaldada por pruebas y por buenas prácticas como SOLID.
Si yo leyera tu código seguro no me entragarías cualquier cosa, por eso es importante introducir en
el proceso los puntos de calidad que recomiento en el libro TDD - Lo que debes saber, pero esta
forma de trabajar es relativamente nueva y ni los clientes ni los jefes inmediatos dominan como se
debe este mundo.
Por eso te enseño todo esto, si mejoramos todos podemos cobrar mas en nuestros paises. Así mi
querido amigo podemos mejorar el mercado.
Piensa que tu Profesor Italo va a leer tu código, eso te ayudará mucho.
La moraleja de todo este relato es que no podemos confiar en nuestra memoria, debemos escribir un
código que meses después nos hable y nos ayude. Ya sea para reutilizarlo o para corregir algo en él
sin trauma alguno.
Las pobres empresas han tenido un programador por siete años y cuando se va nadie mas sabe cómo
mantener o actualizar el software ¡Oh por dios, hay que hacer de nuevo el software porque está
obsoleto! y la verdad del asunto es que se fue el “genio” que apagaba fuegos y vivió así tranquilo por
años.
La perdida es grande, la empresa sufre esto directamente y el nuevo programador también porque
no avanzará como profesional.
¡Todos perdemos!…
En esta sección del libro busco enseñar una estructura y modo de trabajo, a veces no entendemos
las clases de Laravel porque no vemos todo el código en una única clase, verás que pasa después de
aprender todo esto.
¿Has trabajado en un equipo donde cada quien responde por su modulo programado? esto es
una muestra de falta de estandares y buenas prácticas de desarrollo. “Déjame le pregunto al otro
programador para darte una respuesta porque eso lo fabricó él”.
¡FALLA! El código es de todo el equipo.

1. Todos debemos conocer el sistema porque creamos una super documentación. La documenta-
ción debe formar parte de nuestro código, no es algo opcional.
Capítulo 11: SOLID 154

2. Debemos hacer código para que sea leída por humanos mientras programamos para una
computadora.

Any fool can write code that a computer can understand. Good programmers write code
that humans can understand
Cualquier tonto puede escribir código que una computadora pueda entender. Los buenos
programadores escriben código que los humanos pueden entender.
Martin Fowler Ingeniero de Software Británico.

Podemos resumir que el código que hoy escribimos será revisado mil veces (escrito una vez, leído
y modificado varias veces). El código debe poderse leer, esto es la mejor práctica de programación
ya que ahorrará tiempo valioso para las personas del futuro y nosotros podemos quizás ser parte de
ese futuro.

Indicador del Código mal Escrito


Un ejemplo común del código mal escrito es aquel que “funciona” pero no sabemos cómo modifi-
carlo, da miedo tocarlo porque podría estallar. Justo allí escribiste para una maquina y no para un
programador.

Indicadores del Código Legible o Bien Escrito


1. Cada cosa tiene un nombre y valor semántico.
2. Los métodos son pequeños.
3. Cada método tiene una única responsabilidad.
4. No tiene o cuenta con muy poco código anidado.

Todos sabemos que esto es un bonito sueño difícil de conseguir en cualquier ambiente laboral, pero
por ello soy profesor y enseño a esta nueva generación. Todo suena muy bien hasta llegar al lugar de
trabajo porque algo así es escaso o no existe. Te aliento a ti a seguir estos consejos, vamos cambiando
uno a uno y poco a poco. Hagamos el esfuerzo, ayúdame a cambiar esta situación para que mas
temprano que tarde nuestra profesión se valore más.
Capítulo 11: SOLID 155

1 <?php
2
3 namespace Illuminate\Foundation\Auth;
4
5 class Login
6 {
7
8 public function login(Request $request)
9 {
10 $this->validateLogin($request);
11
12 if ( $this->attemptLogin($request) ) {
13 return $this->sendLoginResponse($request);
14 }
15
16 return $this->sendFailedLoginResponse($request);
17 }
18
19 }

¿Qué hace ese método?

1. El método se llama login, “debe ser para iniciar sesión”.


2. Recibe un parámetro que traduce a “solicitud”, ¿la solicitud del login?.
3. Dentro valida los datos recibidos con validateLogin.
4. Luego hace el intento de login porque attempt traduce a intento.
5. Si el intento de login es verdadero entonces quiere decir que si existen los datos.
6. Si falla o no se cumple la condición entonces retornamos una respuesta fallida de login.

Esto es un ejemplo de un gran código legible.

1. Nota que el método es corto.


2. Dedica un método para cada función.
3. Así logramos tener métodos cortos y de responsabilidad única.

La idea es que al leerlo no tenga que revisar cada método por separado para descubrir finalmente
que hace el código. Otro indicador del código mal escrito es que necesita inspeccionar para obtener
mas detalles y descubrir que hace.
¿Quieres ver el mismo ejemplo pero mal escrito? Ok.
Capítulo 11: SOLID 156

Los Comentarios
La documentación de un software nace de los comentarios, las documentaciones están obsoletas
cuando la hacemos por separado, pero si hacemos que se genere con sami por ejemplo siempre
estará actualizada porque se genera a partir de cada comentario.

Malos Comentario

Un mal comentario es aquél que dice lo mismo que el nombre del método o propiedad o es muy
general. Es un tema difícil pero es algo que debemos practicar para desarrollar esta habilidad.

1 <?php
2
3 namespace Illuminate\Foundation\Auth;
4
5 class Login
6 {
7
8 public function login(Request $request)
9 {
10 // valida los datos de login.
11 $this->validateLogin($request);
12
13 if ( $this->attemptLogin($request) ) {
14 return $this->sendLoginResponse($request);
15 }
16
17 // retorno de errores.
18 return $this->sendFailedLoginResponse($request);
19 }
20
21 }

Una vez me perdí un proyecto como consultor porque exigí comentarios en el código, el jefe
de proyectos me dijo “yo pensé que podías resolverlo porque das clase de programación”, y dije
gentilmente que no podía ayudar en el proyecto, muchas gracias y hasta luego.
Los buenos programadores hacen código legible y descriptivo que no necesitan comentarios, pero la
experiencia me dice que todo necesita comentario.
“Ayúdanos, cuando funcione lo programamos mejor y lo comentamos” es algo que hoy día tampoco
creo. Mi papá es carpintero y siempre dejó para después hacer su cocina y closets de la casa, lo mismo
es en los software, si ya funciona lo entregamos y terminamos. Nunca se mejora ni se arregla hasta
que el cliente nos llama para incluir un nuevo modulo o mejorar el actual y gritamos ¡Oh por dios!.
Capítulo 11: SOLID 157

Buenos Comentarios

1 <?php
2
3 namespace Illuminate\Foundation\Auth;
4
5 class Login
6 {
7 /*
8 /----------------------------------------------------
9 / Clase Login para el Inicio de Sesión
10 /----------------------------------------------------
11 / Esta clase maneja la autenticación del sistema y
12 / nos enviará al index sí el login es correcto, sí
13 / falla entonces nos enviará de nuevo a la ventana
14 / de login con los errores encontrados.
15 /
16 */
17
18 /**
19 * Este método maneja la solicitud de inicio de sesión.
20 */
21 public function login(Request $request)
22 {
23 $this->validateLogin($request);
24
25 if ( $this->attemptLogin($request) ) {
26 return $this->sendLoginResponse($request);
27 }
28
29 // Sí el intento de login no es exitoso vamos de
30 // nuevo la ventana de login con los errores.
31 return $this->sendFailedLoginResponse($request);
32 }
33
34 }

Un buen comentario dice exactamente que hace eso que describimos, que recibe, que retorna y nos
proporciona toda la información necesaria para que al leerlo estemos completamente satisfecho.

Nota Importante

Todo a nivel de software es en inglés, el inglés es el idioma de la tecnología, pero usé el


español para ilustrar claramente el objetivo de un comentario. Todo con fines educativos.
Capítulo 11: SOLID 158

La forma correcta sería la siguiente:

1 <?php
2
3 namespace Illuminate\Foundation\Auth;
4
5 class Login
6 {
7 /*
8 /----------------------------------------------------
9 / Login class for Login
10 /----------------------------------------------------
11 / This class handles system authentication and will
12 / send us to the index if the login is correct, yes
13 / fail then send us back to the window login with
14 / errors found
15 /
16 */
17
18 /**
19 * This method handles the login request.
20 */
21 public function login(Request $request)
22 {
23 $this->validateLogin($request);
24
25 if ( $this->attemptLogin($request) ) {
26 return $this->sendLoginResponse($request);
27 }
28
29 // If the login attempt is unsuccessful we
30 // go from new login window with errors
31 return $this->sendFailedLoginResponse($request);
32 }
33
34 }

Conclusión
Debemos de inmediato mejorar nuestras habilidades y conocimientos para ser productivos y
prósperos, por eso comencé este capítulo felicitándote. Nunca es tarde, hoy es el gran día para
empezar y puedes desde ya comenzar tus primeros pasos Senior. Hay miles de artículos sobre las
Capítulo 11: SOLID 159

diferencias de un programador junior y uno senior y lo puedo resumir en productividad. Para mi


ahí está la verdadera diferencia.
Un junior no necesariamente es alguien joven, un junior es alguien que resuelve un problema usando
su estilo y un senior usa un patrón de diseño para llegar al mismo resultado.
Esto pasa porque el junior se preocupa por exportar datos en PDF y el senior invirtió ese tiempo
en aprender sobre el lenguaje y buenas prácticas. No es fácil, ser programador es difícil cuando
hablamos de programación de verdad.
Otra dura verdad, usar paquetes no nos hace programadores. Los programadores podemos leer los
paquetes, mejorarlos, comentarlos o crear uno nuevo manteniendo buenas prácticas de desarrollo
de software.
Se dice que programar es fácil pero yo he pasado días sin salir solo viendo mi pantalla para construir
una solución o reparando un error.
La experiencia se gana haciendo, haciendo a diario.
Esto para mi es emocionante precisamente porque es difícil, de verdad me atrapa y te lo cuento para
principalmente hablarte con la verdad y sientas esta misma emoción que yo.

SOLID

Introducción
En el pasado se podía hablar de programación estructurada y programación orientada a objetos y
esto según yo forma parte del pasado, es necesario hablar de objetos desde el principio.
Podemos hacer un gran sistema sin clases, netamente con programación estructurada y podría
funcionar bien pero nos llenamos de archivos, parámetros, ciclos y muchos condicionales. Esto
realmente funciona y admiro esta capacidad pero el problema está de nuevo en el mantenimiento y
a largo plazo. ¿Cómo escalas? o ¿Cómo haces crecer un sistema así?…
Al trabajar con objetos podemos reutilizar, usar menos código y mantenemos vivo los principios de
la programación.
Estos principios son los que vamos a aprender aquí, vamos a ganar la capacidad de crecimiento
constante, la adaptación sin traumas al cambio, el escribir menos código, legibilidad y lo mas
importante el mantenimiento.

La idea de fabricar un software es que puedas vivir de él sin volverlo a hacer desde cero
cada vez.
Profesor, Italo Morales F.

Uno de los principios de la programación orientada a objetos es el mantenimiento y todo se puede


resumir en los principios SOLID.
Capítulo 11: SOLID 160

Principios
Esto fue creado por Robert Cecil Martin, al que todos conocen como el tío bob, es de Estados Unidos
y yo lo sigo en twitter⁵, para mi es increíble porque él introdujo 5 principios que hoy conocemos como
SOLID que básicamente representa los principios básicos o los fundamentos de la programación
orientada a objetos.

1. S: Principio de responsabilidad única (Single responsibility principle).


2. O: Principio de abierto/cerrado (Open/closed principle).
3. L: Principio de sustitución de Liskov (Liskov substitution principle).
4. I: Principio de segregación de la interfaz (Interface segregation principle).
5. D: Principio de inversión de la dependencia (Dependency inversion principle).

Aclaración

1. No hay que seguir ese orden, solo que el tío bob lo sugirió así para hacer énfasis en que si lo
usas entonces tendremos un código fuerte y solido.
2. Estos principios funcionan en conjunto y no por separado.
3. Todos forman un estilo, todos deben ejecutarse a la par. No se trata de usar el principio de
responsabilidad única y olvidar el principio de abierto/cerrado.
4. Para yo entender esto realmente tuve que enfocarme en el principio de responsabilidad única
y poco a poco fui aceptando al resto.
5. SOLID es un principio de programación no un estilo de PHP, debes usarlo sin importar el
lenguaje que estés usando.

Recuerda, estos conceptos son universales y ten la seguridad de que podrás comunicarte claramente
con otros programadores.
Quiero que dejes de crear todo en los controladores. Siempre recibo fotos del método index de 25
líneas solicitando ayuda, aprendamos poco a poco y pongamos en práctica. Nada de esto está casado
con un lenguaje de programación. Si hoy estás en PHP y mañana en Java podrás seguir hablando
de clases, objetos, SOLID y otros términos.
Sería frustrante que el día de mañana saltemos a Java y perdamos todo lo aprendido.
Necesito que desarrolles criterio, todo esto forma parte de la aclaración y quiero aclararte que debes
pensar, analizar y decidir. Mi experiencia es que cuando aprendí usaba SOLID hasta en las vistas y
esto no debe ser así.
Todo esto es para usarse pero de la mejor manera, haz los ejercicios aquí propuestos, replícalos y poco
a poco los irás dominando. Abusar de esto hará que tu sistema no sea tan legible como queramos.
Muchas gente colabora en Laravel porque se entiende, porque es fácil leer y colaborar. Lo mismo
podría pasar con tus sistemas en el futuro.
⁵https://twitter.com/unclebobmartin
Capítulo 11: SOLID 161

No debes aprender patrones o principios para crear los tuyos. Debes aprenderlos para usarlos. De
esa manera te podrás entender con otros programadores. Si hablas español y te quieres comunicar
con un francés quizás puedes hacerlo en inglés, es el estándar, para comunicarte con él no generas
ni desarrollas un nuevo idioma.
Estos principios y modo de desarrollo son complicados porque debemos aplicarlos según el problema
que estamos enfrentando, no es algo que se descarga como un componente o una librería, ahí
su dificultad. Pero no te preocupes, haré mi mayor esfuerzo para explicarte correctamente cada
concepto y de una forma muy fácil.
Siempre nos llegará el caos, la moraleja de todo esto es que mientras mas limpio esté nuestro código
será mas fácil de lidiar con él.
Y para finalizar esta sección de aclaración te comento lo siguiente, Laravel puede que muera pero
los principios jamás lo harán.

S: Principio de responsabilidad única (Single responsibility


principle)
Tomando en cuenta que el principio se llama SOLID vamos a comenzar con la letra S. Esto quiere
decir lo siguiente: Una clase solo debe tener una única tarea y parece que redunda pero es
importante hacer el debido énfasis.
Esto debe aplicar para todo en cuanto al desarrollo.

1. Una clase llamada Login.php no debe tener nada respecto al registro de usuarios.
2. Un controlador llamado UserController.php no debería tener el código de guardar artículos.
3. Etc…

Este principio dice algo simple pero muy importante, cada elemento de código tiene que tener una
única responsabilidad, nada mas…
Aclaremos un poco más este concepto: Podemos usar la frase “una única función o una única tarea”,
y esto aplica a un todo no nada mas a clases, entendamos esto como un concepto global que aplica
al software no a una estructura, clase, método ni nada especifico.
Si vas a Javascript debes mantener el concepto al crear un componente, si vas a HTML debes tener en
cuenta el concepto para tus estructuras visuales, lo mismo si trabajamos con CSS ya que necesitamos
una hoja de estilo por cada formato aplicado, en PHP lo mantenemos en las clases, los paquetes,
namespace, clase padre, estructura en general, etc.

1. Aprende este principio como estructura de nuestro software.


2. Una clase debe tener una única responsabilidad.
3. Cada responsabilidad es en esencia una función.
4. Para poder extender un sistema debemos tener a las responsabilidades separadas.
Capítulo 11: SOLID 162

5. Un sistema colapsará con facilidad si tenemos varias responsabilidades en las clases.

Una clase con muchas responsabilidades podría hacer que cuando hagas un cambio en
otra clase del sistema esta se vea perjudicada y de error sin saber el porqué exacto.
Profesor, Italo Morales F.

¿No te ha pasado por ejemplo que si corriges un bug esto hace que otra parte del sistema se dañe?,
estos son uno de los síntomas de violar este principio.
Cuando empecé a programar y no conocía este principio podías ver que creaba una clase llamada
User.php y dentro tenía todo respecto a sus datos, registro, login, recordar contraseña, actualización
de perfil y todo respecto a los usuarios.
Otra cosa importante es que si una clase tiene muchas tareas no vamos a recordar que métodos hay
dentro de ella, he tenido clases muy largas, tan largas que he programado dos veces una tarea con
distintos nombres. Este es el tipo de errores que debemos evitar al máximo.
Como el programador pasa mucho mas tiempo leyendo su codigo para mejorarlo o corregirlo nos
conviene usar este principio, es mejor enfrentar un pequeño código que una super clase cada vez.
Querido amigo esto es principalmente lo que hace que nuestro código sea un completo desastre, creo
que ya lo notaste. Por ejemplo un controlador CRUD requiere siete métodos y por no conocer este
principio terminamos creando muchos métodos más.
Te pongo estos ejemplos para que te hagas una idea clara de que se usa en cada parte de tu software,
en cada archivo. Piensa en que este es el principio más importante y debes tenerlo siempre presente.

Cohesión

Esto es un termino técnico pero no es difícil, cuando usamos el principio de responsabilidad única
decimos que tenemos un alto nivel de cohesión. Esto quiere decir que contamos con una alta relación
entre sus funcionalidades manteniendo un enfoque único.
Esto podría traducirse a coherencia, consistencia y congruencia.

1. Si mantenemos una clase con una única tarea y dentro está perfectamente relacionadas sus
funciones entonces tenemos alta cohesión.
2. En otras palabras, la idea es tener una clase con una única responsabilidad y lo mas indepen-
diente del resto como sea posible.

Acoplamiento

En general esto hace referencia a la unión de dos piezas y en un sistema necesitamos que las clases
no se conozcan o se conozcan muy poco, la idea es evitar al máximo la dependencia entre ellos.
Necesitamos entonces un bajo acoplamiento al momento de programar.
Capítulo 11: SOLID 163

Balance Perfecto

1. Alta cohesión: Una única responsabilidad y perfecta relación entre sus funciones.
2. Bajo acoplamiento: Poca o ninguna relación con otros componentes del sistema.

Nota que esto aplica si hablamos de controladores, modelos, clases de un componente, vistas, archivo
css, etc. Esto es un termino de programación que siempre se explica nombrando una clase pero debes
verlo como un todo, es un término que debes siempre tenerlo presente.

Beneficios

¿Qué ganamos realmente?


Cuando hablamos del principio de responsabilidad única debemos apuntar a la alta cohesión y bajo
acoplamiento ganamos leer mejor nuestro código, el poder del mantenimiento, la reusabilidad y por
su puesto la capacidad de implementar pruebas. De hecho, por eso se llaman pruebas unitarias, si
tienes una clase que es independiente podrás probarla de manera independiente.

Qué Debemos Evitar

Debemos evitar la baja cohesión y el alto acoplamiento.


Cuando la cohesión es baja quiere decir que mi componente usa o depende de otro componente para
funcionar. Esto trae como resultado un alto acoplamiento. Recuerda que el acoplamiento significa
unión, si el acoplamiento es alto entonces quiere decir que nuestros componentes están bastantes
relacionados y es el caos.

Breve Reflexión

La cohesión y el acoplamiento es el objetivo de este principio. Cuando desarrollas tienes como meta
real minimizar el costo de mantenimiento para ganar al momento de hacer cambios en el sistema.
Haz dinero fabricando sistemas sencillos de programar y fácil de mantener.
Al comenzar preguntate ¿cual es la responsabilidad real de esta clase, componente, método, etc? Si
respondemos varias entonces estamos violando el principio de responsabilidad única. Evita progra-
mar todo en un solo archivo hasta que “funcione” porque terminará quedandose así ocasionando
como resultado una deuda técnica. Parece que es atajo pero terminarás teniendo como resultado un
desastre como antes y ahora será peor porque es un error a conciencia.
Programar violando este principio da como resultado que quieras renunciar al trabajo porque estarás
muy estresado debido a los requerimientos que no puedes solucionar o que solucionas con miedo
tratando de no dañar otras areas del sistema.

1. Un junior siempre tiene deudas técnicas.


Capítulo 11: SOLID 164

2. Un senior no tiene deudas técnicas.

Ya sabes en que trabajar para ser un programador senior.


“No te preocupes, mañana lo organizo, lo importante es que funcione” es algo que debes dejar de
hacer o no hacer nunca en la vida.
“Los tests me hacen perder tiempo porque es más código” y ya has descubierto que gracias a los tests
evitas las deudas técnicas y además gracias a los tests puedes seguir más fácilmente el principio de
responsabilidad única.
Si queremos ser profesionales y por supuesto contar con un mayor ingreso tenemos que ser realmente
profesionales y programar bien, no solo “funcione” sino que todo programador lo pueda entender y
extender.

Ejemplo

Veamos un ejemplo tomando una clase sencilla de usuarios.

1 <?php
2
3 class User
4 {
5 protected $name;
6
7 public function setName($name)
8 {
9 $this->name = $name;
10
11 return $this->name;
12 }
13 }

Te había comentado que esto aplica a todo, no unicamente a la relación entre clase. Veamos aquí
que tenemos una clase llamada User que tiene un método dedicado a guardar el nombre, parece
que cumplimos con el principio pero no es así, aunque funciona podemos ver que al momento de
guardar estamos retornando, es decir, está haciendo dos tareas.
La clase corregida quedaría de la siguiente manera.
Capítulo 11: SOLID 165

1 <?php
2
3 class User
4 {
5 protected $name;
6
7 public function getName()
8 {
9 return $this->name;
10 }
11
12 public function setName($name)
13 {
14 $this->name = $name;
15 }
16 }

Podemos ver que aplicamos el principio, cada método tiene una única responsabilidad y es
precisamente el objetivo. Cumplimos con lo que he venido enseñando, lo importante no es que
escribas miles de líneas de código sino que se pueda leer fácilmente, que sea coherente, congruente
y que sea fácil de mantener en el futuro.
La cohesión la podemos ver en la parte de que los métodos necesarios están dentro de mi clase, en
otras palabras, la clase se llama User, dentro de ella contamos con guardar el nombre de un usuario
y al mismo tiempo obtenerlo.
El acoplamiento es bajo debido a que para obtener el nombre de un usuario no utilizo otra clase ni
ningún componente adicional.

Estructuras de Control / Condicional

Quiero que revises el código de Laravel y me digas cuantos condicionales consigues, es una bonita
tarea y aquí te contaré porque cuando revisamos proyectos hechos por profesionales no vemos tantos
“IF”. Las estructuras de control son las que siempre usamos para interrumpir o alterar el flujo natural
del sistema:

1. If
2. Else
3. Else if
4. Switch
5. …

Esto es importante explicarlo porque si no lo conocemos terminamos escribiendo programación


estructurada dentro de las clases haciendo métodos exageradamente largos y violamos el principio
de responsabilidad única.
Capítulo 11: SOLID 166

Primero que nada, no se trata de no usarlos, se trata de usar las estructuras de control cuando son
realmente necesarios.
Nota que en el código anterior no hacemos preguntas, solo decimos “guardar nombre” y en el otro
método “obtener el nombre” si usamos por ejemplo una estructura de control estamos permitiendo
que nuestro método, clase o componente haga una cosa u otra o una cosa de varias cosas. Asi que
muy probablemente estaremos quebrantando el principio de responsabilidad única.

Si tiene nombre Entonces


guardo el nombre
Sino
retorno el nombre anterior o mensaje de error

Imagina tener un método dedicado a la notificación y que tenga dentro un IF o cualquier otra
estructura de control que pregunte cada vez el tipo de notificación y que dependiendo del tipo
notifique al usuario vía email, push, slack o lo que sea. Es un método que hace muchas cosas y
justo por eso se usan muy poco cuando programamos con estos principios.
Si dentro de un método de una clase vemos por ejemplo los siguientes ejemplos es porque
definitivamente algo está mal:

1 if ($type == 'video') {
2 //...
3 } elseif ($type == 'post') {
4 //...
5 } elseif ($type == 'default') {
6 //...
7 }

Otro ejemplo podría ser usando switch.

1 switch ($type) {
2 case 'video':
3 //...
4 break;
5 case 'post':
6 //...
7 break;
8 case 'default':
9 //...
10 break;
11 }
Capítulo 11: SOLID 167

Aquí es cuando el cerebro empieza a calentarse porque no conocemos otra forma de hacer las cosas,
esto se ve mucho, por ejemplo.

Si recibo un email Entonces


envío el email y copio al usuario logueado
Sino
solo envío email al usuario logueado

Si tienes algunos métodos con estas estructuras dentro piense en cómo los puedes mejorar, por
ejemplo cada acción de la condicional podría se un método. Nota que este tipo de información no la
consigues en https://php.net, ni en Laravel, simplemente SOLID son consejos para programar mejor,
depende de ti cómo creas el código.
Esto es importante entenderlo porque como te dije hace un segundo, puede ser necesario usar una
condición y esta respuesta te la dará el criterio, el buen criterio que desarrolles estudiando este libro.
Solo ten cuidado de mantener una alta cohesión, un bajo acoplamiento y cero deuda tecnica. Toma
tus decisiones teniendo esto en mente.

O: Principio de abierto/cerrado (Open/closed principle)


Ya aprendimos el principio de responsabilidad única, ahora trabajemos con este segundo principio,
básicamente trata de que las entidades deben estar abiertas para ser extendidas pero deben estar
cerradas para ser modificadas.
Recuerda que el tío bob organizó estos principios, en el pasado por supuesto existían y él mediante
la observación creó ese estupendo nombre de SOLID.
En resumen: Una clase, componente, método, etc debe estar abierta para su extensión pero cerrada
para su modificación.
Esto lo quebrantamos cuando por ejemplo usamos condicionales como en la explicación del principio
anterior, imagina que necesitamos crear otro tipo de notificación y tenemos dentro del método
precisamente una condicional. En este caso de una sentencia switch.

1 switch ($type) {
2 case 'video':
3 //...
4 break;
5 case 'post':
6 //...
7 break;
8 }
Capítulo 11: SOLID 168

Si luego tengo que programar el envío mediante SMS como puedes imaginar necesitamos crear otro
case y ahí es precisamente donde fallamos. Hemos modificado porque nuestro código está “abierto
a modificaciones” y no cerrado como sugiere este principio.

1 switch ($type) {
2 case 'video':
3 //...
4 break;
5 case 'post':
6 //...
7 break;
8 }

Parece que lo correcto es crear el nuevo case, sin embargo el problema es que estamos tocando y
modificando un código que ya funciona y podemos dañarlo mientras creamos la nueva función o
nueva caracteristica.
Esto se te debe hacer muy familiar, ayer el sistema funcionaba y hoy estalló ¿por qué? porque
hoy implementamos la nueva función dentro del código que ya funcionaba. En mis primeros años
cambiaba las cosas con verdadero miedo porque el software ya estaba en producción y era muy
común que llamaran porque “se cayó el sistema”.
¿Italo qué hiciste? “metí este for aquí …” y el sistema estallaba ¡Buuum!.
A veces resolvemos nuestros problemas alterando el código que ya funcionaba pero con el tiempo
te das cuenta que son formas de resolver, la verdad no estás programando como un profesional.
Al igual que con el principio de responsabilidad única, debemos aplicar este con mucho criterio sino
tu código terminará con muchos archivos para una única función o característica.
Este principio te invita a dejar de pasar parametros para tomar deciciones, en lugar de ellos debemos
crear interfaces que son basicamente archivos guias y contratos que no debemos romper.
Las interfaces son muy importante, parece extraño pensar en ello porque nunca las hemos usado
y este principio nos dice que debemos hacerlo, si te has encontrado con esta teoria antes es muy
probable que sientas que esto es un extra para organizar nuestro código. Ningún lenguaje nos obliga
a usarlas es por ello que parecen ser innecesarias o de poco importancia.
Es programación orientada a objetos esto es vital, presta atención para que este concepto forme parte
de ti.

1. Tenemos que pensar en interfaces antes que en clases o implementación.


2. La implementación (nuestro código) debe solo cumplir con la interface.
3. Una interface da mayor legibilidad a nuestro código.
4. Una interface nos ayudará en el futuro a entender nuestro código.
Capítulo 11: SOLID 169

Dicho de otro modo, ¿si no hay interfaces con qué cumplimos?, por ello caemos en la improvisación
y en los largos códigos hasta que funcione.
Si queremos añadir una nueva funcionalidad ya no tendríamos que modificar el nuevo código,
necesitamos crear una clase que cumplirá con la interface y esta se pasará como parametro.
El principio es “Añadir nuevas características o funciones sin dañar el código que ya funciona”.

1 // Antes pasábamos por ejemplo un tipo para tomar una decisión


2 switch ($type) {
3 case 'video':
4 //...
5 break;
6 case 'post':
7 //...
8 break;
9 }

Para cumplir con este principio necesitamos cambiar la forma de pensar y parar de crear código
improvisado.

Mala Práctica

1 <?php
2
3 class Lesson
4 {
5
6 public function display($type)
7 {
8 switch ($type) {
9 case 'video':
10 //...
11 break;
12 case 'post':
13 //...
14 break;
15 }
16 }
17
18 }

Esto es una clase que de acuerdo al tipo va a enviar un mensaje por diferentes canales, si el tipo es
email entonces tomará esa ruta.
Capítulo 11: SOLID 170

Precisamente eso es lo grave, para que sea una buena práctica debes crear una clase Email.php,
Slack.php y así por cada decisión. Siempre que trabajemos así vamos a dañar el código anterior
porque estamos alterando el código que sirve y funciona sin problemas. Esta mal pensar en un
nuevo case de mi switch para agregar una nueva función.

Jamas toques el código que funciona…

Buena Práctica

1. Piensa en lo que quieres resolver.


2. Define una interface común.
3. Crea la interface.
4. Crea el código.

Esto es poderoso y nota como nuestro código está preparado para enfrentar nuevos problemas y
cambios sin mayor trauma. Desarrolla criterio y confía en tu intuición, esto es así porque no hay un
manual exacto al respecto, solo es un principio general que debemos aplicar.
No lo hagas en todo momento, por ejemplo en modelos de Laravel, Controladores y similares no lo
harás, no creemos confusión al respecto. Pero si creas un módulo llamado Lessons para el manejos
de clases en una plataforma si que te será muy útil.

Index.php

1 <?php
2
3 include('Lesson.php');
4
5 include('RenderInterface.php');
6 include('Video.php');
7 include('Post.php');
8
9 $lesson = new Lesson();
10 $video = new Video();
11 $post = new Post();
12
13 $lesson->render($video);
14 $lesson->render($post);

Aquí incluyo la clase de lección, la interface, el video y el post. Con eso veremos que pase lo que
pase nunca tocaré a mi clase lección, esto es muy útil si necesitamos en el futuro crear un tipo de
lección llamado noticias News.php.

Interface RenderInterface.php
Capítulo 11: SOLID 171

1 <?php
2
3 interface RenderInterface
4 {
5
6 public function display();
7
8 }

El super heroe de este principio. Es quien dirá que hacer respecto a mis videos, posts y futuros tipos.
Video.php

1 <?php
2
3 class Video implements RenderInterface
4 {
5
6 public function display()
7 {
8 echo "Lección tipo video <br>";
9 }
10
11 }

Al implementar a la interface nos obliga a usar el método heroe llamado display().


Post.php

1 <?php
2
3 class Post implements RenderInterface
4 {
5
6 public function display()
7 {
8 echo "Lección tipo posts, solo texto <br>";
9 }
10
11 }

Manejamos la misma filosofia que en Video.php, la idea es crear nuevos tipos sin problemas, sin
alterar mi clase Lesson.php.
Lesson.php
Capítulo 11: SOLID 172

1 <?php
2
3 class Lesson
4 {
5
6 public function render(RenderInterface $RenderInterface)
7 {
8 return $RenderInterface->display();
9 }
10
11 }

¡Buuum!, nota como esta clase no recibe ni videos, ni posts ni nada mas. De aquí desparece por
completo el switch y cumplimos con nuestro principio.
Si en el futuro creamos una nueva clase llamada News.php no cambiaremos nada de Lesson.php.

Reflexión Final

Parece que este patrón solo trata de la inyección de dependencia debido a que resolvimos el problema
haciendo una inyección, pero puedes pensar que lo aplicamos cuando quitamos de nuestros métodos
estas estructuras de control condicionales.
La clave dice: Una clase debe estar abierta a extensión pero cerrada para su modificación. Básica-
mente nuestra clase debe poder extenderse pero no debemos permitir la modificación del código.

Exactamente Cómo lo Logramos

Ya vimos un ejemplo pero podemos consultar claramente cómo funciona el polimorfismo y al


aplicarlo también cumplimos con este principio. Las opciones válidas serían:

1. Creando clases abstractas.


2. Creando interfaces.

Y esto lo expliqué en el capítulo de PHP donde toco el tema de la programación orientada a objetos.
Nota que las características de la programación orientada a objetos nos enseña sobre todo sintaxis,
entonces, escribir esa sintaxis siguiendo estos principios nos llevará al siguiente nivel.
Recuerda que lo que buscamos evitar es crear código estructurado dentro de nuestras clases, métodos,
etc.
Usa este principio cuando veas un If o cualquier otro condicional porque crecerá y te dañará el
proyecto en corto tiempo.

1. La lógica estará mejor ordenada y repartida.


Capítulo 11: SOLID 173

2. Las clases se podrán extender (Herencia).


3. Las clases no se modificarán cada vez que necesitemos agregar una función.
4. Busca la clase que modificas con frecuencia y aplica ahí el principio.
5. Si ante un nuevo requisito necesitas modificar una clase existente entonces aplica el principio.

En resumen “No toques el código que ya funciona”. Usa tu criterio y desarrolla experiencia para
tomar la decisión correcta.

L: Principio de sustitución de Liskov (Liskov substitution principle)


Cuando hablamos de programación orientada a objetos sabemos que una de sus caracteristicas es la
herencia, es principio precisamente trata sobre ello. Trata sobre cómo usar correctamente la herencia,
dando un beneficio inmediato para reutilizar mejor nuestro código.
Siempre que aprendemos o nos instroducimos a la programación orientada a objetos conocemos de
inmediato a la herencia, forma parte de las caracteristicas de este paredigma de programación y de
rapidamente lo aprendemos.
El principal objetivo de la herencia es reutilizar el código, donde básicamente dejamos de copiar y
pegar.
Este principio tienes este nombre porque fue introducido por Barbara Liskov en una conferencia,
te había comentado que el tio bob tiene el mérito de ordenar y llamar a todas estas buenas práctica
SOLID, sin embargo son principios que siempre existieron.
Este principio dice:

Cada clase que hereda de otra puede usarse como su padre sin necesidad de conocer las
diferencias entre ellas.

Suena extraño pero vamos a hacerlo sencillo.

1 // Clase Padre
2 class Base
3 {
4
5 function public display();
6
7 }
8
9 // Clase hija
10 class Html extends Base
11 {
12
Capítulo 11: SOLID 174

13 // ...
14
15 }

El principio sugiere que donde sea que estes usando la clase Base deberias poder usar la clase Html
sin dañar, romper o alterar cualquier código. ¿Donde o cuando alteras este principio? Cuando por
ejemplo usamos la herencia y en la clase hija alteramos las salidas o resultados.

Mala Práctica en la Herencia

Veamos el ejemplo de violar este principio.

Index.php

1 <?php
2
3 include('Person.php');
4 include('Guest.php');
5 include('User.php');
6
7 $guest = new Guest();
8 $user = new User();
9
10 $guest->login();
11 $user->login();

Aquí vemos que hay una clase persona, usuario y también invitado. Al parecer quiero iniciar sesión
o hacer login con un usuario invitado.

Clase Padre Person.php

1 <?php
2
3 class Person
4 {
5
6 public function login()
7 {
8 echo "Iniciando sesión de un usuario <br>";
9 }
10
11 }

Clase Hija User.php


Capítulo 11: SOLID 175

1 <?php
2
3 class User extends Person
4 {
5
6 }

Clase Hija Guest.php

1 <?php
2
3 class Guest extends Person
4 {
5
6 public function login()
7 {
8 echo "Este usuario es un invitado, no puede iniciar sesión <br>";
9 }
10
11 }

Esto es en realidad algo muy sencillo, se trata de mucho sentido común, tanto que no lo compren-
demos a la primera. Nota que la clase hija llamada Guest.php sobreescribe el método login(), eso
quiere decir que no podré reemplazar a Person.php a través de Guest.php.
Recuerda: Se trata de poder usar a la clase principal (padre) a través de sus clases “hijas” sin
interrumpir, alterar el resultado o romper el sistema.
Si hacemos una analogía y creamos una clase animal con el método con el método nadar, correr y
volar por ejemplo suena a que es algo lógico, pero cuando crees a las clases hijas perro, águila y pato
habrán problemas:

1. El aguila solo puede volar y correr.


2. El pato puede nadar, correr y volar.
3. Sin embargo el perro solo podría correr.

Esto viola el principio, porque a través de perro no podremos reemplazar a la clase padre animal.
Moraleja: No debemos extender de clases si voy a alterar algunos métodos o si tengo pensado dejar
de usar otro métodos de mi clase padre. Si necesitamos heredar es porque podré hacer absolutamente
todo lo que mi clase padre hace. Es decir, podré reemplazarla en cualquier momento.
Nota que esto te ayudará a dejar de crear esa clases padres que solo servían como repositorios de
métodos, me ha pasado que tengo una clase padre con muchos métodos y extiendo solo para poder
usar algunos de ellos o solo para reemplazar el comportamiento de algunos otros.
Capítulo 11: SOLID 176

La herencia debe usarse con cuidado porque aparentemente simplifica y encapsula todo nuestro
código, la herencia no es la técnica de sobreescribir sus métodos padres o heredados. He visto clases
que al heredar sobreescriben al método solo para agregar un comentario o una excepción. Y es esto
precisamente lo que debe evitarse.
¿Cuando violamos el principio?

1. Cuando extendemos y no usamos.


2. Cuando extendemos y sobreescibimos.
3. Incluir nuevos comportamientos en un método que originalmente no se comporta así.
4. Cuando extendemos pero su clase hija no podría reemplazar a su clase padre.

Todo esto es una forma de resolver. Cuando hacemos este tipo de soluciones violamos al mismo
tiempo el principio de abierto/cerrado porque esta alteración impide que nuestra nueva clase hija
no esté abierta a su extensión. Nota que esto genera una cadena de malas prácticas.
Ambos principios están muy relacionado. Al usar este principio de forma correcta estamos aplicando
implicitamente el principio de abierto/cerrado.

Mala Práctica con Interface

Index.php

1 <?php
2
3 include('DataInterface.php');
4 include('File.php');
5 include('Sql.php');
6
7 $file = new File();
8 $sql = new Sql();
9
10 $file->all();
11 $sql->all();

DataInterface.php
Capítulo 11: SOLID 177

1 <?php
2
3 interface DataInterface
4 {
5
6 public function all();
7
8 }
9 ````
10
11 ##### File.php
12
13 ```php
14 <?php
15
16 class File implements DataInterface
17 {
18
19 public function all()
20 {
21 echo "Listado de todos los archivos en array <br>";
22 }
23
24 }

Sql.php

1 <?php
2
3 class Sql implements DataInterface
4 {
5
6 public function all()
7 {
8 echo "Listado de todos en JSON <br>";
9 }
10
11 }

Resultado
Capítulo 11: SOLID 178

1 Listado de todos los archivos en array


2 Listado de todos en JSON

Aquí hacemos un ejemplo, sin embargo lo que queremos ilustrar es que ambas clases usan el método
all() de nuesta interface, el problema está en que en File.php retorno un Array y en Sql.php
retornamos un Json. Y esto significa que quien consuma estos datos no podrá interactuar de la
misma forma a pesar de usar la misma interface debido a que la salida de datos es diferente. Este
hecho viola este principio.

Resumen

El principio nos lleva a entender que una clase padre será reemplazable por sus clases hijas sin
interrumplir o romper el sistema. Eso nos lleva a entender que una clase hija se va a comportar de
la misma manera que una clase padre.
Si empezamos a trabajar así nuestro codigo comenzará a transmitir olores, esto quiere decir que
presenta sintomas un problema profundo que aún no notamos. No necesariamente tenemos errores
o bugs a la vista, básicamente se trata de malas técnicas que en realidad no impide el correcto
funcionamiento pero esto aumenta el riesgo de errores o fallas graves en el futuro.
Quien programe así podría saberse de memoria cada cosa, cada alteración y en general tener todo
muy claro, pero en realidad es un desastre dificil de entender si viola este principio básico de herencia.
Si necesitas explicar que al extender de cierta clase hija debemos saber que un método se comporta
diferente al comportamiento de su clase padre entonces es un alerta, esto no debe ser así, recuerda
que el código debe explicarse por si mismo.
La herencia es una gran caracteristica pero debe usarse con mucho cuidado. Como dije hace un
segundo a veces usamos a nuestras clases padres en un repositorio o archivo con muchos metodos
sin relacion alguna entre ellos violando incluso el principio de responsabilidad única.
Debemos evitar que una clase sobreescriba a un método de su clase padre, esto hace que el acuerdo
no sea honrado, así que usa a la herencia siempre que sea necesario y con gran criterio y cuando la
uses aplica el Principio de Sustitución de Liskov.

I: Principio de segregación de la interfaz (Interface segregation


principle)
Este principio es un principio realmente simple. Nos invita a crear varias interfaces en lugar de crear
una super interface.

1. Es mejor interfaces específicas que una interface de propósito general.


2. Una clase no se verá forzada a implementar métodos que no tiene que usar.
Capítulo 11: SOLID 179

No debemos crear grandes interfaces que tengan todos los métodos, es muy probable que no los
necesitemos todos. Si tenemos que crear todos estos métodos entonces podríamos crear varias
pequeñas interfaces.
Segregar significa separar o aparta una cosa de otra, significa al mismo tiempo separar o dividir.
Este probablemente sea el principio mas sencillo pero nota como se relaciona automaticamente con
el principio anterior de Liskov.
En otras palabras, si creamos una super interfaz violamos el principio de segregación y es muy
probable que también afecte al principio de Liskov.
Solo piensa en interfaces pequeñas y no en interfaces grandes.
A medida que nuestro sistema crece debemos hacer cambios, y cuando estos cambios implican tocar
a grandes interfaces, vamos a tener que revisar todas las implementaciones y esto hará que el sistema
se dañe en algún otro lado.
Modificar grandes interfaces tendrá un impacto mas global. Sin embargo, si dividimos y creamos
pequeñas interfaces seremos mucho más ágiles a la hora de incorporar cambios y al mismo tiempo
seremos más productivos.
Debemos programar para interfaces y no para implementaciones porque este ultimo nos invita a
improvisar. Recuerda que la interface define el comportamiento de nuestros objetos y es el primer
pensamiento que debemos tener al momento de resolver un problema.
Recuerda lo programado en el ejemplo anterior donde usamos una interface.

1 <?php
2
3 class Lesson
4 {
5
6 public function render(RenderInterface $RenderInterface)
7 {
8 return $RenderInterface->display();
9 }
10
11 }

En este ejemplo tenemos el método render() que espera como parametro un comportamiento exacto.
No importa cómo lo hará, solo espera poder mostrar una lección definida por nuestra interfaz e
implementada por alguna clase que no sabemos cual es.
Usa a las interfaces y sigue el principio de segregación de interfaces. No cometas el error de pensar
que no usar interfaces es un problema menos.
El objetivo final de este principio, es mantener un nivel bajo de acoplamiento, de manera similar
que el principio de responsabilidad única. Una interface muy grande probablemente ayude a violar
el principio de responsabilidad única.
Capítulo 11: SOLID 180

Mala Práctica

Index.php

1 <?php
2
3 include('DataInterface.php');
4 include('File.php');
5 include('Sql.php');
6
7 $file = new File();
8 $sql = new Sql();
9
10 $file->getMd();
11 $sql->getSql();

Interface DataInterface.php

1 <?php
2
3 interface DataInterface
4 {
5
6 public function getMd();
7
8 public function getSql();
9
10 }

Clase File.php

1 <?php
2
3 class File implements DataInterface
4 {
5
6 public function getSql()
7 {
8 //
9 }
10
11 public function getMd()
Capítulo 11: SOLID 181

12 {
13 echo "Listado de todos los archivos MD en un array <br>";
14 }
15
16 }

Clase Sql.php

1 <?php
2
3 class Sql implements DataInterface
4 {
5
6 public function getSql()
7 {
8 echo "Consulta hecha en SQL <br>";
9 }
10
11 public function getMd()
12 {
13 //
14 }
15
16 }

Ahí vemos el concepto claramente definido, las interfaces nos obligan a usar todos sus métodos. Es
por ello que la recomendación es crear interfaces mas pequeñas para poder usar realmente cada uno
de sus métodos y no dejarlos vacío como en mi ejemplo.
A veces se implementan y solo se retorna una excepción, en cualquier caso es una falla grave
implementar interfaces y no usar alguno de sus métodos.
Crea interfaces pequeñas, especificas y concretas.

D: Principio de inversión de la dependencia (Dependency inversion


principle)
Este es el principio que definitivamente nos ayuda a desacoplar completamente a nuestros objetos.
A veces vemos la necesidad de instanciar una clase dentro del método de otra clase y esto los hará
muy dependientes. La idea es que nuestros clases dependan de una abstracción y no de otra clase
concretamente.
Capítulo 11: SOLID 182

La idea es evitar que nuestras clases dependan una de otra porque será mas difícil de modificar. Es
un diseño rígido y esto implica que cualquier cambio que hagamos nos obligará a hacer cambios en
muchas partes de nuestro código.
La consecuencia directa de hacer que nuestras clases tengan dependencia directa de otras clases es
que podemos tener resultados inesperados en otros módulos o partes del código, la consecuencia es
un sistema frágil. Lo que quiere decir que cualquier cosa lo puede romper. Esto hace que digamos
“ese modulo funcionaba bien”.
Con este principio evitamos que sea dificil la reutilización de nuestro código. La reutilización de
código el gran pilar de la programación orientada a objetos pero no conocer estos datos hace que
sepamos crear clases pero no programar.
Un código acoplado o muy dependiente es un indicador claro de un programador junior y el resultado
es código duplicado en todos lados y eso es un gran problema pensando en el mantenimiento futuro
de cualquier módulo.
Usar en varias partes un código porque se ha duplicado nos genera una enorme deuda técnica y es
lo que este principio viene a evitar. Es aquí cuando sugerimos al cliente volver a hacer el software.
He visto muchos clientes perdiendo dos años o mas en un software que nunca pudieron usar porque
para ahorrar costos contrataron universitarios o personas sin suficiente experiencia que programaron
solo para que funcione cierto módulo, luego no saben como avanzar y el cliente contrata otros dos
programadores que vuelven a hacer ese ciclo por dos años mas. Resultado final, un desastre que
nadie quiere reparar y un cliente frustrado porque no logró sacar adelante su proyecto.
En este caso debemos reafirmar el concepto de programar contra las interfaces y no contra
implementaciones. Te puede sonar al concepto del principio Abierto / Cerrado pero quiero que tengas
esta oración como definición clave.

1. O: Principio de abierto/cerrado (Open/closed principle): Úsalo cuando empieces a usar If,


Switch y cualquier sentencia de control.
2. D: Principio de inversión de la dependencia (Dependency inversion principle): Cuando
estemos programando directamente con una clase, en ese caso debemos programar contra una
interface y no contra una clase o implementación.

¿Cuando lo usamos comúnmente? Aunque debemos usarlo siempre que sea necesario, esto lo vemos
en su esencia cuando implementamos el patrón repositorio.
Para recordar:

1. Cada entidad en general o clase debe saber muy poco sobre otras unidades, módulos o clases.
2. Cuando creas un componente debe cada una de sus clases no depender de otros componentes
directamente.
3. El desacoplamiento es el objetivo principal.
Capítulo 11: SOLID 183

Buscamos que nuestro código sea sencillo y limpio y el patrón usado es la inyección de dependencia,
que esto no te confunda.

• Principio de inversión de la dependencia es el principio.


• Inyección de dependencia es el patrón usado para cumplir con este principio.

Espero enseñarte en mi canal en youtube sobre el patrón repositorio para que veas todo al respecto,
para poder cumplir con él hacemos uso del patrón de diseño inyección de dependencia y ahí logramos
evitar que las clases no generen instancias de sus dependencias.

Mala Práctica

Index.php

1 <?php
2
3 include('Lesson.php');
4
5 include('Video.php');
6 include('Post.php');
7
8 $video = new Video();
9 $post = new Post();
10
11 $video->display();
12 $post->display();

Allí vemos que quiero imprimir en pantalla un video y un post, parece que todo anda normal, sobre
todo cuando obtenemos el mismo resultado en el navegador que con la buena práctica.
Lesson.php

1 <?php
2
3 class Lesson
4 {
5
6 public function render($display)
7 {
8 return $display;
9 }
10
11 }

Video.php
Capítulo 11: SOLID 184

1 <?php
2
3 class Video
4 {
5
6 public function display()
7 {
8 $lesson = new Lesson();
9
10 echo $lesson->render("Lección tipo video <br>");
11 }
12
13 }

Ahí está la falla, dentro de display() instanciamos a la clase Lesson y esto genera una dependencia
inmediata, conseguimos que el acoplamiento es alto.

Post.php

1 <?php
2
3 class Post
4 {
5
6 public function display()
7 {
8 $lesson = new Lesson();
9
10 echo $lesson->render("Lección tipo posts, solo texto <br>");
11 }
12
13 }

Y aquí lo mismo, esto es lo realmente grave pensando en el futuro de la aplicación. El problema se


evidencia porque dentro del método display() se crea una instancia de la clase Lesson para hacer
uso se su método render(). Acoplamiento en su maxima expresión y aunque funcione estamos
violando este principio porque obliga que conozcamos con exactitud que hay en Lesson para poder
hacer funcionar nuestro sistema.

Mejora

Index.php
Capítulo 11: SOLID 185

1 <?php
2
3 include('Lesson.php');
4
5 include('Video.php');
6 include('Post.php');
7
8 $video = new Video();
9 $post = new Post();
10
11 $lesson = new Lesson();
12
13 $lesson->renderVideo($video);
14 $lesson->renderPost($post);

Lesson.php

1 <?php
2
3 class Lesson
4 {
5
6 public function renderVideo(Video $video)
7 {
8 return $video->display();
9 }
10
11 public function renderPost(Post $post)
12 {
13 return $post->display();
14 }
15
16 }

Video.php
Capítulo 11: SOLID 186

1 <?php
2
3 class Video
4 {
5
6 public function display()
7 {
8 echo "Lección tipo video <br>";
9 }
10
11 }

Post.php

1 <?php
2
3 class Post
4 {
5
6 public function display()
7 {
8 echo "Lección tipo posts, solo texto <br>";
9 }
10
11 }

Con esto conseguimos eliminar la creación de la instancia dentro de las clases Video y Post, esto es un
buen avance, dicho de otro modo no hemos eliminado la creación de las instancias, solo la movimos
y se hace mediante la inyección de dependencias, básicamente trata de pasar como parametro a una
clase.
Es un ejemplo muy concreto para ver cómo vive este concepto en nuestro código.

Buena Práctica

En este caso podemos ver que en Lesson tenemos dos métodos donde una va destinado a los videos
y el otro a las lecciones, si en el futuro necesito otro tipo de lección entonces además de crear a la
clase en cuestión también tendré que crear un nuevo método en esta clase.

Index.php
Capítulo 11: SOLID 187

1 <?php
2
3 include('Lesson.php');
4
5 include('RenderInterface.php');
6 include('Video.php');
7 include('Post.php');
8
9 $video = new Video();
10 $post = new Post();
11
12 $lesson1 = new Lesson($video);
13 $lesson2 = new Lesson($post);
14
15 $lesson1->render();
16 $lesson2->render();

Lesson.php

1 <?php
2
3 class Lesson
4 {
5
6 protected $lesson;
7
8 public function __construct(RenderInterface $RenderInterface)
9 {
10 $this->lesson = $RenderInterface;
11 }
12
13 public function render()
14 {
15 return $this->lesson->display();
16 }
17
18 }

Esta clase recibe como parametro una interface y es lo ideal, porque esta interface podría ser un
video, un post o en el futuro podría ser cualquier cosa. Así evitamos crear nuevos métodos por cada
nueva función, en teoria no manipuraremos mas el código que ya funciona.

Interface RenderInterface.php
Capítulo 11: SOLID 188

1 <?php
2
3 interface RenderInterface
4 {
5
6 public function display();
7
8 }

Video.php

1 <?php
2
3 class Video implements RenderInterface
4 {
5
6 public function display()
7 {
8 echo "Lección tipo video <br>";
9 }
10
11 }

Post.php

1 <?php
2
3 class Post implements RenderInterface
4 {
5
6 public function display()
7 {
8 echo "Lección tipo posts, solo texto <br>";
9 }
10
11 }

Aplicar este patrón no es nada complicado, siempre que inyectemos clases lo estamos aplicando y
esto se puede hacer mediante el constructor o métodos como parámetros. La más cómoda siempre
será mediante el constructor aunque el efecto es similar, todo depende realmente de lo que quieras
lograr.
Capítulo 11: SOLID 189

1. Inyección mediante el constructor: Toda la clase contará con esta dependencia.


2. Inyección mediante un método: Es dicho método quien podrá usar esta clase inyectada.

Esto es algo que al igual que los principios anteriores, debe aplicarse con mucho criterio. Cuando
empecé en este mundo inyectaba todo y esto a largo plazo también ocasiona problemas porque al
hacerlo violas el resto de principios.
Si notas que necesitas inyectar muchas dependencias probablemente esa ciase esté haciendo
demasiadas cosas y ahí no cumples con el principio de responsabilidad única.

Resumen
Acabamos de aprender cinco principios, quiero que veas que son consejos o herramientas que
podemos usar para crear un código increíble. No debes abusar porque de nada sirve perder el foco
y crear código que no sea legible ni mantenible.
Crea criterio, sé cuidadoso y evita grandes problemas.
Capítulo 12: SOLID en Laravel
SOLID en la Práctica
Aprendimos estas técnicas, consejos o formas de trabajar usando ejemplos sencillo en PHP, dejarlo
hasta ahí no sería correcto y ahora que manejamos la teoría debemos ver cómo usar SOLID en
Laravel directamente, al final es aquí donde vamos a programar nuestros proyectos, apliquemos los
principios SOLID siempre que sea posible.
El principal problema de no aplicarlo es que terminamos teniendo código estructurado dentro de
nuestros controladores y si evolucionamos un poco tendremos a nuestros controladores bastante
limpios y nuestros modelos colapsados. Aprende bien esto, debes aplicarlo y practicarlo porque es la
única forma en que te pueda asegurar que serás un mejor programador, quiero que crees proyectos
de calidad así que ayúdame porque es una meta de ambos.
Repasemos en breves conceptos para que abramos este entendimiento y los conozcamos con mayor
facilidad.

Qué son Exactamente los Principios SOLID


Recuerda que son consejos o conceptos creados por Robert C. Martin, esto ya existía, él los organizó
y los llamó SOLID, los llamó así porque al mismo tiempo emiten un mensaje interesante y es que nos
invita a crear código realmente sólido y de calidad. La verdadera importancia está en crear código
de calidad y no en crear código que simplemente funcional. El objetivo es una alta cohesión y bajo
acoplamiento.
Saber programación orientada a objetos no es suficiente, es necesario saber cómo organizar nuestro
código porque ello nos permite desarrollar sistemas que podamos entender fácilmente eliminando
código espagueti.
Los principios SOLID son netamente principios y no es algo que solo funcione en PHP o Laravel,
con estos capítulos te estoy enseñando en realidad a programar no a usar a Laravel y ya. Otra cosa
en que debes pensar es que no necesariamente debes empezar aplicando la S y luego continuar con
OLID en ese orden. Se llama así porque suena genial y tiene un significado importante que muestra
claramente su objetivo. Yo lo explico en orden simplemente para que la palabra SOLID no se te
olvide.

1. S: Principio de responsabilidad única (Single responsibility principle): Una clase solo debe tener
una única responsabilidad, cuando creamos un Request para validar, un Resource para manejar
los datos de un API, un Middleware para controlar el acceso, etc nota que cada clase se dedicará
a una única cosa. Esto evita que llenemos de mucho código a nuestros pobres controladores.
Capítulo 12: SOLID en Laravel 191

2. O: Principio de abierto/cerrado (Open/closed principle): Esto significa que debemos crear clases
que puedan extenderse pero ante una nueva función no debería modificarse directamente. Lo
logramos pensando bien en nuestras herencias, interfaces y con clases abstractas.
3. L: Principio de sustitución de Liskov (Liskov substitution principle): Este principio nos ayuda a
crear con conciencia a las herencias, básicamente si heredas de una clase hija debes poder usar
los métodos del padre sin mayor problema y manteniendo el mismo comportamiento. En otras
palabras si heredas de una clase no sustituyas sus métodos ni propiedades. Usa interfaces y no
tantas herencias.
4. I: Principio de segregación de la interfaz (Interface segregation principle): Básicamente divide
tus interfaces en pequeñas interfaces para que no cometas el error de implementar una y no
usar todos sus métodos, evita crear super interfaces con muchos métodos.
5. D: Principio de inversión de la dependencia (Dependency inversion principle): Este principio
nos ayuda a lograr el bajo acoplamiento de clases, esto lo logramos inyectando interfaces y
no clases directamente porque una interface podría reemplazar a cualquier clase. En Laravel
lo usamos muchos cuando desarrollamos con el patrón repositorio. La teoría dice que inyectes
abstracciones y no dependencias directamente.

Esto es SOLID, leyendo con detenimiento el capítulo anterior y este resumen entenderemos mucho
mejor todo al respecto. Esto son principios que se aplican en cualquier lenguaje donde usemos la
programación orientada a objetos. No siempre los necesitarás, aprendelos y aplicalos cuando tengas
la oportunidad. Te iluminarás cuando lo hagas porque vas a desarrollar mucha experiencia en el
camino.
Esto realmente vale la pena porque los ejemplo planteados son verdaderos.

1. Seguramente has decidido renunciar a un empleo luego de unos meses porque sabes que el
sistema en cualquier momento se va a romper.
2. Un cliente tiene un sistema que nadie quiere mantener y por ende está perdiendo su dinero.
3. Quizás has propuesto hacer el sistema desde cero debido a que no comprendías el código.

Y así hay muchos casos, puede parecerte complicado aplicar estos principios y la verdad no están
descabellado pensar así, pero trato de explicarte de una forma muy sencilla sin sacrificar grandes
funciones.
Estos principios son bastante obvios y sencillos quizás por eso nos cuesta ponerlos en práctica, por eso
quiero seguir con este proyecto para enseñarte a usar PHP y al mismo tiempo enseñarte a programar.
Programar bien es una tarea muy compleja que requiere práctica para que vayas construyendo buena
experiencia. Para ser un buen profesional necesitas esfuerzo y dedicación.
Piensa en estos principios es que son una serie de consejos que te ayudará a crear código que se
pueda leer y mantener. Aunque al principio veas que antes programabas pocas líneas y ahora son
varios archivos. Antes era una clase y ahora son clases e interfaces.
¿Qué queremos evitar?
Capítulo 12: SOLID en Laravel 192

1. Mezclar responsabilidades
2. Heredad sin importar como sobrescribimos.
3. Programar interfaces enormes duplicando código
4. Complicarnos la vida con el mantenimiento.

Esto tiene un propósito muy claro, el propósito es económico lo que quiere decir que si programamos
bien se ahorrará dinero por parte del cliente y nosotros ganaremos mas porque podemos cobrar por
cada modulo futuro que se programe, ganaremos bien y rápido porque con SOLID tenemos todo
preparado para entender, leer y extender rápidamente.
Si programas mal de tal forma que ya no quieras saber nada de un sistema entonces cuando te llame
el cliente no vas a querer atenderlo, el cliente pierde dinero por perder tiempo o contratando a otro
programador y tu también perderás dinero porque no vas a programar ese nuevo módulo o soporte
que quiere el cliente.

Programar mal hace que todos pierdan.

Programar trata mucho sobre el mantenimiento y si programas mal no vas a querer mantenerlo. El
tiempo es oro, en otras palabras el tiempo vale dinero.

1. Si programas mal, entonces gastarás mas tiempo en mantenimiento y lo que cobres no cubrirá
todos esos días.
2. Si programas bien podrás hacer un rápido mantenimiento y ganarás todo ese dinero en menos
tiempo.

Esto tiene que ir de la mano con la metodología TDD, espero hayas tomado mi libro de TDD en
Laravel porque trabajar con esta metodología nos ayudará en gran medida a desarrollar con los
principios SOLID.
Es probable que ya tengas muy claro los costes verdaderos del mantenimiento, es nuestro deber
tomar consciencia para evitar tirar los sistemas a la basura y empezar de cero cada vez.
Es importante porque casi nunca en nuestra carrera conseguimos proyectos para hacer desde cero,
a menos que trabajemos vendiendo páginas web y solo fabricamos y entregamos. Lo que es muy
común es trabajar en proyectos que ya han arrancado, no siempre borrar y empezar de cero es
la mejor opción, en el 2008 lo propuse y me hicieron caso, fue un tiro en la cabeza debido a que
el sistema era realmente complejo y todos seguiamos sin conocer claramente estos principios, ni
patrones, ni nada. Empezar de cero no siempre es la mejor opción si de verdad no sabes en que te
estás metiendo.
Solo piensa que nuestro día a día es trabajar en código existente, debemos lidiar con sus problemas
y con todas sus deuda técnica.
Hay otra realidad, no debes despreciar proyectos con problemas y solo hacer aquellos que sean
netamente nuevos nuevos. Mostramos verdadero profesionalismo en la batalla, con sistemas malos
Capítulo 12: SOLID en Laravel 193

y desordenados, con usuarios encima y clientes llamando todo el día, en realidad estos son los
proyectos que cuestan mucho dinero porque ya están en producción.
Mira este caso de la vida real, una empresa contrata un comercial en el canal de Youtube Ecuatoriano
de sketch Enchufe TV, cada video que sube este canal supera fácilmente los dos millones de visitas.
El problema con esta empresa era que luego de lanzar el video estaban recibiendo mucho tráfico en
una landing page y adivina qué pasó. ¡Sorpresa!… El formulario de registro no funcionaba.
Desesperados porque el video ya tenía quinientas mil visitas decidieron ofrecerme 3.000 USD sin
yo pedir nada aún, te juro que tenía en mente cobrar 120 USD porque era una amiga y no sabía
con detalle que estaba pasando ni que habían contratado una publicidad en sketch con Enchufe TV.
Decidí revisar, corregir y subir. Lo hice en unos minutos y quedé como un héroe.
Pero no te imaginas, el código era un desastre, tanto que el programador anterior decidió no contestar
mas su teléfono, así estaría de obstinado. Yo solo leí los mensajes de error, no me dediqué a hacer
código bonito ni nada, solo leí, entendí el error y corregí. Pero ahí está otra virtud, saber programar
bien te da un punto de vista que te ayuda a tratar con estos problemas y resolverlos.
La nota importantes es que si somos capaces de demostrar un buen trabajo sabrán que valemos y
nos llamarán mas seguido para nuevos proyectos porque sabemos resolver y nosotros sabemos que
somos buenos programadores.
¿Qué pasó con el sistema donde fallaba el formulario? Fue desarrollado por un programador con
poca experiencia y todo lo estaba haciendo mediante AJAX. El problema con los proyectos que
comenzamos desde cero es que en algún momento dejará de ser desde cero, tendrás mucho código
dificil de mantener y justo ahí vas a querer hacerlo desde cero otra vez.
Los proyectos con problemas en algún momento fueron empezado desde cero y hoy tienen problemas
porque los empezaron sin principios ni ninguna norma.
Si te enfrentas a un horrible sistema solo trabaja para dejarlo mejor que como lo conseguiste, sin
excusas ni quejas, porque podría haber otro programador por allí hablando mal del trabajo que
dejaste y que a él le toca mantener.
Hay código que no se puede testear, al que no se le puede aplicar la metodología TDD porque es un
completo desastre, lo mismo pasa con SOLID, a veces es imposible corregir aplicando los principios,
así que lo que debes hacer es apagar fuegos, corregir algunas cosas, comentar y apenas tengas la
oportunidad corriges un módulo entero con buenas prácticas.
Jamás trates de arreglarlo todo a la vez, jamas, nunca en la vida lo hagas. Solo un poco a la vez.
No se trata de comenzar desde cero, se trata de ayudar a nuestros clientes porque son ellos quienes
tienen el problema y están pagando para ser ayudados.
En nuestra profesión todo lleva tiempo y cualquier cosa puede traer efectos secundarios, sé
profesional y no te dejes guiar por tu cliente cuando te dice que es fácil y que seguramente lo podrás
resolver rápido. Un profesional sabe cómo frenar de la mejor manera a los clientes así.
No se trata de solo solucionar, se trata de tomar en cuenta el tiempo y hacer que funcione con buenas
prácticas.
Capítulo 12: SOLID en Laravel 194

Para finalizar, quiero que comprendas que SOLID son consejos que nos da una guía y buenas
prácticas que no nos garantizan que no vayamos a tener bug pero si nos minimiza mucho tener
problemas. Se trata de principios que son mas viejos que yo y que han sido discutidos y puestos
en prácticas todos estos años. Las tienes que interiorizar y asimilar, son principios universales que
debemos aplicar.
Todos los principios están interrelacionados y si fallas en uno estarás fallando en todos, así que si
aplicas uno estarás de alguna manera dejando mejor el camino para aplicar el resto.
Nadie dijo que esto fuese fácil, pero tengo cómo proposito enseñar a programar y no nada más
a exportar PDF y Excel en Laravel para que en el futuro sean tus paquetes los que ayuden a la
comunidad y no solo seas un usuario de estos paquetes.
Espero que Rimorsoft Online sea un virus que te infecta de programación sin que exista cura ya que
el camino es largo y requiere aprendizaje diario.
Capítulo 13: Ingeniería de Software
Principios SOLID aplicados en Laravel
Hemos aprendido con ejercicios en PHP cómo trabajar con SOLID, la recomendación es usarlo
siempre que sea posible. Esto por supuesto te ayudará como programador porque estarías creando
código de buena calidad y de un mayor nivel de mantenimiento y escalabilidad. Ya aprendimos en
PHP pero cuando del mundo laboral se trata usaremos en realidad a Laravel, así que vamos directo
a ver cómo aplicar cada principio en nuestro gran Framework.

Repaso
Recuerda que son conceptos organizados por Robert C. Martin que nos ayudarán a crear sistemas
de calidad.
La idea es crear proyectos de fácil mantenimiento, sin código espagueti y con mayor alcance
al momento de escalar. Recuerda que estas son técnicas de programación que puedes aplicar en
cualquier lenguaje, no son propios de PHP.

Configuración base
Necesitamos algunos archivos para poder hacer los ejercicios, es importante porque quiero que
copies y pegues y que todo esto te funcione. Necesitamos un modelo, migración, controlador y una
vista para practicar.

Instalemos a Laravel

1 $ laravel new solid

La idea es tener un proyecto en cero para poder entender cada uno de estos maravillosos conceptos
y aprender mejor cómo aplicar SOLID en Laravel.

Creamos un Controlador y Modelo

1 $ php artisan make:controller PostController --model=Post

Con esta línea se crea el controlador y la consola te preguntará si queremos crear al mismo tiempo
un modelo y marcamos si [yes].
En el controlador necesitamos una configuración básica.
Capítulo 13: Ingeniería de Software 196

1 <?php
2
3 namespace App\Http\Controllers;
4
5 use App\Post;
6 use Illuminate\Http\Request;
7
8 class PostController extends Controller
9 {
10 public function store(Request $request)
11 {
12 $request->validate([
13 'title' => 'required',
14 'body' => 'required'
15 ]);
16
17 $post = Post::create([
18 'title' => $request->input('title'),
19 'body' => $request->input('body')
20 ]);
21
22 return response()->json([
23 'id' => $post->id,
24 'title' => $post->title,
25 'body' => $post->body
26 ], 201);
27 }
28 }

Aquí vemos cómo violamos el principio, la idea es optimizarlo.

Migración

Necesitamos una tabla para hacer una práctica real de cada principio.

1 $ php artisan make:migration create_posts_table

Y configuramos cada campo, para el ejemplo usaremos dos campos.


Capítulo 13: Ingeniería de Software 197

1 <?php
2
3 use Illuminate\Database\Migrations\Migration;
4 use Illuminate\Database\Schema\Blueprint;
5 use Illuminate\Support\Facades\Schema;
6
7 class CreatePostsTable extends Migration
8 {
9 //...
10 public function up()
11 {
12 Schema::create('posts', function (Blueprint $table) {
13 $table->bigIncrements('id');
14
15 $table->string('title');
16 $table->string('body');
17
18 $table->timestamps();
19 });
20 }
21
22 //...
23 public function down()
24 {
25 Schema::dropIfExists('posts');
26 }
27 }

Vista

Creamos un formulario en welcome.blade.php para hacer las pruebas desde el navegador.

1 <!DOCTYPE html>
2 <html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
3 <head>
4 <meta charset="utf-8">
5 <meta name="viewport" content="width=device-width, initial-scale=1">
6
7 <title>SOLID en Laravel</title>
8
9 <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.\
10 4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV\
Capítulo 13: Ingeniería de Software 198

11 6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
12 </head>
13 <body>
14 <div class="container">
15 <div class="row">
16 <div class="col-sm-6">
17 <h1>Post</h1>
18
19 @if ($errors->any())
20 <div class="alert alert-danger">
21 @foreach ($errors->all() as $error)
22 - {{ $error }} <br>
23 @endforeach
24 </div>
25 @endif
26
27 <form action="{{ route('posts.store') }}" method="POST">
28 @csrf
29 <div class="form-group">
30 <label>Título *</label>
31 <input
32 type="text"
33 name="title"
34 class="form-control"
35 value="{{ old('title') }}"
36 >
37 </div>
38 <div class="form-group">
39 <label>Contenido *</label>
40 <input
41 type="text"
42 name="body"
43 class="form-control"
44 value="{{ old('body') }}"
45 >
46 </div>
47 <input
48 type="submit"
49 value="Enviar"
50 class="btn btn-sm btn-primary"
51 >
52 </form>
53 </div>
Capítulo 13: Ingeniería de Software 199

54 </div>
55 </div>
56 </body>
57 </html>

Rutas

Finalmente configuramos las rutas, solo necesitamos dos.

1 <?php
2
3 //...
4
5 Route::get('/', function () {
6 return view('welcome');
7 });
8
9 Route::post('posts', 'PostController@store')->name('posts.store');

Y cómo puedes imaginar necesitas hacer la configuración de la base de datos en el archivo .env y
ejecutar el comando $ php artisan migrate.
Con esta base podremos practicar para entender realmente estos valiosos principios, realízalo antes
de continuar, debes poder guardar y validar los datos.

SOLID

S - Principio de responsabilidad única


Una clase solo debe tener una única tarea y parece que redunda pero es importante hacer el debido
énfasis. Seguro te has encontrado con que un pobre método de controlador tiene mas de treinta líneas
de código porque allí está la validación, el formato de datos, condicionales para retornar PDF o vista
blade, etc. Ahí claramente se viola este principio y debemos solventarlo.
En nuestro ejercicio vemos que el método store del controlador esta con mucha carga o muchas
responsabilidades, está validando, guardando cada dato y dando formato para retornar. Aquí
violamos el principio y necesitamos llevar a diferentes clases esta responsabilidad.
Capítulo 13: Ingeniería de Software 200

1 <?php
2
3 namespace App\Http\Controllers;
4
5 use App\Post;
6 use Illuminate\Http\Request;
7
8 class PostController extends Controller
9 {
10 public function store(Request $request)
11 {
12 $request->validate([
13 'title' => 'required',
14 'body' => 'required'
15 ]);
16
17 $post = Post::create([
18 'title' => $request->input('title'),
19 'body' => $request->input('body')
20 ]);
21
22 return response()->json([
23 'id' => $post->id,
24 'title' => $post->title,
25 'body' => $post->body
26 ], 201);
27 }
28 }

Tratemos primero a la validación, para ello creamos una clase form request para llevar allá toda
nuestra validación.

1 $ php artisan make:request PostRequest

Y hacemos la configuración correspondiente.


Capítulo 13: Ingeniería de Software 201

1 <?php
2
3 namespace App\Http\Requests;
4
5 use Illuminate\Foundation\Http\FormRequest;
6
7 class PostRequest extends FormRequest
8 {
9 //...
10 public function authorize()
11 {
12 return true;
13 }
14
15 //...
16 public function rules()
17 {
18 return [
19 'title' => 'required',
20 'body' => 'required'
21 ];
22 }
23 }

Revisa el namespace de cada archivo para que sepas su ubicación. Por ejemplo esta clase
está en app/Http/Requests y se llama PostRequest, esto lo sé porque el namespace dice
AppHttpRequests

Ahora vinculamos esta clase a nuestro controlador para validar de una manera mas optima, solo
invocamos la clase y le damos uso en el método store como parámetro.

1 <?php
2
3 namespace App\Http\Controllers;
4
5 use App\Post;
6 use App\Http\Requests\PostRequest;
7
8 class PostController extends Controller
9 {
10 public function store(PostRequest $request)
11 {
Capítulo 13: Ingeniería de Software 202

12 $post = Post::create([
13 'title' => $request->input('title'),
14 'body' => $request->input('body')
15 ]);
16
17 return response()->json([
18 'id' => $post->id,
19 'title' => $post->title,
20 'body' => $post->body
21 ], 201);
22 }
23 }

Puedes verificar en el navegador y confirmar que todo está funcionando como antes pero aislando
la responsabilidad de validar. Sigamos optimizando.
Vamos a inyectar al modelo Post para guardar de otra manera los datos.

1 <?php
2
3 namespace App\Http\Controllers;
4
5 use App\Post;
6 use App\Http\Requests\PostRequest;
7
8 class PostController extends Controller
9 {
10 public function store(PostRequest $request, Post $post)
11 {
12 $post = $post->create($request->all());
13
14 return response()->json([
15 'id' => $post->id,
16 'title' => $post->title,
17 'body' => $post->body
18 ], 201);
19 }
20 }

Pudimos haber aplicado el patrón repositorio y esto nos ayudaría a aislar la capa de guardar pero
así como está se entiende bastante bien la idea. Ahora veamos cómo trabajar con el retorno de los
datos, aquí el problema es que el formato de datos se está haciendo directamente en el controlador.
Capítulo 13: Ingeniería de Software 203

1 $ php artisan make:resource PostResource

Y configuramos esta clase para dar el formato deseado a nuestros datos.

1 <?php
2
3 namespace App\Http\Resources;
4
5 use Illuminate\Http\Resources\Json\JsonResource;
6
7 class PostResource extends JsonResource
8 {
9 //...
10 public function toArray($request)
11 {
12 return [
13 'id' => $this->id,
14 'title' => $this->title,
15 'body' => $this->body
16 ];
17 }
18 }

Y nuestro controlador solo se dedica a redirigir y controlar que es su verdadera responsabilidad.

1 <?php
2
3 namespace App\Http\Controllers;
4
5 use App\Post;
6 use App\Http\Requests\PostRequest;
7 use App\Http\Resources\PostResource;
8
9 class PostController extends Controller
10 {
11 public function store(PostRequest $request, Post $post)
12 {
13 $post = new PostResource(
14 $post->create($request->all())
15 );
16
17 return response()->json($post, 201);
Capítulo 13: Ingeniería de Software 204

18 }
19 }

Esto puedes organizarlo cómo desees, lo importante es entender que nuestros controladores ya está
liberado y hemos aislado la validación, creación y formato de datos. Otra forma de organizarlo sería
la siguiente:

1 <?php
2
3 namespace App\Http\Controllers;
4
5 use App\Post;
6 use App\Http\Requests\PostRequest;
7 use App\Http\Resources\PostResource;
8
9 class PostController extends Controller
10 {
11 public function store(PostRequest $request, Post $post)
12 {
13 return response()->json(new PostResource(
14 $post->create($request->all())
15 ), 201);
16 }
17 }

Y aquí vemos claramente cómo aplicamos el principio de responsabilidad única, con esto no quiero
crear obsesión, lo importante es saber que esto existe y aplicarlo siempre que sea posible. Analiza y
actúa, siempre que puedas usa estás técnicas.
En este caso recuerda que los métodos de los controladores solo deben recibir solicitudes y dar
respuestas en base a esas solicitudes.

Conclusión

Tenemos en este caso un controlador mucho mas legible y varias clases aisladas dedicadas
únicamente a lo suyo. Todo está separado y se entiende porque todo está en su lugar.
Y lo más importante:

• Es más fácil crear pruebas unitarias.


Capítulo 13: Ingeniería de Software 205

O - Principio de Abierto/Cerrado
La idea es crear el código una vez y no modificarlo si necesitamos agregar nuevas funciones. Esto
debe implementarse cuando tenemos en nuestro código decisiones o condicionales como switch y
básicamente todo lo explicado en el capitulo de SOLID.
En este ejemplo quiero imprimir una plantilla adecuada para videos o para lecciones en texto, esto
es muy común y lo controlamos con un campo adicional en nuestra tabla.

Migración

1 <?php
2
3 use Illuminate\Database\Migrations\Migration;
4 use Illuminate\Database\Schema\Blueprint;
5 use Illuminate\Support\Facades\Schema;
6
7 class CreatePostsTable extends Migration
8 {
9 //...
10 public function up()
11 {
12 Schema::create('posts', function (Blueprint $table) {
13 $table->bigIncrements('id');
14
15 $table->string('title');
16 $table->string('body');
17
18 $table->enum('type', ['video', 'post']);
19
20 $table->timestamps();
21 });
22 }
23
24 //...
25 public function down()
26 {
27 Schema::dropIfExists('posts');
28 }
29 }

Modelo
Capítulo 13: Ingeniería de Software 206

1 <?php
2
3 namespace App;
4
5 use Illuminate\Database\Eloquent\Model;
6
7 class Post extends Model
8 {
9 protected $fillable = ['title', 'body', 'type'];
10 }

Rutas

1 <?php
2
3 //...
4
5 Route::get('/', function () {
6 return view('welcome');
7 });
8
9 Route::post('posts', 'PostController@store')->name('posts.store');
10 Route::get('posts/{post}', 'PostController@show')->name('posts.show');

Vistas

Welcome

1 <!DOCTYPE html>
2 <html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
3 <head>
4 <meta charset="utf-8">
5 <meta name="viewport" content="width=device-width, initial-scale=1">
6
7 <title>SOLID en Laravel</title>
8
9 <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.\
10 4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV\
11 6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
12 </head>
13 <body>
14 <div class="container">
Capítulo 13: Ingeniería de Software 207

15 <div class="row">
16 <div class="col-sm-6">
17 <h1>Post</h1>
18
19 @if ($errors->any())
20 <div class="alert alert-danger">
21 @foreach ($errors->all() as $error)
22 - {{ $error }} <br>
23 @endforeach
24 </div>
25 @endif
26
27 <form action="{{ route('posts.store') }}" method="POST">
28 @csrf
29 <div class="form-group">
30 <label>Título *</label>
31 <input
32 type="text"
33 name="title"
34 class="form-control"
35 value="{{ old('title') }}"
36 >
37 </div>
38 <div class="form-group">
39 <label>Contenido *</label>
40 <input
41 type="text"
42 name="body"
43 class="form-control"
44 value="{{ old('body') }}"
45 >
46 </div>
47 <div class="form-group">
48 <label>Tipo *</label>
49 <input type="radio" name="type" value="video"> Video
50 <input type="radio" name="type" value="post"> Post
51 </div>
52 <input
53 type="submit"
54 value="Enviar"
55 class="btn btn-sm btn-primary"
56 >
57 </form>
Capítulo 13: Ingeniería de Software 208

58 </div>
59 </div>
60 </div>
61 </body>
62 </html>

Video

1 <!DOCTYPE html>
2 <html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
3 <head>
4 <meta charset="utf-8">
5 <meta name="viewport" content="width=device-width, initial-scale=1">
6
7 <title>Video</title>
8
9 <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.\
10 4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV\
11 6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
12 </head>
13 <body>
14 <div class="container">
15 <div class="row">
16 <div class="col-sm-6">
17 <h1>Contenido en Video</h1>
18
19 <h2>{{ $post->title }}</h2>
20
21 <p>........</p>
22 </div>
23 </div>
24 </div>
25 </body>
26 </html>

Post
Capítulo 13: Ingeniería de Software 209

1 <!DOCTYPE html>
2 <html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
3 <head>
4 <meta charset="utf-8">
5 <meta name="viewport" content="width=device-width, initial-scale=1">
6
7 <title>Post</title>
8
9 <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.\
10 4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV\
11 6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
12 </head>
13 <body>
14 <div class="container">
15 <div class="row">
16 <div class="col-sm-6">
17 <h1>Contenido en Texto</h1>
18
19 <h2>{{ $post->title }}</h2>
20
21 <p>........</p>
22 </div>
23 </div>
24 </div>
25 </body>
26 </html>

Son vistas sencillas, básicamente quiero ilustrar cómo imprimir una u otro plantilla dependiendo el
caso. Veamos a nuestro controlador.

Violación del Principio

1 <?php
2
3 namespace App\Http\Controllers;
4
5 use App\Post;
6 use App\Http\Requests\PostRequest;
7 use App\Http\Resources\PostResource;
8
9 class PostController extends Controller
10 {
11 //...
Capítulo 13: Ingeniería de Software 210

12
13 public function show(Post $post)
14 {
15 switch ($post->type) {
16 case 'video':
17 return view('video', compact('post'));
18 break;
19 case 'post':
20 return view('post', compact('post'));
21 break;
22 }
23 }
24 }

Esto funciona, pero nota que tenemos un switch y esto quiere decir que debemos volver cada vez
que tengamos un nuevo formato, si hablamos de lecciones podemos tener en el futuro encuestas,
PDFs, lecciones públicas, etc. Esto nos dice que para nuevas funcionalidades debemos copiar, pegar
y editar el código que ya funciona y esto es lo peligroso.
Así que vamos a optimizar nuestro código creando interface y una clase por cada función.
Necesitamos una clase por cada función o característica. Para que nuestro controlador también esté
dedicado a lo suyo y no tenga que estar tomando decisiones, a pesar de que esto funciona nota que
violamos al mismo tiempo el principio de responsabilidad única.
Necesitamos crear dentro del directorio app.

• Lessons
– Lesson Clase que usaremos para manejar el switch.
– LessonInterface Archivo para mantener un estándar en Post y Video.
– Post Tipo de lección en texto.
– Video Tipo de lección en vídeo.

Como puedes imaginar, si en el futuro creamos otro tipo de lección no tenemos que alterar a
nuestro controlador porque tenemos de forma aislada todo lo relacionado con las lecciones. Vamos
detallando cada archivo y finalmente miremos como queda nuestro controlador.

Modulo Lecciones

Lesson
Capítulo 13: Ingeniería de Software 211

1 <?php
2
3 namespace App\Lessons;
4
5 class Lesson
6 {
7
8 public function render($type)
9 {
10 switch ($type) {
11 case 'video':
12 return new Video();
13 break;
14 case 'post':
15 return new Post();
16 break;
17 }
18 }
19
20 }

Esta será como mi clase encargada de controlar al switch y a partir de allí podremos retornar
cualquier tipo de lecciones, esto es muy útil para controlar tipos de pagos, tipos de reportes, etc.

Interface

1 <?php
2
3 namespace App\Lessons;
4
5 interface LessonInterface
6 {
7
8 public function display($post);
9
10 }

Con esta interface nos aseguramos que cada función se comportará como esperamos, en mi caso me
interesa que tengan obligatoriamente un método llamado display().

Post
Capítulo 13: Ingeniería de Software 212

1 <?php
2
3 namespace App\Lessons;
4
5 class Post implements LessonInterface
6 {
7
8 public function display($post)
9 {
10 return view('post', compact('post'));
11 }
12
13 }

Mi primer tipo de lección donde procesaré lecciones del tipo texto nada mas.

Video

1 <?php
2
3 namespace App\Lessons;
4
5 class Video implements LessonInterface
6 {
7
8 public function display($post)
9 {
10 return view('video', compact('post'));
11 }
12
13 }

Así como creamos estos tipos podremos crear otros tipos de lecciones, es lo interesante porque al
dedicar clases a cada función tendremos la oportunidad de crear mas métodos y así cualquier cosa
necesaria sin necesidad de crear un super controlador para procesar distintos tipos de lecciones.

Controlador
Capítulo 13: Ingeniería de Software 213

1 <?php
2
3 namespace App\Http\Controllers;
4
5 use App\Post;
6 use App\Http\Requests\PostRequest;
7 use App\Http\Resources\PostResource;
8
9 use App\Lessons\Lesson;
10
11 class PostController extends Controller
12 {
13 //...
14
15 public function show(Post $post, Lesson $lesson)
16 {
17 $lesson = $lesson->render($post->type);
18
19 return $lesson->display($post);
20 }
21 }

Con este código conseguimos el principio de abierto para extensión pero cerrado para su modifica-
ción.

Conclusión

Conseguimos que Lesson cree la clase necesaria según el tipo de lección que quiero ver, esto es
interesante porque no es la única técnica, básicamente aprende esto: ¿Estás usando un switch?
Entonces extráelo y haz que cada función sea una clase.
Lo conseguimos usando interfaces bien definida y especifica; ahí obtenemos clases bastante cerradas
a modificaciones y abiertas para extenderla.

• Es importante extender sin manipular el código que ya funciona.


• Separación de toda la lógica ya que son diferentes tipos de funcionalidades.

Y lo más importante:

• Es más fácil crear pruebas unitarias.


Capítulo 13: Ingeniería de Software 214

L - Principio de Sustitución de Liskov


El Principio cita que, cada clase que hereda de otra puede usarse como su padre sin necesidad de
conocer las diferencias entre ellas.
Una de sus caracteristicas principales de la programación orientada a objetos es la herencia, y este
principio nos dice cómo tratar correctamente la herencia, generando el beneficio de reutilización de
código.

Podemos recordar el concepto: El principal objetivo de la herencia es reutilizar el código,


donde básicamente dejamos de copiar y pegar. Este principio tienes este nombre porque
fue introducido por Barbara Liskov en una conferencia, te había comentado que el tio
bob tiene el mérito de ordenar y llamar a todas estas buenas práctica SOLID, sin embargo
son principios que siempre existieron.

Algunos consejos:

1. No sobrescribas métodos al heredar, cuida este principio para no violar este principio.
2. No crees condiciones dentro de los métodos, esto puede evitarse. Al momento de heredar
probablemente debas alterarlo y ahí violas el principio.
3. Puedes crear en la clase base o principal las propiedades para evitar que las clases hijas
reemplacen estos valores, aquí hacemos valido lo aprendido en el capítulo de programación
orientada a objetos.

Este principio no se viola cuando aprendemos bastante bien las teorías de encapsulamiento al mismo
tiempo podemos utilizar interfaces para no romper este principio.
Evitar heredar también es evitar contradecir a nuestras clases padres, recuerda nuestro ejemplo
anterior. Usé una interface para obligar a mis clases de funciones usen el método deseado. Siempre
que puedas trata de estar atado a una clase padre.
Recuerda siempre que esto se usa cada vez que se pueda, no hace falta crear miles de interfaces para
no violar el principio, esto es algo que se debe aprender, analizar y usar cuando debamos usar. El
tiempo te ayudará a desarrollar criterio.

Concepto de Mala Práctica

Hay dos casos muy comunes, veamos un repaso.

1. Si heredas y sobrescribes el método de la clase padre.

Esto es muy común, heredas el método get() por ejemplo pero al heredarlo lo sobrescribes para
agregar condiciones personalizadas.

1. Si usas una interface pero retornas tipos de datos diferentes.

Imagina crear una interface con un método llamado output y que al usarla en una clase hija esta
retorne un string pero al usarla en otra clase esta retorne un array
Capítulo 13: Ingeniería de Software 215

Ejemplo de lo Incorrecto

Clase Padre: Base

Tenemos una clase para que el resto de clases hereden y usen sus métodos. El error está en heredar
y reemplazar.
¿Puedo hacerlo? Si puedes sobrescribir, pero hazlo a conciencia y con criterio.

1 <?php
2
3 namespace App;
4
5 class Base
6 {
7 protected $model;
8
9 public function __construct() {
10 $this->model = $this->getModel();
11 }
12
13 public function pluck()
14 {
15 return $this->model->pluck('name', 'id');
16 }
17 }

Clase Hija: User

1 <?php
2
3 namespace App;
4
5 use App\User;
6
7 class Admin extends Base
8 {
9 public function getModel() {
10 return new User;
11 }
12
13 public function pluck()
14 {
Capítulo 13: Ingeniería de Software 216

15 return $this->model->pluck('username', 'id');


16 }
17 }

Ahí se ve claramente cómo estoy sobrescribiendo el método pluck y es lo que el principio intenta
evitar, recuerda que una clase que hereda de otra, se debe poder usar como el padre sin alterar el
funcionamiento del sistema.
El ejemplo con interface lo ilustré en el capítulo de SOLID en PHP.

I - Principio de segregación de la interfaz


Este principio es sencillo y fácil de usar, yo diría que es el más fácil de entender. Hace referencia a
que una clase que implementa una interface debe usar todos sus métodos y no algunos.
A veces tenemos una super interface con diez (10) métodos pero al implementarla vemos que la clase
solo necesita cuatro (4) de ellas. En este caso deberíamos dividir en pequeñas interfaces a esta super
interface.
Lo que debemos recordar: Es mejor crear varias interfaces en lugar de crear una super interface.

1. Es mejor interfaces específicas que una interface de propósito general.


2. Una clase no se verá forzada a implementar métodos que no tiene que usar.

Interface

1 <?php
2
3 namespace App\Lessons;
4
5 interface LessonInterface
6 {
7
8 public function display($post);
9
10 }

Post
Capítulo 13: Ingeniería de Software 217

1 <?php
2
3 namespace App\Lessons;
4
5 class Post implements LessonInterface
6 {
7
8 public function display($post)
9 {
10 return view('post', compact('post'));
11 }
12
13 }

Aquí cumplimos con el principio, es una interface especifica no una super interface. Si se te presentan
dudas revisa el capítulo de SOLID en PHP porque revisamos sus malas prácticas.
Con esto logramos un código verdaderamente desacoplado dando como resultado facilidad de
refactorizar, legibilidad y mantenimiento.

D - Principio de Inversión de Dependencias


La idea principal de este principio es tener un código de calidad con bajo acoplamiento. El objetivo
es tener a nuestras clases muy independientes .
Este principio invita a implementar a través de interfaces y no clases directamente. Es muy común
ver este bloque de código en nuestro controladores en Laravel.

1 <?php
2
3 namespace App\Http\Controllers;
4
5 use App\Post;
6 //...
7
8 class PostController extends Controller
9 {
10 public function index(Post $post)
11 {
12 $posts = $post->get();
13
14 return response()->json($post);
15 }
16 }
Capítulo 13: Ingeniería de Software 218

Parece que todo está bien porque siempre lo hacemos así, pero hay varios problemas que podemos
evitar aplicando este principio. De hecho se ve claramente en la explicación del capítulo de SOLID
en PHP. Podemos enumerar los problemas.

1. Estamos dependiendo solo de Eloquent.


2. Post se inyecta directamente al método y necesitariamos instanciarlo para hacer un test.
3. Vemos que el método tiene la responsabilidad de crear un objeto.
4. Es difícil volver a utilizar el código porque el acoplamiento es alto, se depende directamente de
otra clase.

Esto lo solucionamos con una interface, es importante inyectar a la interface y no a la clase


directamente. Piensa en que lo importante es implementar a una interface y no a una clase. Esto
es realmente útil cuando nos interesa tener disponible el código de dar formato en JSON y retornar
básicamente cualquier formato.

Controlador

1 <?php
2
3 namespace App\Http\Controllers;
4
5 //...
6
7 use App\Repositories\PostRepositoryInterface;
8
9 class PostController extends Controller
10 {
11 public function index(PostRepositoryInterface $post)
12 {
13 $posts = $post->data();
14
15 return response()->json($posts);
16 }
17
18 //...
19 }

Aquí pasamos como parametro a una interface y no a la clase Post, esto es lo interesante
porque quiero que en este momento mis datos sean administrador por Eloquent, si en el futuro
quisiera tratarlos de otra manera entonces no toco nada en mi controlador, en ese caso creo otra
implementación y es la principal ventaja al momento de trabajar con interfaces, no nos interesa qué
hay detrás, solo sabemos que vamos a retornar a los posts, pero no sabemos cómo.

Rutas
Capítulo 13: Ingeniería de Software 219

1 <?php
2
3 //...
4
5 Route::get('/', function () {
6 return view('welcome');
7 });
8
9 Route::post('posts', 'PostController@store')->name('posts.store');
10 Route::get('posts/{post}', 'PostController@show')->name('posts.show');
11 Route::get('posts', 'PostController@index')->name('posts.index');

Interface

1 <?php
2
3 namespace App\Repositories;
4
5 interface PostRepositoryInterface
6 {
7
8 public function data();
9
10 }

Repositorio

1 <?php
2
3 namespace App\Repositories;
4
5 use App\Post;
6
7 class PostRepository implements PostRepositoryInterface
8 {
9
10 public function data()
11 {
12 return Post::get();
13 }
14
15 }
Capítulo 13: Ingeniería de Software 220

La idea es que mi clase implemente a la interface para tener libertades al momento de obtener mis
datos. En este caso es con Eloquent, pero podría ser desde un JSON, SQL o cualquier formato.
Falta decirle a Laravel que al usar a PostRepositoryInterface este debe instanciar a PostRepository.
Aún no lo sabe y si ejecuto mi sistema este dará error “Target [AppRepositoriesPostRepositoryIn-
terface] is not instantiable.”, esto resulta porque no podemos instanciar a una interfaciar.
Vamos a decirle exactamente eso a Laravel “cuando uses la interface en realidad debes instanciar al
repositorio”.

1 <?php
2
3 namespace App\Providers;
4
5 use Illuminate\Support\ServiceProvider;
6
7 use App\Repositories\PostRepositoryInterface;
8 use App\Repositories\PostRepository;
9
10 class AppServiceProvider extends ServiceProvider
11 {
12 //....
13 public function register()
14 {
15 $this->app->bind(PostRepositoryInterface::class, PostRepository::class);
16 }
17
18 //...
19 }

Esto se llama enlace o “bind”, hacemos este enlace porque nuestra clase depende de una interface.
En register() del AppServiceProvider usamos a bind() donde el primer parámetro es la interface
y el segundo parámetro es la clase concreta que queremos utilizar.
La idea es que si quisiera manejar mis datos con SQL directamente yo crearía SQLRepository o
quizás PostSQLRepository. En ese caso solo creo el código necesario y cambio aquí el enlace. Al
hacerlo mi controlador ni se enterará de que pasó y eso está bien, es la idea. Al implementar una
interface conseguimos este resultado.
Si implementamos directamente la clase necesitaríamos ir al controlador a adaptar nuestro código
para que funcione con SQL.
Capítulo 13: Ingeniería de Software 221

Controlador Final
Hemos visto por partes el código, aquí te mostraré el archivo completo. La idea es apreciar cómo
debe quedar siempre, poco código y dedicado a realizar su trabajo y nada mas.

1 <?php
2
3 namespace App\Http\Controllers;
4
5 use App\Post;
6 use App\Http\Requests\PostRequest;
7 use App\Http\Resources\PostResource;
8
9 use App\Repositories\PostRepositoryInterface;
10
11 use App\Lessons\Lesson;
12
13 class PostController extends Controller
14 {
15 public function index(PostRepositoryInterface $post)
16 {
17 $posts = $post->data();
18
19 return response()->json($posts);
20 }
21
22 public function store(PostRequest $request, Post $post)
23 {
24 return response()->json(new PostResource(
25 $post->create($request->all())
26 ), 201);
27 }
28
29 public function show(Post $post, Lesson $lesson)
30 {
31 $lesson = $lesson->render($post->type);
32
33 return $lesson->display($post);
34 }
35 }
Capítulo 13: Ingeniería de Software 222

Reflexión
No nos obsesionemos con este tema, apliquemos estos principios siempre que sea necesario o cuando
lo consideres. La experiencia te dirá qué hacer en cada caso. Laravel es un gran frameworks y no
cumple al 100% con SOLID, así debemos programar nosotros. Con criterio aplicando cada cosa para
no paralizarnos.
Capítulo 14: Arquitectura
LaravelEngineer debe ser la mejor experiencia de aprendizaje de Laravel, por ello incluyo este
capítulo, por ello escucho a mis lectores y agrego lo que ellos necesitas o consideran interesante.
Este capítulo existe porque creo muy útil saber cómo está construido este gran Framework.

Fachada
Esta es la respuesta a la pregunta ¿cómo tener un código sencillo y bonito? y ¿cómo al mismo tiempo
trabajamos buenas prácticas de desarrollo?
Es dificil pensar en todo ello y garantizar escribir código y pruebas para tener código de calidad.
Esto se resuelve usando las fachadas “clases fachadas” porque son precisamente un patron de diseño
llamado Facade.

Facade: Es una clase que representa a un subsistema entero.

1 Route::get('/', function () {
2 return view('welcome');
3 });

Eso es una fachada, a través de Route accedemos a un inmenso mundo de rutas. Una fachada es
un enlace, un acceso directo a un sistema mucho mas grande o como dice la teoría “una clase que
representa a un subsistema entero”.
En este caso Route es la clase y get() es el método que nos interesa tratar.
Si seguimos con el ejemplo de las rutas podemos revisar y entender mejor cómo funciona este sistema
de fachadas. Al entenderlo podemos crear nuestros propios subsistemas en Laravel y accederlos
tranquilamente como una fachada. En config/app.php tenemos la sección de alias.
Capítulo 14: Arquitectura 224

1 <?php
2
3 return [
4
5 //..
6
7 /*
8 |--------------------------------------------------------------------------
9 | Class Aliases
10 |--------------------------------------------------------------------------
11 |
12 | This array of class aliases will be registered when this application
13 | is started. However, feel free to register as many as you wish as
14 | the aliases are "lazy" loaded so they don't hinder performance.
15 |
16 */
17
18 'aliases' => [
19
20 //...
21 'Route' => Illuminate\Support\Facades\Route::class,
22 //...
23
24 ],
25
26 ];

Ahí vemos que Route es en realidad el acceso directo a Illuminate\Support\Facades\Route y si


vamos a esta clase vemos con claridad que la misma es una representación de un gran sistema que
se encuentra en otra carpeta llamada Illuminate\Routing, la clase donde está get(), post(), etc es
vendor/laravel/framework/src/Illuminate/Routing/Router.php.

Esto nos ayuda a entender su flexibilidad y modo de trabajo.


Entendamos que Laravel está hecho de muchos componentes propios y de terceros, por ello incluso
dona dinero a Symfony y a otros proyectos open source. Verlo así nos ayuda a entender cómo cada
componente al final forman un gran proyecto llamado Laravel. Con este concepto quiero explicar la
robustez del código porque cada componente es responsable de su propia funcionalidad y esto sigue
el concepto de responsabilidad única.
Piensa en un componente que funciona bien dentro de Laravel y fuera de él. Lograrlo nos lleva
al siguiente nivel como programadores y es algo que te enseñaré en el proyecto educativo de
componentes.
Notas Finales
Feedback
Puedes enviarme cualquier feedback que tengas sobre el contenido de esta obra o lo que quieras
enviar, recuerda que mi email es [email protected].
También puedes usar mis redes sociales personales, en todas soy italomoralesf, leo todo lo que me
escriben y respondo a mis alumnos siempre.
Me voy a esforzar para responder a todos y a tiempo.
Haz tu importante aporte.
¡Espero tus mensajes!…
– Profesor, Italo Morales F.
Actualizaciones del Libro
La idea es continuar mejorando y por supuesto cada vez ir construyendo mejor código, ejemplos y
mejores conceptos, voy a ir agregando ejercicios para ayudarte a crecer aún más en este tema. Las
próximas actualizaciones las tendrás en tu email y todo será completamente gratis.
Todos nuestros productos tendrán la filosofía de un solo pago y muchas actualizaciones. Vamos a
mejorar siempre y vamos a ayudar a muchas personas a través de estos textos, ejercicios y videos
en el canal de Youtube.
Siempre se puede mejorar. No lo olvides.
– Profesor, Italo Morales F.
Contactos
Puedes ponerte en contacto conmigo para ayudarte en lo que respecta al mundo del desarrollo
web. Incluso si quieres publicar tutoriales o participar de alguna manera en Rimorsoft Online,
solo escríbeme y lo coordinamos.
Nuestro canal: https://youtube.com/rimorsoft

Rimorsoft Online
1. Nuestra Web: https://rimorsoft.com
2. Instagram: https://instagram.com/rimorsoft
3. Twitter: https://twitter.com/rimorsoft
4. Facebook: https://facebook.com/rimorsoft
5. Github: https://github.com/rimorsoft
6. Chat SLACK: https://rimorsoft.slack.com

Profesor Italo Morales F.


1. Instagram: https://instagram.com/italomoralesf
2. Twitter: https://twitter.com/italomoralesf
3. Github: https://github.com/italomoralesf
4. Facebook: https://facebook.com/ProfesorItaloMoralesF
Guía de Futuros Pasos
Una pregunta ¿cuál debería ser mi siguiente paso?.

Esta es parte de una obra mucho más extensa. No tienes que preocuparte porque tengo grandes planes
para ti. Seguiré escribiendo otros cursos sobre PHP, Laravel, Javascript y tecnologías relacionadas.
Voy a agregar correcciones y actualizaciones para lograr nuestra meta que es formar a un millón de
programadores en Latinoamérica.
Siempre recibirás un email al momento de actualizar este material. ¡Tan sencillo como eso!.
Mi plan: (pronto muy pronto)

1. TDD (ya disponible https://rimorsoft.com/curso/tdd-en-laravel).


2. Patrones de Diseño (planificado).
3. Laravel Avanzado (LaravelEngineer forma parte de este plan).
4. Javascript aquí https://rimorsoft.com/serie/aprende-javascript
5. …y mucho más.

Puedes hacerme sugerencias vía email, hazme saber qué deseas aprender en un futuro cercado.
Gracias una vez más.
Sinceramente,
– Profesor, Italo Morales F.
Italo Morales F
Profesor Italo Morales F. CEO & Founder de Rimorsoft Online, la voz de los videos que estudias en
el canal de Youtube y el creador de cada texto educativo que te ayuda desde https://rimorsoft.com.
Mediante este proyecto educativo estamos ayudando a muchas personas, sigo adelante porque en mi
email hay muchos mensajes de agradecimientos y muchos mensajes de aliento y motivación para
continuar siempre adelante a pesar de todo.

Me gusta ayudar y considero como mi mayor placer ver a las personas crecer, formar sus
empresas o escalar velozmente como empleados.

– Profesor, Italo Morales F.


Mensaje Final
Con esta página finalizamos…
Sé que sabrás hacerlo bien, creo en ti y no dudo de que conseguirás dominar está tecnología, da el
gran paso con Laravel, sigue estudiando, lo vas a lograr.
Si leiste cada página como lo sugerí al principio entonces te sugiero actualizar tu hoja de vida y
colocar allí que dominas a Laravel, consigue un trabajo y escríbeme diciendo que lo has logrado.
¡Que sigas estando bien!.
– Profesor, Italo Morales F.

También podría gustarte