Docs Menu
Docs Home
/ /

Tutorial: Crea un recordatorio de tareas con Laravel y MongoDB

En este tutorial, aprenderás a usar MongoDB en una aplicación Laravel creando un sistema sencillo de recordatorios de tareas. La aplicación te permite crear, leer, actualizar y eliminar tareas. Además, envía recordatorios por correo electrónico para las próximas tareas según una hora programada.

Antes de comenzar este tutorial, asegúrese de tener los siguientes componentes instalados en su entorno de desarrollo:

  • PHP y la extensión PHP MongoDB

  • Laravel

  • Compositor

  • NPM

También debe configurar un clúster de MongoDB Atlas. Para saber cómo configurar un clúster, consulte la guía de introducción.

1

Utilice Composer para crear un nuevo proyecto de Laravel y navegue hasta el directorio del proyecto:

composer create-project laravel/laravel LaravelMongodbProject
cd LaravelMongodbProject
2

Para usar MongoDB en su aplicación, debe instalar el paquete Laravel MongoDB y configurarlo en el config/database.php .env.

Instale el paquete utilizando el siguiente comando:

composer require mongodb/laravel-mongodb

Tip

Si se produce un error al ejecutar el comando anterior, asegúrese de que la extensión PHP de MongoDB esté instalada. Para saber cómo instalarla, consulte el paso "Instalar la extensión PHP de MongoDB" en la guía de introducción.

3

Una vez finalizada la instalación del paquete MongoDB de Laravel, agregue la conexión de su base de datos MongoDB al archivo config/database.php para completar la configuración. Agregue la siguiente configuración de MongoDB a la matriz connections que contiene las configuraciones para otros tipos de bases de datos:

return [
'connections' => [
'mongodb' => [
'driver' => 'mongodb',
'dsn' => env('MONGODB_URI'),
'database' => 'task_reminder',
],
// Other connections here
],
];

Su aplicación obtiene el valor dsn del archivo .env. Navegue hasta el archivo .env. Luego, cree un valor para MONGODB_URI y asígnele el valor de su cadena de conexión de MongoDB.

Tip

Para obtener su cadena de conexión de MongoDB, navegue a su clúster en MongoDB Atlas. Haga clic en el icono Connect y haga clic en el Drivers debajo Connect your application de. Seleccione "PHP" en el Driver menú de selección. Copie la cadena de conexión del cuadro de diálogo. Para obtener información detallada sobre cómo obtener la cadena de conexión, consulte "crear una cadena de conexión".

En el archivo .env, establezca el valor DB_CONNECTION en mongodb para que sea la conexión predeterminada de su aplicación. Edite el valor SESSION_DRIVER y configúrelo en mongodb, como se muestra en el siguiente código:

MONGODB_URI=mongodb+srv://YOUR_MONGODB_CONNECTION_STRING
DB_CONNECTION=mongodb
// Other DB_ values here ...
SESSION_DRIVER=mongodb
4

Después de instalar y configurar su aplicación para que funcione con MongoDB, configure la autenticación. Laravel simplifica la implementación de la autenticación ofreciendo paquetes como Laravel Breeze, Laravel Fortify y Laravel Jetstream. Este tutorial utiliza Laravel Breeze para la autenticación.

Instalar Laravel Breeze usando Composer:

composer require laravel/breeze --dev

Una vez completada la instalación, ejecute los siguientes comandos:

php artisan key:generate
php artisan breeze:install
php artisan migrate
php artisan db:seed
npm install
npm run dev

Se le pedirá que elija su pila y paquete de pruebas preferidos. Para este tutorial, seleccione la primera opción, Blade con Alpine.

┌ Which Breeze stack would you like to install? ───────────────┐
│ > ● Blade with Alpine │
│ ○ Livewire (Volt Class API) with Alpine │
│ ○ Livewire (Volt Functional API) with Alpine │
│ ○ React with Inertia │
│ ○ Vue with Inertia │
│ ○ API only │
└──────────────────────────────────────────────────────────────┘

Este comando agrega vistas de autenticación, rutas, controladores y otros recursos relacionados a su aplicación.

5

Laravel Breeze crea un modelo de usuario predeterminado para bases de datos SQL. Debe actualizarlo para que funcione con MongoDB y solucionar problemas de compatibilidad con limitaciones de velocidad.

Abra app/Models/User.php y reemplace su contenido con lo siguiente:

