UNIDAD-1

 Requisitos previos (lo esencial)

Para instalar y ejecutar Laravel en Windows, necesitas estos 4 componentes:

Herramienta

Versión mínima

¿Para qué sirve?

PHP

8.2 o superior

Lenguaje base de Laravel

Composer

Última estable

Gestiona las dependencias de PHP (obligatorio)

Servidor web + BD

MySQL / MariaDB

Para ejecutar PHP y almacenar datos. La opción más fácil es XAMPP (incluye Apache, PHP y MySQL)

Editor de código

Cualquiera (VS Code, PHPStorm)

Para escribir tu código

Opcional pero recomendado: Node.js y NPM si vas a trabajar con frontend (CSS, JavaScript, Vite).

🚀 Paso a paso para instalar Laravel

1. Instalar XAMPP (PHP + servidor web + MySQL)

  • Descarga XAMPP desde su sitio oficial.

  • Durante la instalación, asegúrate de seleccionar PHP, Apache y MySQL.

  • Al terminar, abre el panel de control de XAMPP y inicia los servicios de Apache y MySQL.

2. Instalar Composer

  • Descarga el instalador Composer-Setup.exe desde getcomposer.org.

  • Cuando te pregunte por la ubicación de php.exe, selecciona la carpeta donde XAMPP instaló PHP. Normalmente es:
    C:\xampp\php\php.exe

3. Instalar Laravel usando Composer

Abre una terminal (CMD, PowerShell o Git Bash) y ejecuta:

bash

composer global require laravel/installer

Importante: Después de este comando, el instalador te mostrará una carpeta donde se guardó el ejecutable de Laravel (ej: %USERPROFILE%\AppData\Roaming\Composer\vendor\bin).
Agrega esa ruta a la variable de entorno PATH de Windows para poder usar el comando laravel desde cualquier lugar.

4. Crear tu primer proyecto Laravel

Ubícate en la carpeta donde quieres crear el proyecto (ejemplo: C:\mis-proyectos):

bash

cd C:\mis-proyectos

laravel new mi-primer-sitio

Esto creará una carpeta llamada mi-primer-sitio con todo el Laravel ya instalado.

💻 Cómo ejecutar tu proyecto

  1. Entra a la carpeta del proyecto:

  2. bash

  3. cd mi-primer-sitio

  4. Inicia el servidor de desarrollo de Laravel:

  5. bash

  6. php artisan serve

  7. Abre tu navegador y ve a: http://localhost:8000

¡Listo! Ya tienes Laravel funcionando en Windows.

⚠️ Nota importante sobre versiones

  • Si usas XAMPP, ten en cuenta que las versiones más recientes pueden incluir una versión antigua de PHP. Verifica que tu XAMPP tenga PHP 8.2 o superior.

  • Si tu XAMPP tiene una versión más vieja, puedes:

    • Instalar PHP manualmente por separado, o

    • Usar Laragon (alternativa más moderna y recomendada para Laravel en Windows).

🔧 Alternativa recomendada: Laragon

Si quieres algo más sencillo, puedes usar Laragon, que ya incluye PHP, Composer, MySQL, Apache/NGINX y está especialmente optimizado para Laravel. Solo lo instalas y ya puedes crear proyectos con laravel new.

CONVENCIÓN DE NOMBRES

Te explico las convenciones de nomenclatura en Laravel con énfasis en la estructura Verbo + Sustantivo:

estructura para controladores:

📝 Controladores - Estructura Correcta

Nombres de Clases (Controladores)

  • Caso: PascalCase

  • Estructura: Sujeto/Objeto (Sustantivo) + Controller

  • Sufijo: Controller

  • Número: Sustantivo en Plural (representa la colección que maneja)

✅ Ejemplos Correctos:

php

// Controlador para manejar usuarios (colección de usuarios)

class UsersController extends Controller {}  // Sujeto: Users


// Controlador para manejar productos (colección de productos)  

class ProductsController extends Controller {} // Sujeto: Products


// Controlador para categorías de productos

class ProductCategoriesController extends Controller {} // Sujeto: ProductCategories

❌ Ejemplos Incorrectos:

php

class UserController extends Controller {}     // ❌ Debe ser plural: UsersController

class ManageUsersController extends Controller {} // ❌ No sigue estructura Sustantivo + Controller

class user_controller extends Controller {}    // ❌ Caso incorrecto

🔧 Métodos - Estructura Correcta

Métodos RESTful Estándar:

php

class ProductsController extends Controller

{

    // SUJETO: Products | VERBO: index (listar)

    public function index() {}    // GET /products

    

    // SUJETO: Product | VERBO: create (mostrar formulario creación)

    public function create() {}   // GET /products/create

    

    // SUJETO: Product | VERBO: store (almacenar)

    public function store() {}    // POST /products

    

    // SUJETO: Product | VERBO: show (mostrar)

    public function show() {}     // GET /products/{id}

    

    // SUJETO: Product | VERBO: edit (mostrar formulario edición)

    public function edit() {}     // GET /products/{id}/edit

    

    // SUJETO: Product | VERBO: update (actualizar)

    public function update() {}   // PUT/PATCH /products/{id}

    

    // SUJETO: Product | VERBO: destroy (eliminar)

    public function destroy() {}  // DELETE /products/{id}

}

Métodos Personalizados:

php

class UsersController extends Controller

{

    // SUJETO: User | VERBO: activate (activar)

    public function activate() {}      // PUT /users/{id}/activate

    

    // SUJETO: User | VERBO: suspend (suspender)  

    public function suspend() {}       // PUT /users/{id}/suspend

    

    // SUJETO: UserProfile | VERBO: update (actualizar)

    public function updateProfile() {} // PUT /users/{id}/profile

    

    // SUJETO: UserPassword | VERBO: change (cambiar)

    public function changePassword() {} // PUT /users/{id}/password

}

🎯 Estructura Generalizada

Para Controladores:

text

[SUSTANTIVO_PLURAL] + Controller

  • Sustantivo: Representa el recurso/entidad que se manipula

  • Plural: Indica que maneja una colección del recurso

  • Controller: Identifica el tipo de clase

Para Métodos:

text

[VERBO] + [SUSTANTIVO_OPCIONAL]()

  • Verbo: La acción a realizar (index, create, store, show, edit, update, destroy)

  • Sustantivo: Opcional, para especificar sub-recursos (profile, password, settings)

🗃️ Modelos

Nombres de Modelos

  • Caso: PascalCase

  • Estructura: Sustantivo en Singular

  • Ejemplos:

    • User (Modelo para usuario) ✅

    • Product (Modelo para producto) ✅

    • Category (Modelo para categoría) ✅

php

// VERBO: Definir | SUSTANTIVO: Modelo de Usuario

class User extends Model

{

    // VERBO: Obtener | SUSTANTIVO: Posts del usuario

    public function getUsersPosts() {}

    

    // VERBO: Calcular | SUSTANTIVO: Edad del usuario

    public function calculateUserAge() {}

}



📊 Variables

Variables y Propiedades

  • Caso: camelCase

  • Estructura: Sustantivo descriptivo (a veces con adjetivo)

  • Ejemplos:

php

// ✅ Variables con sustantivos descriptivos

$userName = 'John';          // Nombre de usuario

$productList = [];           // Lista de productos

$totalAmount = 100;          // Monto total

$isActiveUser = true;        // Usuario activo

$hasValidSubscription = false; // Tiene suscripción válida


// ✅ Colecciones (sustantivo en plural)

$activeUsers = User::where('active', true)->get(); // Usuarios activos

$productCategories = Category::all();              // Categorías de productos


