Laravelengineer v1.3 Rimorsoft
Laravelengineer v1.3 Rimorsoft
É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.
Sobre Nosotros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . i
Al Estudiante . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ii
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
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
Store . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96
Validar al guardar un post . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104
Show . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107
Update . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113
Delete . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116
Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119
Usuarios Invitados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124
Feedback . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
Contactos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
Rimorsoft Online . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
Profesor Italo Morales F. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
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.
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 });
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.
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.
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.
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.
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.
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.
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.
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?:
Instalación de Laravel
Podemos usar composer directamente o instalar un software llamado “instalador de Laravel”.
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"
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.
1 if (App::environment('local')) {
2 // Hacer algo en un entorno local
3 }
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.
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.
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:
Y para permitir solo algunas conexiones debemos especificarlas como una sola IP o un grupo de IPs.
Tenemos el siguiente ejemplo:
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.
Instalación
1 $ laravel new crud
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 //...
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
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.
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> </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
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.
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
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.
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.
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
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.
Routes
Básicas
1 Route::get('prueba', function () {
2 return 'Hola';
3 });
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
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.
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
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 ]);
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
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 }
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
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.
Setup
1 $ laravel new formrequest
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>
Controlador
1 $ php artisan make:controller PostController
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 }
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 @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
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:
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>
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
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>
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>
1 <p>
2 Contenido por defecto
3 </p>
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
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.
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
1 @php
2 // No lo hagas :)
3 @endphp
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 }
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
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 }
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.
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 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 }
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').
1 @if (count($errors))
2 <div class="alert alert-danger">
3 <button type="button" class="close" data-dismiss="alert">
4 <span>×</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
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>
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
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 }
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>
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 }
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:
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:
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.
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.
Después de ejecutar el comando necesitas instalar las dependencias y compilar los archivos
necesarios usando npm.
1 $ npm install
Todo en uno
Laravel es increíblemente, también puedes instalar todo de una vez si así lo requieres.
Los pasos necesarios para tener todo funcionando son los siguientes:
1. Instalar laravel/ui.
Capítulo 5: Componente de Login y Registro 58
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.
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.
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.
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 });
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.
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: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 });
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.
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 }
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.
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 });
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.
• 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 }
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 });
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 }
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.
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 }
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 }
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 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.
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 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 });
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
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.
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 }
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:
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.
Un comando que uso a menudo es migrate:refresh, este revierte todas las migraciones (hace
rollback) y ejecuta inmediatamente el comando migrate.
Existe también el comando migrate:fresh, omite el rollback y simplemente elimina todas las tablas
y después ejecuta el comando migrate:
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:
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();
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');
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
Selects
Siempre ha sido un problema obtener todo un registro cuando solo necesitamos algunas columnas.
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. >=.
2. <>.
3. like.
1 $posts = DB::table('posts')->where([
2 ['active', 1],
3 ['view', '>', '1000'],
4 ])->get();
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();
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
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.
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.
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.
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.
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:
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. 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
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
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 ];
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.
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 }
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 }
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
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
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)
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 }
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
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
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 <?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.
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)
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
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 <?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 }
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
17
18 FAILURES!
19 Tests: 1, Assertions: 1, Failures: 1.
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 }
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
Básicamente quiero la estructura que Laravel provee para un listado paginado de datos.
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
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 }
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.
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)
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
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.
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;.
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.
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');
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.
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.
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 }
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.
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 }
1 <?php
2
3 namespace App;
4
5 class Cached extends Lock
6 {
7 public function acquire()
8 {
9 //...
10 }
11 }
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
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?
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:
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.
¿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
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:
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.
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:
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”.
1 <?php
2
3 class Admin extends Base
4 {
5 public function __construct($name)
6 {
7 $this->name = $name;
8 }
9 }
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.
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 .
• 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.
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:
¿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 }
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.
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 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:
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:
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.
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.
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 }
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
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
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.
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.
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.
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.
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
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.
Ejemplo
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.
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. …
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.
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 }
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 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.
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.
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”.
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.
Buena Práctica
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 }
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.
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.
En resumen “No toques el código que ya funciona”. Usa tu criterio y desarrolla experiencia para
tomar la decisión correcta.
Cada clase que hereda de otra puede usarse como su padre sin necesidad de conocer las
diferencias entre ellas.
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.
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.
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 }
1 <?php
2
3 class User extends Person
4 {
5
6 }
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:
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?
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.
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
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.
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.
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.
¿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.
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 }
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
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.
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 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
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.
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 }
Migración
Necesitamos una tabla para hacer una práctica real de cada principio.
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
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
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
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
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
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 }
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:
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.
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.
Y lo más importante:
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.
Esto es muy común, heredas el método get() por ejemplo pero al heredarlo lo sobrescribes para
agregar condiciones personalizadas.
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
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 }
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
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.
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.
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.
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.
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 ];
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
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)
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.