<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Notifications\Notifiable;
use MongoDB\Laravel\Auth\User as MongoUser;
class User extends MongoUser {
use HasFactory, Notifiable;
protected $connection = 'mongodb';
protected $collection = 'users';
/**
* The attributes that are mass assignable.
*
* @var array<int, string>
*/
protected $fillable = [
'name',
'email',
'password',
];
/**
* The attributes that should be hidden for serialization.
*
* @var array<int, string>
*/
protected $hidden = [
'password',
'remember_token',
];
/**
* Get the attributes to cast.
*
* @return array<string, string>
*/
protected function casts(): array
{
return [
'email_verified_at' => 'datetime',
'password' => 'hashed',
];
}
}
6

Sirva el proyecto usando el servidor integrado de Laravel y confirme que todo funciona correctamente. En el directorio del proyecto de Laravel, ejecute el siguiente comando:

php artisan serve

El proyecto se ejecuta en 127.0.0.1:8000. Si el puerto 8000 ya está en uso, Laravel cambia a un nuevo puerto disponible y lo imprime en la terminal.

Para probar el sistema de autenticación, seleccione el botón Register en su aplicación y cree una nueva cuenta de usuario. Esto almacenará el usuario en su base de datos MongoDB y le permitirá iniciar sesión con esas credenciales. Para este tutorial, puede establecer el nombre de usuario en test@example.com y la contraseña en password.

Para verificar que el paquete Laravel MongoDB se configuró correctamente, cree una ruta para hacer ping a su clúster MongoDB. Agregue lo siguiente a routes/web.php:

Route::get('/ping', function (Request $request) {
$connection = DB::connection('mongodb');
try {
$connection->command(['ping' => 1]);
$msg = 'MongoDB is accessible!';
} catch (\MongoDB\Driver\Exception\ConnectionException $e) {
$msg = 'You are not connected to MongoDB. Error: ' . $e->getMessage();
}
return ['msg' => $msg];
});

Visita esta ruta en tu navegador. Con la configuración correcta, verás el mensaje "¡MongoDB es accesible!" en tu navegador.

7

Cree el modelo y el controlador para la función de programación de tareas utilizando el siguiente comando:

php artisan make:model Task --resource --controller

Este comando crea el modelo Task en el directorio app/Models y el TaskController en el directorio app/Http/Controllers con métodos de recursos.

Cree una ruta para TaskController navegando a routes/web.php y agregando el siguiente código:

use App\Http\Controllers\TaskController;
// Other route definitions...
Route::resource('tasks', TaskController::class)->middleware('auth');
8

Navegue a app/Models/Task.php y reemplace el contenido del archivo con el siguiente código:

<?php
namespace App\Models;
use MongoDB\Laravel\Eloquent\Model;
class Task extends Model {
protected $connection = 'mongodb';
protected $table = 'tasks';
protected $fillable = [
'title',
'description',
'due_date',
'email',
'reminder_time',
'last_notification_date'
];
}

Este código crea el modelo de tarea con las siguientes especificaciones:

  • La instrucción use MongoDB\Laravel\Eloquent\Model después del espacio de nombres es específica de los modelos MongoDB. Anula las funciones de Eloquent implementadas con SQL mediante consultas MongoDB.

  • La propiedad protected $table = 'tasks' es opcional. Especifica el nombre de la colección MongoDB utilizada para almacenar los documentos de este modelo.

  • La propiedad protected $fillable especifica las propiedades asignables en masa.

Tip

Una de las características únicas de MongoDB es que no requiere migraciones como las bases de datos relacionales. Puedes añadir nuevos campos directamente a tus documentos sin actualizar el modelo ni crear migraciones. Esta función es útil para gestionar datos dinámicos.

9

Navegue a app/Http/Controllers/TaskController.php y actualice el contenido con el siguiente código:

<?php
namespace App\Http\Controllers;
use App\Models\Task;
use Carbon\Carbon;
use Illuminate\Http\Request;
class TaskController extends Controller {
/**
* Displays a listing of the resource.
*/
public function index()
{
$tasks = Task::where('email', auth()->user()->email)->get();
return view('tasks.index', compact('tasks'));
}
/**
* Shows the form for creating a new resource.
*/
public function create()
{
return view('tasks.create');
}
/**
* Stores a newly created resource in storage.
*/
public function store(Request $request)
{
$data = $request->validate([
'title' => 'required|string|max:255',
'description' => 'nullable|string',
'due_date' => 'required|date',
'reminder_time' => 'required|date',
]);
$data['due_date'] = Carbon::parse($request->due_date);
$data['reminder_time'] = Carbon::parse($request->reminder_time);
$data['email'] = auth()->user()->email;
$data['last_notification_date'] = null;
Task::create($data);
return redirect()->route('tasks.index')->with('success', 'Task created successfully.');
}
/**
* Displays the specified resource.
*/
public function show(string $id)
{
//
}
/**
* Shows the form for editing the specified resource.
*/
public function edit(string $id)
{
$tasks = Task::where('id', $id)->get();
return view('tasks.edit', ['tasks' => $tasks]);
}
/**
* Updates the specified resource in storage.
*/
public function update(Request $request, string $id)
{
$data = $request->validate([
'title' => 'required|string|max:255',
'description' => 'nullable|string',
'due_date' => 'required|date',
'reminder_time' => 'required|date',
]);
$task = Task::findOrFail($id);
$data['due_date'] = Carbon::parse($request->due_date)->format('Y-m-d H:i:s');
$data['reminder_time'] = Carbon::parse($request->reminder_time)->format('Y-m-d H:i:s');
$task->update($data);
return redirect()->route('tasks.index')->with('success', 'Task updated successfully.');
}
/**
* Removes the specified resource from storage.
*/
public function destroy(string $id)
{
$task = Task::findOrFail($id);
$task->delete();
return redirect()->route('tasks.index')->with('success', 'Task deleted successfully.');
}
}

La clase TaskController contiene código que maneja las operaciones CRUD del modelo de tarea:

  • El método index() recupera todas las tareas que pertenecen al usuario que inició sesión y las envía al archivo index.blade.php para su visualización.

  • El método create() devuelve la vista de formulario para crear una nueva tarea.

  • El método store() valida la entrada, asigna el correo electrónico del usuario conectado a la tarea y lo guarda en la base de datos.

  • El método edit() recupera la tarea específica que se va a editar y la muestra en un formulario de edición.

  • El método update() guarda la tarea editada en la colección de tareas de MongoDB.

  • El método destroy() elimina una tarea específica.

Cada operación redirecciona a la lista de tareas con un mensaje de éxito para que el usuario pueda dar su opinión.

10

En el directorio resources/views, cree una carpeta llamada tasks y cree los siguientes archivos en ella:

  • create.blade.php

  • edit.blade.php

  • index.blade.php

Navegue a resources/views/tasks/create.blade.php y agregue el siguiente contenido:

1<x-app-layout>
2 <x-slot name="header">
3 <h2 class="font-semibold text-xl text-gray-800 leading-tight">
4 {{ __('Tasks') }}
5 </h2>
6 </x-slot>
7
8 <div class="py-12">
9 <div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
10 <div class="bg-white overflow-hidden shadow-sm sm:rounded-lg">
11 <div class="container mx-auto p-4">
12 <h2 class="text-2xl font-bold mb-4">Create New Task</h2>
13
14 <form action="{{ route('tasks.store') }}" method="POST">
15 @csrf
16
17 <div class="mb-4">
18 <label for="title" class="block text-gray-700">Title:</label>
19 <input type="text"
20 name="title"
21 id="title"
22 required
23 class="border border-gray-300 p-2 w-full"
24 value="{{ old('title') }}">
25 @error('title')
26 <p class="text-red-500">{{ $message }}</p>
27 @enderror
28 </div>
29
30 <div class="mb-4">
31 <label for="description" class="block text-gray-700">Description:</label>
32 <textarea name="description"
33 id="description"
34 class="border border-gray-300 p-2 w-full">{{ old('description') }}</textarea>
35 </div>
36
37 <div class="mb-4">
38 <label for="due_date" class="block text-gray-700">Due Date:</label>
39 <input type="date"
40 name="due_date"
41 id="due_date"
42 required
43 class="border border-gray-300 p-2 w-full"
44 value="{{ old('due_date') }}">
45 @error('due_date')
46 <p class="text-red-500">{{ $message }}</p>
47 @enderror
48 </div>
49
50 <div class="mb-4">
51 <label for="reminder_time" class="block text-gray-700">Reminder Time:</label>
52 <input type="datetime-local"
53 name="reminder_time"
54 id="reminder_time"
55 class="border border-gray-300 p-2 w-full"
56 value="{{ old('reminder_time') }}">
57 </div>
58
59 <button type="submit"
60 class="bg-green-600 text-white p-2 border rounded">
61 Create Task
62 </button>
63 </form>
64 </div>
65 </div>
66 </div>
67 </div>
68</x-app-layout>

El formulario contiene entradas de texto para title y description y entradas de fecha y hora para due date y reminder time.

Navegue a resources/views/tasks/edit.blade.php y agregue el siguiente contenido:

1<x-app-layout>
2 <x-slot name="header">
3 <h2 class="font-semibold text-xl text-gray-800 leading-tight">
4 {{ __('Edit Task') }}
5 </h2>
6 </x-slot>
7
8 <div class="py-12">
9 <div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
10 <div class="bg-white overflow-hidden shadow-sm sm:rounded-lg">
11 <div class="p-6 text-gray-900">
12 @foreach($tasks as $task)
13 <form action="{{ route('tasks.update', $task->id) }}" method="POST">
14 @csrf
15 @method('PUT')
16
17 <div class="mb-4">
18 <label for="title" class="block text-gray-700">Title:</label>
19 <input type="text"
20 name="title"
21 id="title"
22 required
23 class="border border-gray-300 p-2 w-full"
24 value="{{ old('title', $task->title) }}">
25 @error('title')
26 <p class="text-red-500">{{ $message }}</p>
27 @enderror
28 </div>
29
30 <div class="mb-4">
31 <label for="description" class="block text-gray-700">Description:</label>
32 <textarea name="description"
33 id="description"
34 class="border border-gray-300 p-2 w-full">{{ old('description', $task->description) }}</textarea>
35 </div>
36
37 <div class="mb-4">
38 <label for="due_date" class="block text-gray-700">Due Date:</label>
39 <input type="date"
40 name="due_date"
41 id="due_date"
42 required
43 class="border border-gray-300 p-2 w-full"
44 value="{{ old('due_date', $task->due_date) }}">
45 @error('due_date')
46 <p class="text-red-500">{{ $message }}</p>
47 @enderror
48 </div>
49
50 <div class="mb-4">
51 <label for="reminder_time" class="block text-gray-700">Reminder Time:</label>
52 <input type="datetime-local"
53 name="reminder_time"
54 id="reminder_time"
55 class="border border-gray-300 p-2 w-full"
56 value="{{ old('reminder_time', $task->reminder_time) }}">
57 </div>
58
59 <button type="submit"
60 class="bg-blue-500 text-white p-2 rounded">
61 Update Task
62 </button>
63 </form>
64 @endforeach
65 </div>
66 </div>
67 </div>
68 </div>
69</x-app-layout>

El formulario de edición contiene los mismos campos de entrada que el formulario de creación y se carga con los datos de la tarea que se está editando actualmente.

Navegue a resources/views/tasks/index.blade.php y agregue el siguiente contenido:

1<x-app-layout>
2 <x-slot name="header">
3 <h2 class="font-semibold text-xl text-gray-800 leading-tight">
4 {{ __('Tasks') }}
5 </h2>
6 </x-slot>
7
8 <div class="py-12">
9 <div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
10 <div class="bg-white overflow-hidden shadow-sm sm:rounded-lg">
11 <div class="p-6 text-gray-900">
12 <div class="mb-2">
13 <a href="{{ route('tasks.create') }}"
14 class="p-2 border mb-4">
15 Create New Task
16 </a>
17 </div>
18
19 <ul class="mt-4">
20 @foreach ($tasks as $task)
21 <div class="mt-2">
22 <hr>
23 </div>
24
25 <li>
26 <h1 class="text-2xl">
27 <strong>{{ $task->title }}</strong>
28 - Due: {{ $task->due_date }}
29 </h1>
30
31 <p class="text-gray-600">
32 {{ $task->description }}
33 </p>
34
35 <div class="flex gap-2 mt-4">
36 <div class="p-2 text-white bg-gray-700">
37 <a href="{{ route('tasks.edit', $task->id) }}">
38 Edit
39 </a>
40 </div>
41
42 <div class="p-2 text-white bg-red-700 rounded">
43 <form action="{{ route('tasks.destroy', $task->id) }}"
44 method="POST"
45 style="display:inline;">
46 @csrf
47 @method('DELETE')
48 <button type="submit">Delete</button>
49 </form>
50 </div>
51 </div>
52 </li>
53 @endforeach
54 </ul>
55 </div>
56 </div>
57 </div>
58 </div>
59</x-app-layout>

Esta vista incluye un enlace al formulario de creación y recorre todas las tareas para mostrar aquellas que pertenecen al usuario autenticado.

11

Añade un enlace a la función de tareas desde la navegación de tu aplicación. Ve a resources/views/layouts/navigation.blade.php y añade el siguiente código después del enlace de navegación del panel:

1// ...existing code ...
2<div class="hidden space-x-8 sm:-my-px sm:ms-10 sm:flex">
3 <x-nav-link :href="route('tasks.index')" :active="request()->routeIs('tasks.index')">
4 {{ __('Tasks') }}
5 </x-nav-link>
6</div>