📋 Resumen Completo de Reglas

Elemento

Caso

Estructura

Singular/Plural

Ejemplo

Controladores

PascalCase

Sustantivo + Controller

Plural

UsersController

Métodos REST

camelCase

Verbo

-

store(), update()

Métodos Personalizados

camelCase

Verbo + Sustantivo

-

calculateTotal()

Modelos

PascalCase

Sustantivo

Singular

User, Product

Variables

camelCase

Sustantivo

Depende contexto

$userName, $products

Tablas BD

snake_case

Sustantivo

Plural

users, product_categories

Columnas BD

snake_case

Sustantivo

-

created_at, price

🎯 Ejemplos Prácticos Completos

Controlador con Métodos Personalizados

php

class OrderController extends Controller

{

    // ✅ VERBO + SUSTANTIVO: Calcular total de orden

    public function calculateOrderTotal($orderId)

    {

        $order = Order::find($orderId);

        $total = $order->calculateTotal();

        return response()->json(['total' => $total]);

    }

    

    // ✅ VERBO + SUSTANTIVO: Aplicar descuento a orden

    public function applyOrderDiscount($orderId, $discount)

    {

        $order = Order::find($orderId);

        $order->applyDiscount($discount);

        return response()->json(['success' => true]);

    }

    

    // ✅ VERBO + SUSTANTIVO: Generar factura de orden

    public function generateOrderInvoice($orderId)

    {

        $invoice = Order::generateInvoice($orderId);

        return response()->download($invoice);

    }

}

Modelo con Métodos

php

class User extends Model

{

    // ✅ VERBO + SUSTANTIVO: Verificar contraseña de usuario

    public function verifyUserPassword($password)

    {

        return Hash::check($password, $this->password);

    }

    

    // ✅ VERBO + SUSTANTIVO: Actualizar perfil de usuario

    public function updateUserProfile($data)

    {

        $this->update($data);

        return $this;

    }

    

    // ✅ VERBO + SUSTANTIVO: Calcular edad de usuario

    public function calculateUserAge()

    {

        return now()->diffInYears($this->birthdate);

    }

}

🔄 Rutas con Convenciones

php

// Rutas RESTful automáticas

Route::resource('products', ProductController::class);


// Rutas personalizadas con nombres VERBO + SUSTANTIVO

Route::post('products/{id}/activate', [ProductController::class, 'activateProduct'])

     ->name('products.activate'); // activateProduct = VERBO + SUSTANTIVO


Route::get('users/{id}/reports', [UserController::class, 'generateUserReport'])

     ->name('users.generateReport'); // generateUserReport = VERBO + SUSTANTIVO