En este punto, puede probar las operaciones CRUD de su sistema de gestión de tareas. Asegúrese de que todo funcione correctamente antes de pasar a la siguiente sección.

12

Para implementar el sistema de recordatorio de tareas pendientes, cree un comando Artisan personalizado para enviar recordatorios por correo electrónico y registre el comando para la programación automática.

Para crear un comando Artisan personalizado, ejecute el siguiente código en su terminal:

php artisan make:command SendTaskReminders

Después de crear el comando, actualice el contenido del archivo app/Console/Commands/SendTaskReminders.php con el siguiente código:

<?php
namespace App\Console\Commands;
use App\Models\Task;
use Carbon\Carbon;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Mail;
class SendTaskReminders extends Command {
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'app:send-task-reminders';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Command description';
/**
* Execute the console command.
*/
public function handle() {
$now = Carbon::now();
$upcomingTasks = Task::where('last_notification_date', null)->get();
$upcomingTasks = Task::where('last_notification_date', null)
->where('reminder_time', '>=', $now->clone()->subMinutes(10))
->get();
foreach ($upcomingTasks as $task) {
$emailBody = <<<EOF
Hello,
This is a reminder for your task:
Title: {$task->title}
Description: {$task->description}
Due Date: {$task->due_date}
Please make sure to complete it on time!
Regards,
Your Task Reminder App
EOF;
Mail::raw($emailBody, function ($message) use ($task) {
$message->to($task->email)
->subject("Task Reminder: {$task->title}");
});
$task->last_notification_date = $now;
$task->save();
$this->info("Reminder email sent for task: {$task->title}");
}
return self::SUCCESS;
}
}

La lógica principal del comando Artisan personalizado se escribe en el método handle(). El código obtiene la marca de tiempo actual mediante Carbon::now().

A continuación, consulta la base de datos para obtener todas las tareas donde reminder_time es menor o igual a la hora actual y donde reminder_time es mayor o igual a 10 minutos antes de la hora actual. En MongoDB, todas las fechas se almacenan en UTC. Incluso si su servidor usa una zona horaria diferente, no necesita cambiarla.

La consulta recupera todas las tareas que vencen en los próximos 10 minutos. El código recorre los resultados y envía recordatorios a los correos electrónicos de los usuarios sobre las tareas que vencen en los próximos 10 minutos.

Nota

Para que el programador de tareas funcione correctamente, debes configurar tu aplicación para enviar correos electrónicos. Mailtrap.io es una herramienta útil para probar el envío de correos electrónicos. Para obtener más información, consulta "Enviar correos electrónicos en Laravel".

13

Para completar la configuración, programe el comando Artisan creado en el paso anterior para que se ejecute cada minuto. Este método ejecuta automáticamente php artisan app:send-task-reminders cada minuto.

Navegue a routes/console.php y agregue el siguiente código:

// ...existing code ...
Schedule::command('app:send-task-reminders')->everyMinute();

Para probar que esto funciona, ejecute el siguiente comando:

php artisan schedule:run

En un servidor de producción, debe configurar un trabajo cron para ejecutar el comando php artisan schedule:run a intervalos regulares.

En un servidor basado en Linux o Unix, puede abrir el archivo de configuración de cron utilizando el siguiente comando:

crontab -e

Agregue el siguiente código a la pestaña de configuración de cron:

* * * * * /usr/bin/php /path-to-your-project/artisan schedule:run >>
/dev/null 2>&1

Reemplace /usr/bin/php con la ruta a su binario de PHP y /path-to-your-project con la ruta completa a su proyecto de Laravel en su servidor. Guarde y cierre el archivo.

Para verificar que el trabajo cron esté configurado correctamente, ejecute el siguiente comando:

crontab -l

Ahora tienes una aplicación de programación de tareas que usa Laravel y MongoDB. Este tutorial muestra cómo realizar las siguientes acciones:

  • Configurar un proyecto de Laravel para trabajar con MongoDB

  • Implementar funciones CRUD para el programador de tareas

  • Cree un comando Laravel Artisan personalizado para el sistema de recordatorios

  • Programe una tarea para ejecutar el comando Artisan a intervalos

  • Configurar el trabajo cron en un servidor basado en Linux

Para obtener más información sobre los conceptos tratados en este tutorial, consulte los siguientes recursos:

  • Ejemplos de uso para ejemplos de código de operaciones comunes

  • Modelos Eloquent para trabajar con modelos Eloquent

Volver

Ejecute un comando