Esta estructura Verbo + Sustantivo hace que el código sea:

  • Más legible: Se entiende inmediatamente qué acción realiza cada método

  • Más mantenible: Nombres consistentes y predecibles

  • Más intuitivo: Sigue el flujo natural de lenguaje (acción + objeto

resumen

Modelo: User (singular)        → Instancia individual

Tabla: users (plural)          → Colección de instancias  

Controlador: UsersController   → Maneja la colección

Métodos: index(), show(), etc. → Operaciones sobre la colección

Esta estructura sigue el principio de que el controlador maneja colecciones de recursos, por eso el sustantivo va en plural, mientras que los métodos operan sobre elementos individuales o la colección completa.


 Rutas en Laravel: Explicación y Ejemplos

Las rutas en Laravel son el mecanismo que permite definir cómo responde tu aplicación a las solicitudes HTTP entrantes. Todas las rutas de Laravel se definen en los archivos dentro del directorio routes/.

Tipos básicos de rutas

1. Rutas básicas

php

Route::get('/saludo', function () {

    return '¡Hola Mundo!';

});

Cuando se visita /saludo en el navegador, se mostrará "¡Hola Mundo!".

1.1 Devolver un arreglo directamente (JSON automático)

Laravel convierte automáticamente a JSON cualquier array o colección que devuelvas desde una ruta o controlador.

Route::get('/tareas', function () {

    $tareas = [

        ['id' => 1, 'nombre' => 'Comprar pan'],

        ['id' => 2, 'nombre' => 'Estudiar Laravel'],

        ['id' => 3, 'nombre' => 'Hacer ejercicio'],

    ];


    return $tareas; // Laravel lo convierte a JSON automáticamente

});

Al visitar /tareas verás en el navegador (o en tu cliente HTTP) algo como:

json

[

    {"id":1,"nombre":"Comprar pan"},

    {"id":2,"nombre":"Estudiar Laravel"},

    {"id":3,"nombre":"Hacer ejercicio"}

]

2. Rutas con parámetros

php

Route::get('/usuario/{id}', function ($id) {

    return 'Usuario '.$id;

});

Esta ruta capturará el ID de la URL y lo pasará a la función.

3. Rutas con parámetros opcionales

php

Route::get('/post/{titulo?}', function ($titulo = 'Título por defecto') {

    return $titulo;

});

El parámetro titulo es opcional y tiene un valor por defecto.

4. Rutas con restricciones

php

Route::get('/user/{id}', function ($id) {

    // Solo se ejecutará si {id} es numérico

})->where('id', '[0-9]+');

5. Rutas con nombre

php

Route::get('/perfil', function () {

    // ...

})->name('perfil');

Puedes generar URLs a esta ruta usando route('perfil').

6-Rutas hacia controladores

php

Route::get('/productos', 'ProductoController@index');

Esto dirigirá las solicitudes GET a /productos al método index de ProductoController.

6.1. Rutas hacia vistas: Route::view()

Laravel tiene un método específico para esto que es muy legible:

php

Route::view('/productos', 'productos.index');

¿Qué hace?
Cuando visites /productos, Laravel cargará directamente la vista que se encuentra en resources/views/productos/index.blade.php.

¿Y si quiero pasar datos estáticos a la vista?
El tercer parámetro de Route::view() acepta un arreglo de datos:

php

Route::view('/productos', 'productos.index', [

    'titulo' => 'Lista de Productos',

    'categoria' => 'Electrónicos'

]);

Luego en tu vista index.blade.php puedes usar {{ $titulo }} y {{ $categoria }}.


7-Grupos de rutas

php

Route::prefix('admin')->group(function () {

    Route::get('/usuarios', function () {

        // Ruta: /admin/usuarios

    });

    

    Route::get('/config', function () {

        // Ruta: /admin/config

    });

});

Tabla de comandos comunes de rutas

Comando

Explicación

Route::get($uri, $callback)

Define una ruta que responde a solicitudes GET

Route::post($uri, $callback)

Define una ruta que responde a solicitudes POST

Route::put($uri, $callback)

Define una ruta que responde a solicitudes PUT

Route::patch($uri, $callback)

Define una ruta que responde a solicitudes PATCH

Route::delete($uri, $callback)

Define una ruta que responde a solicitudes DELETE

Route::any($uri, $callback)

Responde a cualquier método HTTP

Route::match(['get', 'post'], $uri, $callback)

Responde solo a los métodos especificados

Route::redirect($from, $to)

Redirige una URI a otra

Route::view($uri, $view)

Devuelve una vista sin necesidad de controlador

Route::resource($name, $controller)

Genera todas las rutas RESTful para un recurso

->name($name)

Asigna un nombre a la ruta

->middleware($middleware)

Aplica middleware a la ruta

->where($param, $regex)

Aplica restricciones a los parámetros de ruta

Route::prefix($prefix)->group()

Agrupa rutas con un prefijo común

Route::namespace($namespace)->group()

Agrupa rutas bajo un namespace específico

Las rutas son fundamentales en Laravel y ofrecen muchas más posibilidades como middleware, binding de modelos, subdominios, etc. Esta es solo una introducción básica.


1. Rutas individuales (manualmente)

php

use App\Http\Controllers\TaskController;

use Illuminate\Support\Facades\Route;


Route::get('/tasks', [TaskController::class, 'index'])->name('tasks.index');

Route::get('/tasks/create', [TaskController::class, 'create'])->name('tasks.create');

Route::post('/tasks', [TaskController::class, 'store'])->name('tasks.store');

Route::get('/tasks/{task}', [TaskController::class, 'show'])->name('tasks.show');

Route::get('/tasks/{task}/edit', [TaskController::class, 'edit'])->name('tasks.edit');

Route::put('/tasks/{task}', [TaskController::class, 'update'])->name('tasks.update');

Route::delete('/tasks/{task}', [TaskController::class, 'destroy'])->name('tasks.destroy');


2. Rutas agrupadas con resource (recomendado)

Laravel permite generar todas las rutas CRUD automáticamente con Route::resource:

php

use App\Http\Controllers\TaskController;

use Illuminate\Support\Facades\Route;


Route::resource('tasks', TaskController::class);

Esto crea las mismas rutas que el método anterior, pero en una sola línea.

Rutas generadas por Route::resource:

Método HTTP

Ruta

Controlador

Nombre de ruta

GET

/tasks

index()

tasks.index

GET

/tasks/create

create()

tasks.create

POST

/tasks

store()

tasks.store

GET

/tasks/{task}

show()

tasks.show

GET

/tasks/{task}/edit

edit()

tasks.edit

PUT/PATCH

/tasks/{task}

update()

tasks.update

DELETE

/tasks/{task}

destroy()

tasks.destroy


3. Rutas apiResource (para APIs)

Si estás construyendo una API, usa apiResource para excluir las rutas de vistas como create y edit:

php

Route::apiResource('tasks', TaskController::class);


¿Dónde colocar estas rutas?

  • Rutas web: En routes/web.php (para aplicaciones con vistas).

  • Rutas API: En routes/api.php (si es una API RESTful).

Si usas Laravel 9+, asegúrate de importar el controlador:

php

use App\Http\Controllers\TaskController;

Consejo adicional

Si quieres ver todas las rutas definidas en tu proyecto, ejecuta:

bash

php artisan route:list


Esto mostrará una tabla con todas las rutas, métodos y controladores 

asociados.

Tips Importantes

  1. Redirecciones:

  2. php

return redirect()->route('tasks.index'); // Redirige a la lista de tareas

  1. return redirect()->back(); // Redirige a la página anterior

  2. Mensajes de sesión:

  3. php

  4. return redirect()->route('tasks.index')->with('success', 'Tarea creada!');

Comando route:list en Laravel

El comando route:list es una herramienta muy útil que muestra una tabla con todas las rutas registradas en tu aplicación Laravel, incluyendo sus métodos HTTP, URIs, nombres (si los tienen), acciones y middlewares aplicados.

Ejemplo de uso

Para ver la lista de rutas, ejecuta en tu terminal:

bash

php artisan route:list

Esto mostrará una salida similar a:

+--------+----------+-------------------+------+---------+--------------+

| Method | URI      | Name              | Action | Middleware |

+--------+----------+-------------------+------+---------+--------------+

| GET    | /        |                   | Closure | web      |

| GET    | saludo   |                   | Closure | web      |

| GET    | usuario/{id} |                | Closure | web      |

| GET    | perfil   | perfil            | Closure | web      |

| GET    | productos |                   | ProductoController@index | web |

+--------+----------+-------------------+------+---------+--------------+

Opciones útiles del comando

Puedes usar varias opciones para filtrar o formatear la salida:

bash

# Mostrar solo rutas con nombre

php artisan route:list --name=perfil


# Mostrar rutas que coincidan con un URI específico

php artisan route:list --path=usuario


# Mostrar en formato JSON

php artisan route:list --json


# Mostrar más detalles (incluyendo middlewares)

php artisan route:list -v

Tabla actualizada con el comando route:list

Comando

Explicación

php artisan route:list

Muestra una tabla con todas las rutas registradas, sus métodos, URIs, nombres y acciones

Route::get($uri, $callback)

Define una ruta que responde a solicitudes GET

Route::post($uri, $callback)

Define una ruta que responde a solicitudes POST

Route::put($uri, $callback)

Define una ruta que responde a solicitudes PUT

Route::patch($uri, $callback)

Define una ruta que responde a solicitudes PATCH

Route::delete($uri, $callback)

Define una ruta que responde a solicitudes DELETE

Route::any($uri, $callback)

Responde a cualquier método HTTP

Route::match(['get', 'post'], $uri, $callback)

Responde solo a los métodos especificados

Route::redirect($from, $to)

Redirige una URI a otra

Route::view($uri, $view)

Devuelve una vista sin necesidad de controlador

Route::resource($name, $controller)

Genera todas las rutas RESTful para un recurso

->name($name)

Asigna un nombre a la ruta

->middleware($middleware)

Aplica middleware a la ruta

->where($param, $regex)

Aplica restricciones a los parámetros de ruta

Route::prefix($prefix)->group()

Agrupa rutas con un prefijo común

Route::namespace($namespace)->group()

Agrupa rutas bajo un namespace específico

El comando route:list es especialmente útil para:

  • Depurar problemas de rutas

  • Verificar que todas las rutas estén correctamente definidas

  • Comprobar los middlewares aplicados a cada ruta

  • Identificar conflictos entre rutas

  • Documentar tu API o sistema de rutas

VISTAS

  • @extends : La vista hija dice "yo voy a usar un layout padre"

  • @section : Define un bloque de contenido (como un hueco o sección)

  • @yield : En el layout padre, muestra el contenido que la vista hija ponga en esa sección

  • @show : Muestra la sección (similar a @yield pero usada en el layout)

Con @show (tu código original):

blade

@section('sidebar')

    Este es mi master sidebar.

@show

Resultado si la hija NO define 'sidebar': Muestra "Este es mi master sidebar."

Sin @show (usando @yield):

blade

@yield('sidebar')

Tu ejemplo (layout padre)

blade

<!-- resources/views/layouts/master.blade.php -->

<html>

    <head>

        <title>@yield('title', 'Título por defecto')</title>

    </head>

    <body>

        @section('sidebar')

            Este es mi master sidebar.

        @show


        <div class="container">

            @yield('content')

        </div>

    </body>

</html>

Ejemplo aún más pequeño (3 líneas)

Layout padre (layout.blade.php):

blade

<html>

    <body>

        @yield('contenido')

    </body>

</html>

Vista hija (home.blade.php):

blade

@extends('layout')


@section('contenido')

    <h1>Hola Mundo!</h1>

@endsection

Resultado final:

html

<html>

    <body>

        <h1>Hola Mundo!</h1>

    </body>

</html>


1. Layout padre – layouts/app.blade.php (sin cambios)

blade

<html>

    <head>

        <title>Mi App - @yield('title')</title>

    </head>

    <body>

        <nav>Menú principal</nav>

        @section('sidebar')

            <aside>Sidebar por defecto</aside>

        @show 

        <main>

            @yield('content')

        </main>

        <footer>© 2026</footer>

    </body>

</html>


2. Vista hija – tareas/index.blade.php (ahora sin @php)

blade

@extends('layouts.app')


@section('title', 'Lista de tareas')


@section('sidebar')

    <aside>

        <h3>Filtros</h3>

        <ul>

            <li>Pendientes</li>

            <li>Completadas</li>

        </ul>

    </aside>

@endsection


@section('content')

    <h1>Lista de tareas</h1>

    <ul>

        @foreach ($tareas as $tarea)

            <li>{{ $tarea['nombre'] }} (ID: {{ $tarea['id'] }})</li>

        @endforeach

    </ul>

@endsection

Nota: Ahora la vista espera que la variable $tareas exista en el entorno de renderizado.


3. Resultado final renderizado (idéntico al anterior)

html

<html>

    <head>

        <title>Mi App - Lista de tareas</title>

    </head>

    <body>

        <nav>Menú principal</nav>

        

        <aside>

            <h3>Filtros</h3>

            <ul>

                <li>Pendientes</li>

                <li>Completadas</li>

            </ul>

        </aside>


        <main>

            <h1>Lista de tareas</h1>

            <ul>

                <li>Comprar pan (ID: 1)</li>

                <li>Estudiar Laravel (ID: 2)</li>

                <li>Hacer ejercicio (ID: 3)</li>

            </ul>

        </main>

        

        <footer>© 2026</footer>

    </body>

</html>


4. ¿Cómo pasar el arreglo desde la ruta?

Puedes hacerlo de dos maneras comunes:

Opción A – Usando un closure en routes/web.php

php

use Illuminate\Support\Facades\Route;


Route::get('/tareas', function () {

    $tareas = [

        ['id' => 1, 'nombre' => 'Comprar pan'],

        ['id' => 2, 'nombre' => 'Estudiar Laravel'],

        ['id' => 3, 'nombre' => 'Hacer ejercicio'],

    ];


    return view('tareas.index', compact('tareas'));

});

Opción B – Usando un controlador

Primero, crea el controlador (ej. TareaController) con un método index:

php

namespace App\Http\Controllers;


use Illuminate\Http\Request;


class TareaController extends Controller

{

    public function index()

    {

        $tareas = [

            ['id' => 1, 'nombre' => 'Comprar pan'],

            ['id' => 2, 'nombre' => 'Estudiar Laravel'],

            ['id' => 3, 'nombre' => 'Hacer ejercicio'],

        ];


        return view('tareas.index', compact('tareas'));

    }

}

Luego, en routes/web.php:

php

use App\Http\Controllers\TareaController;

Route::get('/tareas', [TareaController::class, 'index']);


5. Diferencia clave (repaso)

Directiva

Uso en el layout

@yield('sidebar')

Muestra únicamente el contenido que la vista hija defina en @section('sidebar'). Si la hija no lo define, no muestra nada.

@section('sidebar') ... @show

Define un contenido por defecto que se mostrará a menos que la vista hija lo sobrescriba con su propio @section('sidebar').

En nuestro ejemplo, usamos @section ... @show en el layout, y la vista hija lo sobrescribe con su propio sidebar de filtros. Si no lo sobrescribiera, veríamos el texto "Sidebar por defecto".

6. Ejemplo adicional: pasar el arreglo directamente desde la ruta sin variable intermedia (solo por curiosidad)

También puedes pasar los datos usando view() con un arreglo asociativo en el segundo parámetro:

php

Route::get('/tareas', function () {

    return view('tareas.index', [

        'tareas' => [

            ['id' => 1, 'nombre' => 'Comprar pan'],

            ['id' => 2, 'nombre' => 'Estudiar Laravel'],

            ['id' => 3, 'nombre' => 'Hacer ejercicio'],

        ]

    ]);});

El resultado en la vista será el mismo, porque $tareas estará disponible.


PASAR VARIABLES DE RUTA A LA VISTA

En Laravel, puedes pasar variables y arreglos de la ruta a la vista de varias maneras:

1. Usando with() encadenado

php

Route::get('/usuario/{id}', function ($id) {

    $nombre = "Juan";

    $datos = ['email' => 'juan@email.com', 'edad' => 30];

    

    return view('perfil')->with('id', $id)

                         ->with('nombre', $nombre)

                         ->with('datos', $datos);

});

1. Usando with() - Pasando el arreglo completo

php

Route::get('/usuario/{id}', function ($id) {

    // Creas un arreglo con todos los datos

    $datosUsuario = [

        'id' => $id,

        'nombre' => 'Juan',

        'email' => 'juan@email.com',

        'edad' => 30,

        'direccion' => 'Calle Principal 123'

    ];

    

    return view('perfil')->with('usuario', $datosUsuario);

});


2. Usando arreglo asociativo en segundo parámetro

php

Route::get('/usuario/{id}', function ($id) {

    $nombre = "Juan";

    $datos = ['email' => 'juan@email.com', 'edad' => 30];

    

    return view('perfil', [

        'id' => $id,

        'nombre' => $nombre,

        'datos' => $datos

    ]);

});

2. Usando arreglo asociativo - Pasando el arreglo completo

php

Route::get('/usuario/{id}', function ($id) {

    $usuario = [

        'id' => $id,

        'nombre' => 'Juan',

        'email' => 'juan@email.com',

        'edad' => 30

    ];

    

    return view('perfil', ['usuario' => $usuario]);

});

3. Usando compact()

php

Route::get('/usuario/{id}', function ($id) {

    $nombre = "Juan";

    $datos = ['email' => 'juan@email.com', 'edad' => 30];

    

    return view('perfil', compact('id', 'nombre', 'datos'));

});

3. Usando compact() - Pasando el arreglo completo

php

Route::get('/usuario/{id}', function ($id) {

    $usuario = [

        'id' => $id,

        'nombre' => 'Juan',

        'email' => 'juan@email.com',

        'edad' => 30,

        'hobbies' => ['leer', 'nadar', 'programar']

    ];

    

    return view('perfil', compact('usuario'));

});

4. Desde un controlador

php

// En web.php

Route::get('/usuario/{id}', [UserController::class, 'show']);


// En UserController.php

public function show($id)

{

    $nombre = "Juan";

    $datos = ['email' => 'juan@email.com', 'edad' => 30];

    

    return view('perfil', [

        'id' => $id,

        'nombre' => $nombre,

        'datos' => $datos

    ]);

}

5. En la vista (perfil.blade.php)

<h1>Perfil de usuario</h1>

<p>ID: {{ $id }}</p>

<p>Nombre: {{ $nombre }}</p>


<h2>Datos del usuario:</h2>

<ul>

    <li>Email: {{ $datos['email'] }}</li>

    <li>Edad: {{ $datos['edad'] }}</li>

</ul>


{{-- O si es un array indexado --}}

@foreach($datos as $key => $value)

    <li>{{ $key }}: {{ $value }}</li>

@endforeach

Ejemplo con múltiples parámetros en la ruta

// Ruta con múltiples parámetros

Route::get('/producto/{categoria}/{id}', function ($categoria, $id) {

    $producto = ['nombre' => 'Laptop', 'precio' => 1000];

    $caracteristicas = ['RAM' => '8GB', 'SSD' => '256GB'];

    

    return view('producto', compact('categoria', 'id', 'producto', 'caracteristicas'));

});

La opción más común y recomendada es usar compact() o el arreglo asociativo directo, ya que son más limpios y fáciles de leer.




Controladores en Laravel (sin modelos)

En este tutorial aprenderás a crear un controlador, definir un método que retorne una vista con datos y vincularlo a una ruta, todo sin usar modelos. Solo trabajaremos con arreglos de prueba………………………………………………………………


1. ¿Qué es un controlador?

Un controlador es una clase que agrupa la lógica de manejo de peticiones HTTP. En lugar de poner toda la lógica en las rutas (closures), los controladores permiten organizar el código en métodos reutilizables.


2. Crear un controlador con Artisan

Ejecuta en la terminal (en la raíz de tu proyecto Laravel):

bash

php artisan make:controller TareaController

Esto creará el archivo app/Http/Controllers/TareaController.php.

3. Definir un método index

Abre el controlador recién creado y agrega un método index que devuelva una vista con un arreglo de tareas.

php

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class TareaController extends Controller

{

    public function index()

    {

        // Datos de ejemplo (sin modelos)

        $tareas = [

            ['id' => 1, 'nombre' => 'Comprar pan'],

            ['id' => 2, 'nombre' => 'Estudiar Laravel'],

            ['id' => 3, 'nombre' => 'Hacer ejercicio'],

        ];

        // Retorna la vista 'tareas.index' y le pasa la variable $tareas

        return view('tareas.index', compact('tareas'));

    }

}

  • compact('tareas') crea un arreglo asociativo ['tareas' => $tareas] que la vista recibirá.

  • La vista debe existir en resources/views/tareas/index.blade.php.


4. Crear la vista (sin CSS)

Crea el directorio tareas dentro de resources/views y dentro coloca index.blade.php con el siguiente contenido:

blade

<!DOCTYPE html>

<html>

<head>

    <title>Lista de tareas</title>

</head>

<body>

    <h1>Mis tareas</h1>

    <ul>

        @foreach ($tareas as $tarea)

            <li>{{ $tarea['nombre'] }} (ID: {{ $tarea['id'] }})</li>

        @endforeach

    </ul>

</body>

</html>

  • Usamos Blade @foreach para recorrer el arreglo.

  • Mostramos el nombre y el ID de cada tarea.

5. Registrar la ruta

Abre routes/web.php y añade:

php

use App\Http\Controllers\TareaController;

Route::get('/tareas', [TareaController::class, 'index']);

  • Esto asigna la URL /tareas al método index del TareaController.


6. Probar la aplicación

Inicia el servidor de desarrollo:

bash

php artisan serve

Abre tu navegador en http://localhost:8000/tareas y verás la lista de tareas renderizada.

7. Explicación del flujo

  1. El usuario hace una petición GET a /tareas.

  2. Laravel enruta la petición al método index de TareaController.

  3. El método prepara los datos (el arreglo $tareas) y llama a view('tareas.index', compact('tareas')).

  4. Blade renderiza la vista con la variable $tareas disponible.

  5. El HTML resultante se envía al navegador.


8. Buenas prácticas básicas

  • Nombres de métodos: Usa verbos HTTP (index, show, create, store, edit, update, destroy) para acciones típicas.

  • Pasar datos: Siempre usa compact() o arreglos explícitos (['tareas' => $tareas]).

  • Organización: Agrupa rutas relacionadas con Route::resource() (opcional, pero útil cuando tengas CRUD).

Resumen

  • Los controladores centralizan la lógica de tus rutas.

  • Los métodos retornan vistas con datos.

  • Las rutas enlazan URLs con métodos del controlador.

  • No necesitas modelos para empezar; puedes usar arreglos de prueba.

2. Obtener Todo el Contenido del Request

Laravel inyecta automáticamente el objeto 


Illuminate\Http\Request en los métodos del controlador.

Ejemplo: Recuperar todos los datos del request


use Illuminate\Http\Request;


class UserController extends Controller

{

    public function store(Request $request)

    {

        // Obtener todos los datos del request (formulario, JSON, etc.)

        $allData = $request->all();


        // Mostrar los datos (útil para debugging)

        dd($allData);


        // También puedes usar:

        // $request->input() → Equivalente a all(), pero permite valores por defecto

    }

}

📌 Uso común:

  • $request->all() → Devuelve un array asociativo con todos los inputs.

  • $request->input() → Similar a all(), pero permite definir un valor por defecto si el campo no existe.

3. Validar Inputs Específicos

Laravel ofrece validación integrada para asegurar que los datos cumplan ciertas reglas.


Ejemplo: Validar campos obligatorios

public function store(Request $request)

{

    // Validación básica

    $validatedData = $request->validate([

        'name' => 'required|string|max:255',

        'email' => 'required|email|unique:users',

        'password' => 'required|min:8',

    ]);


    // Si pasa la validación, continuamos

    return response()->json(['success' => 'Usuario creado!']);

}

📌 Reglas comunes:

  • required → El campo es obligatorio.

  • email → Debe ser un email válido.

  • unique:users → El email no debe existir en la tabla users.

  • min:8 → Mínimo 8 caracteres.

💡 Métodos alternativos para acceder a inputs específicos:

php

$name = $request->input('name'); // Obtiene el campo 'name'

$email = $request->email; // Sintaxis alternativa (propiedad dinámica)

$defaultValue = $request->input('role', 'user'); // Valor por defecto si no existef

 FLUJO DE DATOS EN EL CRUD

📥 1. Del Modelo al Controlador (Obtener datos)

php

// Obtener todos los registros

$productos = Producto::all();


// Obtener un registro específico

$producto = Producto::find($id);

$producto = Producto::findOrFail($id); // Lanza error 404 si no existe


// Obtener con condiciones

$productosActivos = Producto::where('activo', true)->get();


// Obtener el último registro

$ultimoProducto = Producto::latest()->first();


// Obtener con relaciones (si tienes)

$producto = Producto::with('categoria')->find($id);

📤 2. Del Controlador a la Vista (Inyectar datos)

Método 1: Usando compact()

php

public function index()

{

    $productos = Producto::all();

    $titulo = "Lista de Productos";

    return view('productos.index', compact('productos', 'titulo'));

}

Método 2: Usando with()

php

public function show($id)

{

    $producto = Producto::findOrFail($id);

    return view('productos.show')->with('producto', $producto);

}

Método 3: Usando array asociativo

php

public function edit($id)

{

    $producto = Producto::findOrFail($id);

    $categorias = Categoria::all();

    

    return view('productos.edit', [

        'producto' => $producto,

        'categorias' => $categorias,

        'modo' => 'edición'

    ]);

}

📥 3. De la Vista al Controlador (Recibir datos)

Para formularios GET (búsquedas, filtros):

php

public function index(Request $request)

{

    // Obtener parámetros de la URL

    $busqueda = $request->input('buscar');

    $categoria = $request->query('categoria');

    

    // También puedes usar

    $busqueda = $request->get('buscar');

    $busqueda = $request->buscar; // Si existe en la URL

    

    // Ejemplo de búsqueda

    $productos = Producto::where('nombre', 'LIKE', "%{$busqueda}%")

                        ->when($categoria, function($query) use ($categoria) {

                            return $query->where('categoria_id', $categoria);

                        })

                        ->get();

    

    return view('productos.index', compact('productos'));

}

Para formularios POST (crear, actualizar):

php

public function store(Request $request)

{

    // Forma 1: Obtener todos los datos

    $datos = $request->all();

    

    // Forma 2: Obtener solo algunos campos

    $nombre = $request->input('nombre');

    $precio = $request->input('precio');

    

    // Forma 3: Obtener con validación (recomendado)

    $validated = $request->validate([

        'nombre' => 'required|max:255',

        'precio' => 'required|numeric|min:0',

        'descripcion' => 'nullable|string'

    ]);

    

    // Guardar usando los datos validados

    $producto = Producto::create($validated);

}

📤 4. Del Controlador a la Vista con Redirección

php

public function store(Request $request)

{

    // Validar y guardar

    $validated = $request->validate([

        'nombre' => 'required|max:255',

        'precio' => 'required|numeric'

    ]);

    

    $producto = Producto::create($validated);

    

    // 🔥 DIFERENTES FORMAS DE REDIRECCIONAR

    // 1. Redirigir a una ruta con nombre

    return redirect()->route('productos.index');

    

    // 2. Redirigir a una URL específica

    return redirect('/productos');

    

    // 3. Redirigir al detalle del producto creado

    return redirect()->route('productos.show', $producto->id);

    

    // 4. Redirigir hacia atrás

    return redirect()->back();

    

    // 5. Redirigir con mensaje flash

    return redirect()->route('productos.index')

                     ->with('success', 'Producto creado exitosamente');

}


💬 MENSAJES FLASH (Sistema de notificaciones)

En el Controlador (Guardar mensaje):

php

// Mensaje de éxito

return redirect()->route('productos.index')

    ->with('success', '¡Producto creado correctamente!');


// Mensaje de error

return redirect()->back()

    ->with('error', 'Hubo un problema al guardar el producto');


// Mensaje de advertencia

return redirect()->route('productos.index')

    ->with('warning', 'El producto no tiene stock');


// Múltiples mensajes

return redirect()->route('productos.index')

    ->with([

        'success' => 'Producto actualizado',

        'info' => 'Revisa los cambios realizados'

    ]);


// Mensaje con datos adicionales

return redirect()->route('productos.show', $producto->id)

    ->with('success', 'Producto actualizado')

    ->with('producto_id', $producto->id);

En la Vista (Mostrar mensajes):


Mostrar un arreglo de tareas con vistas y debugging

Este tutorial te guía paso a paso para crear una pequeña aplicación en Laravel que solo muestra una lista de tareas desde un arreglo en memoria. No incluye formulario para agregar, solo la visualización, y además incorpora técnicas de depuración con dump() y dd() para que veas qué ocurre internamente.


1. Estructura del proyecto

Crearemos:

  • Una ruta GET para acceder a la lista.

  • Un controlador con un arreglo estático de tareas.

  • Una vista Blade que renderiza la lista.

  • Puntos de debugging para inspeccionar los datos.


2. Definir la ruta (routes/web.php)

Abre el archivo routes/web.php y agrega la siguiente ruta:

php

<?php


use App\Http\Controllers\TareaController;

use Illuminate\Support\Facades\Route;


Route::get('/tareas', [TareaController::class, 'index'])->name('tareas.index');

  • GET /tareas: Cuando el usuario visite esa URL, se ejecutará el método index del TareaController.

  • name('tareas.index'): Asigna un nombre a la ruta para usarla en las vistas o redirecciones (aunque en este ejemplo solo la usaremos para mostrar).


3. Crear el controlador (app/Http/Controllers/TareaController.php)

Genera el controlador con el comando Artisan:

bash

php artisan make:controller TareaController

Luego, edita el archivo con el siguiente contenido:

php

<?php


namespace App\Http\Controllers;


use Illuminate\Http\Request;


class TareaController extends Controller

{

    // Arreglo estático de ejemplo (simula datos)

    private $tareas = [

        ['id' => 1, 'nombre' => 'Comprar pan'],

        ['id' => 2, 'nombre' => 'Estudiar Laravel'],

        ['id' => 3, 'nombre' => 'Hacer ejercicio'],

    ];


    public function index()

    {

        // Debug: mostramos el contenido del arreglo antes de enviarlo a la vista

        dump($this->tareas);   // Muestra en la barra de depuración (o en la página)


        // También podemos usar dd() si queremos detener la ejecución para inspeccionar

        // dd($this->tareas);   // Descomenta para probar


        return view('tareas.index', ['tareas' => $this->tareas]);

    }

}

Explicación del controlador:

  • private $tareas: Es un arreglo fijo que simula una base de datos. En una aplicación real, aquí vendrían los datos desde un modelo.

  • index(): Prepara los datos y los pasa a la vista.

  • dump($this->tareas): Muestra el contenido del arreglo en la salida (útil para verificar que los datos existen). No detiene la ejecución.

  • dd($this->tareas): Si se descomenta, muestra el arreglo y detiene la ejecución, ideal para depurar en un punto crítico.


4. Crear la vista (resources/views/tareas/index.blade.php)

Crea la carpeta tareas dentro de resources/views y dentro de ella el archivo index.blade.php:

html

<!DOCTYPE html>

<html lang="es">

<head>

    <meta charset="UTF-8">

    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <title>Lista de Tareas</title>

    <style>

        body { font-family: Arial, sans-serif; margin: 20px; }

        .debug-box { background: #f4f4f4; padding: 10px; border-left: 4px solid #007bff; margin-bottom: 20px; }

        ul { list-style: none; padding: 0; }

        li { background: #e9ecef; margin: 5px 0; padding: 8px; border-radius: 4px; }

    </style>

</head>

<body>

    <h1>📋 Mis Tareas</h1>


    <!-- Caja de depuración en la vista -->

    <div class="debug-box">

        <strong>🔍 Debug: Contenido de la variable $tareas</strong>

        @dump($tareas)   <!-- Muestra el contenido de $tareas en la vista -->

    </div>


    <!-- Lista de tareas -->

    @if(count($tareas) > 0)

        <ul>

            @foreach($tareas as $tarea)

                <li>

                    <strong>ID:</strong> {{ $tarea['id'] }} - 

                    <strong>Nombre:</strong> {{ $tarea['nombre'] }}

                </li>

            @endforeach

        </ul>

    @else

        <p>No hay tareas para mostrar.</p>

    @endif


    <p><small>Datos estáticos (se pierden al reiniciar el servidor).</small></p>

</body>

</html>

Explicación de la vista:

  • @dump($tareas): Muestra el contenido de la variable en un formato legible, directamente en la página. Es súper útil para ver qué datos está recibiendo la vista.

  • @foreach recorre el arreglo y muestra cada tarea.

  • Se usa {{ }} para escapar la salida y evitar inyección XSS.


5. Probar la aplicación

Inicia el servidor de desarrollo:

php artisan serve

Ahora abre tu navegador en: http://localhost:8000/tareas

Verás:

  • La lista de tareas con sus IDs y nombres.

  • Un bloque de depuración que muestra el arreglo completo (gracias a @dump en la vista).

  • En la parte superior (si estás en modo de depuración), también verás la salida de dump($this->tareas) del controlador.


6. Flujo de trabajo explicado

  1. El usuario hace una petición GET a /tareas.

  2. Laravel busca la ruta definida en web.php y ejecuta el método index del TareaController.

  3. El controlador tiene un arreglo $tareas con datos de ejemplo.

  4. Se ejecuta dump($this->tareas) que muestra el arreglo en la barra de depuración (no detiene la ejecución).

  5. El controlador retorna la vista tareas.index pasándole el arreglo.

  6. La vista recibe $tareas, y con @dump($tareas) lo muestra en el HTML para inspección visual.

  7. Finalmente, la vista renderiza la lista de tareas.


7. ¿Qué pasa si usamos dd() en lugar de dump()?

Si en el controlador cambias dump($this->tareas) por dd($this->tareas), la ejecución se detiene y solo verás el contenido del arreglo, sin llegar a la vista. Esto es útil cuando quieres verificar que los datos existen antes de que ocurra cualquier otro procesamiento.

Puedes probar cambiando esa línea y recargando la página para ver el efecto.


8. Notas importantes

  • Datos en memoria: El arreglo se define dentro del controlador. Cada vez que se ejecuta el método index, se crea el arreglo desde cero. Si modificaramos el arreglo (por ejemplo, agregando una tarea), los cambios no se persistirían porque no hay una base de datos.

  • Para aplicaciones reales: En lugar de un arreglo estático, usarías un modelo de Eloquent para obtener datos desde la base de datos.

  • Depuración en producción: dump() y dd() solo deben usarse en entornos de desarrollo. En producción, asegúrate de que APP_DEBUG=false en tu archivo .env.


9. Ampliación: Mostrar también en consola

Si prefieres ver la información en la consola (cuando ejecutas pruebas o comandos), puedes usar logger() o info():

php

logger('Tareas:', $this->tareas);

Esto escribirá en el archivo de logs (storage/logs/laravel.log).


10. Resumen del código final

Ruta (routes/web.php):

php

Route::get('/tareas', [TareaController::class, 'index'])->name('tareas.index');

Controlador (app/Http/Controllers/TareaController.php):

php

<?php


namespace App\Http\Controllers;


class TareaController extends Controller

{

    private $tareas = [

        ['id' => 1, 'nombre' => 'Comprar pan'],

        ['id' => 2, 'nombre' => 'Estudiar Laravel'],

        ['id' => 3, 'nombre' => 'Hacer ejercicio'],

    ];


    public function index()

    {

        dump($this->tareas);  // Depuración en el controlador

        return view('tareas.index', ['tareas' => $this->tareas]);

    }

}

Vista (resources/views/tareas/index.blade.php):

html

<!DOCTYPE html>

<html>

<head>

    <title>Lista de Tareas</title>

</head>

<body>

    <h1>Mis Tareas</h1>

    @dump($tareas)  <!-- Depuración en la vista -->

    <ul>

        @foreach($tareas as $tarea)

            <li>{{ $tarea['id'] }} - {{ $tarea['nombre'] }}</li>

        @endforeach

    </ul>

</body>

</html>


Conclusión

Has creado un ejemplo funcional que muestra un arreglo de tareas en una vista, con puntos de depuración para entender mejor el flujo de datos. Este es el primer paso para construir aplicaciones más complejas, donde los datos vendrán de la base de datos y se podrán agregar, editar o eliminar.

¡Sigue practicando! Prueba a modificar el arreglo, agregar más campos o cambiar el estilo de la vista. Cuando te sientas cómodo, avanza al siguiente nivel: conectar con una base de datos usando Eloquent.



Separar controladores para Web y API en Laravel (Enfoque para principiantes)

Crear el controlador (TareaController)

Genera el controlador si no existe:

bash

php artisan make:controller TareaController

Luego, edita el archivo app/Http/Controllers/TareaController.php con el siguiente contenido:

php

<?php


namespace App\Http\Controllers;


use Illuminate\Http\Request;


class TareaController extends Controller

{

    // Arreglo de ejemplo (simula base de datos)

    private $tareas = [

        ['id' => 1, 'nombre' => 'Comprar pan'],

        ['id' => 2, 'nombre' => 'Estudiar Laravel'],

        ['id' => 3, 'nombre' => 'Hacer ejercicio'],

    ];


    /**

     * Muestra la lista de tareas.

     * Si la solicitud espera JSON, devuelve los datos en formato JSON.

     * Si no, devuelve la vista Blade.

     */

    public function index(Request $request)

    {

        // Depuración: mostrar el arreglo en la barra de debug (solo en desarrollo)

        dump($this->tareas);


        // Si la solicitud es para una API (espera JSON)

        if ($request->wantsJson()) {

            // También podemos usar dd() para inspeccionar antes de devolver

            // dd($this->tareas); // Descomentar para depurar


            return response()->json([

                'status' => 'success',

                'data'   => $this->tareas

            ]);

        }


        // Si no espera JSON, devuelve la vista web

        return view('tareas.index', ['tareas' => $this->tareas]);

    }


    /**

     * (Opcional) Obtener una tarea específica por ID.

     * Este método solo se usará para la API.

     */

    public function show($id)

    {

        // Buscar la tarea por ID (simulación)

        $tarea = collect($this->tareas)->firstWhere('id', $id);


        if (!$tarea) {

            return response()->json(['error' => 'Tarea no encontrada'], 404);

        }


        return response()->json($tarea);

    }

}

Explicación del controlador:

  • $tareas: Arreglo estático con datos de ejemplo.

  • index(Request $request):

    • Usa $request->wantsJson() para detectar si el cliente espera una respuesta JSON (generalmente cuando el encabezado Accept: application/json está presente).

    • Si es así, devuelve un JsonResponse con los datos y un estado success.

    • Si no, devuelve la vista tareas.index pasando el arreglo.

  • show($id): Método adicional para la API que devuelve una tarea específica. No tiene vista asociada, solo JSON.

Pregunta frecuente: ¿Es mejor crear un solo controlador que maneje tanto vistas como JSON, o crear dos controladores separados?
Respuesta: Para un principiante, lo más normal y recomendado es usar dos controladores separados. Aunque técnicamente es posible usar el mismo, separarlos te da un código más limpio, fácil de mantener y seguir las buenas prácticas de Laravel.

En este tutorial construirás una aplicación de tareas con:

  • Controlador Web: Para mostrar vistas Blade.

  • Controlador API: Para devolver JSON (endpoints RESTful).

  • Ambos compartirán la misma lógica de negocio (por ahora un arreglo en memoria).

  • Incluiremos técnicas de depuración con dump() y dd() para que entiendas el flujo.


¿Por qué separar controladores?

  1. Responsabilidad única: Cada controlador tiene un propósito claro (web vs API).

  2. Mantenibilidad: Si cambia la API (ej. agregar versionado), no afecta la web.

  3. Flexibilidad: Puedes usar diferentes middlewares, validaciones o formatos de respuesta.

  4. Principio de separación de concerns: Es más fácil de entender para otros desarrolladores.

  5. En proyectos grandes, es la práctica estándar (Laravel incluso sugiere estructuras como app/Http/Controllers/Api).


1. Configuración inicial

Asegúrate de tener un proyecto Laravel nuevo o existente. Si no, crea uno:

bash

composer create-project laravel/laravel tareas-app

cd tareas-app


2. Crear los controladores

2.1. Controlador Web

El controlador web estará en app/Http/Controllers/TareaController.php (el nombre por defecto). Lo creamos con Artisan:

bash

php artisan make:controller TareaController

2.2. Controlador API

Para la API, es común crear una subcarpeta Api dentro de Controllers. Lo haremos así:

bash

php artisan make:controller Api/TareaController

Esto creará app/Http/Controllers/Api/TareaController.php.


3. Definir las rutas

3.1. Rutas web (routes/web.php)

php

<?php


use App\Http\Controllers\TareaController;

use Illuminate\Support\Facades\Route;


Route::get('/tareas', [TareaController::class, 'index'])->name('tareas.index');

3.2. Rutas API (routes/api.php)

php

<?php


use App\Http\Controllers\Api\TareaController as ApiTareaController;

use Illuminate\Support\Facades\Route;


Route::get('/tareas', [ApiTareaController::class, 'index']);

Route::get('/tareas/{id}', [ApiTareaController::class, 'show']);

Nota: Usamos un alias ApiTareaController para evitar conflicto de nombres con el controlador web.


4. Implementar el Controlador Web

Abre app/Http/Controllers/TareaController.php y escribe:

php

<?php


namespace App\Http\Controllers;


use Illuminate\Http\Request;


class TareaController extends Controller

{

    // Arreglo de ejemplo (simula base de datos)

    private $tareas = [

        ['id' => 1, 'nombre' => 'Comprar pan'],

        ['id' => 2, 'nombre' => 'Estudiar Laravel'],

        ['id' => 3, 'nombre' => 'Hacer ejercicio'],

    ];


    /**

     * Muestra la lista de tareas en una vista.

     */

    public function index()

    {

        // Depuración: mostrar el arreglo antes de enviar a la vista

        dump($this->tareas);  // Aparece en la barra de debug (si está instalada) o en la salida


        return view('tareas.index', ['tareas' => $this->tareas]);

    }


    // (Opcional) Podrías agregar otros métodos como store, edit, etc., pero para este ejemplo solo mostramos.

}

Observaciones:

  • El controlador web solo se preocupa por devolver vistas.

  • No tiene lógica de detección de JSON, porque su función es puramente web.

  • Usamos dump() para inspeccionar el arreglo.


5. Implementar el Controlador API

Abre app/Http/Controllers/Api/TareaController.php y escribe:

php

<?php


namespace App\Http\Controllers\Api;


use App\Http\Controllers\Controller;

use Illuminate\Http\Request;


class TareaController extends Controller

{

    // El mismo arreglo de ejemplo (podríamos extraerlo a un servicio compartido, pero por simplicidad lo duplicamos)

    private $tareas = [

        ['id' => 1, 'nombre' => 'Comprar pan'],

        ['id' => 2, 'nombre' => 'Estudiar Laravel'],

        ['id' => 3, 'nombre' => 'Hacer ejercicio'],

    ];


    /**

     * Devuelve todas las tareas en JSON.

     */

    public function index()

    {

        // Depuración: inspeccionar antes de devolver

        dump($this->tareas);  // Visible en la barra de debug


        // Podríamos usar dd() para detener la ejecución y ver el arreglo

        // dd($this->tareas); // Descomentar para probar


        return response()->json([

            'status' => 'success',

            'data'   => $this->tareas

        ]);

    }


    /**

     * Devuelve una tarea específica en JSON.

     */

    public function show($id)

    {

        // Buscar la tarea por ID

        $tarea = collect($this->tareas)->firstWhere('id', (int)$id);


        if (!$tarea) {

            return response()->json([

                'status' => 'error',

                'message' => 'Tarea no encontrada'

            ], 404);

        }


        return response()->json([

            'status' => 'success',

            'data'   => $tarea

        ]);

    }

}

Observaciones:

  • El controlador API siempre devuelve JSON.

  • Incluye manejo de errores con códigos HTTP apropiados (404).

  • Podemos usar dump() para depurar antes de enviar la respuesta.

  • El arreglo está duplicado; en una aplicación real, lo ideal sería tener una capa de servicio o un repositorio para compartir la lógica (pero eso es más avanzado).


6. Crear la vista web

Crea la carpeta resources/views/tareas y dentro el archivo index.blade.php:

html

<!DOCTYPE html>

<html lang="es">

<head>

    <meta charset="UTF-8">

    <title>Mis Tareas</title>

    <style>

        body { font-family: Arial, sans-serif; margin: 20px; }

        .debug-box { background: #f0f0f0; padding: 10px; border-left: 4px solid #007bff; margin-bottom: 20px; }

        ul { list-style: none; padding: 0; }

        li { background: #e9ecef; margin: 5px 0; padding: 8px; border-radius: 4px; }

        .api-info { background: #d4edda; padding: 10px; border-radius: 4px; margin-top: 20px; }

    </style>

</head>

<body>

    <h1>📋 Lista de Tareas (Web)</h1>


    <!-- Depuración en la vista -->

    <div class="debug-box">

        <strong>🔍 Debug: Contenido de $tareas (desde la vista)</strong>

        @dump($tareas)

    </div>


    @if(count($tareas) > 0)

        <ul>

            @foreach($tareas as $tarea)

                <li><strong>ID:</strong> {{ $tarea['id'] }} - <strong>Nombre:</strong> {{ $tarea['nombre'] }}</li>

            @endforeach

        </ul>

    @else

        <p>No hay tareas.</p>

    @endif


    <div class="api-info">

        <p><strong>🌐 También dispones de una API:</strong></p>

        <p>Endpoint: <code>/api/tareas</code> (devuelve JSON)</p>

        <p>Prueba con curl: <code>curl -H "Accept: application/json" http://localhost:8000/api/tareas</code></p>

    </div>

</body>

</html>


7. Probar la aplicación

7.1. Iniciar el servidor

bash

php artisan serve

7.2. Probar la web

Abre http://localhost:8000/tareas en tu navegador. Verás la lista de tareas y el bloque de depuración.

7.3. Probar la API

Usa Postman, Insomnia o curl en la terminal:

bash

curl -H "Accept: application/json" http://localhost:8000/api/tareas

Deberías obtener:

json

{

    "status": "success",

    "data": [

        {"id":1,"nombre":"Comprar pan"},

        {"id":2,"nombre":"Estudiar Laravel"},

        {"id":3,"nombre":"Hacer ejercicio"}

    ]

}

Y para una tarea específica:

bash

curl -H "Accept: application/json" http://localhost:8000/api/tareas/1

Respuesta:

json

{

    "status": "success",

    "data": {"id":1,"nombre":"Comprar pan"}

}

Si pruebas con un ID inexistente (ej. /api/tareas/99), obtendrás un error 404 con el mensaje correspondiente.


8. Depuración con dump() y dd()

Ambos controladores incluyen dump($this->tareas). Esto te permite ver el contenido del arreglo en la barra de depuración de Laravel (si tienes el paquete laravel/debugbar instalado) o en la salida de la página. Si no ves nada, instala Debugbar:

bash

composer require barryvdh/laravel-debugbar --dev

Luego, si quieres detener la ejecución para inspeccionar un punto específico, descomenta dd($this->tareas) en cualquiera de los controladores. Por ejemplo, en el controlador API:

php

public function index()

{

    dd($this->tareas); // Muestra el arreglo y detiene todo

    // ...

}

Al hacer una petición a la API, verás el dump y no se devolverá JSON, pero es útil para depurar.

En la vista, también puedes usar @dd($tareas) en lugar de @dump para detener la renderización y mostrar el contenido.


9. ¿Qué pasa si queremos compartir los datos entre controladores?

En el ejemplo duplicamos el arreglo en ambos controladores. Para evitar duplicación, podríamos:

  • Crear un servicio (clase) que gestione las tareas y lo inyectar en ambos controladores.

  • Usar un modelo con base de datos (lo más común).

  • Usar un trait o una clase base.

Por simplicidad, para este tutorial lo dejamos así, pero en la práctica avanzada se recomienda una capa de servicio.


10. Conclusión: ¿Es buena práctica separar controladores?

Sí, es la práctica recomendada y la más común en proyectos Laravel. Separar controladores para web y API te da:

  • Código más organizado y fácil de leer.

  • Menos riesgo de romper una parte al modificar la otra.

  • Posibilidad de aplicar middlewares específicos (ej. autenticación para API con Sanctum, y sesiones para web).

  • Escalabilidad: si necesitas versionar la API (v1, v2), es más sencillo.

Los principiantes suelen empezar con un solo controlador por simplicidad, pero a medida que el proyecto crece, la separación se vuelve necesaria. Este tutorial te muestra el camino correcto desde el inicio.

Ahora ya sabes cómo estructurar tu aplicación para que tenga tanto interfaz web como API, manteniendo cada parte en su lugar.


11. Extras: Mejoras sugeridas

  • Validación: Agrega validación en los métodos de creación/actualización.

  • Eloquent: Reemplaza el arreglo por un modelo Tarea y una base de datos.

  • API Resources: Usa TareaResource para formatear la salida JSON de manera más controlada.

  • Autenticación: Protege la API con Laravel Sanctum o Passport.

Comentarios

Entradas más populares de este blog

02 -Rutas en Laravel

01-04-convencion nombres

3-Rutas