개요
In this tutorial, you can learn how to use MongoDB in a Laravel application by building a simple task reminder system. The application allows you to create, read, update, and delete tasks. Additionally, it sends email reminders for upcoming tasks based on a scheduled time.
전제 조건
Before you begin this tutorial, ensure you have the following components installed in your development environment:
You must also set up a MongoDB Atlas cluster. To learn how to set up a cluster, see the Getting Started guide.
단계
Install the MongoDB Laravel package.
To use MongoDB in your application, you must install the Laravel MongoDB package and configure it in the config/database.php file.
Install the package by using the following command:
composer require mongodb/laravel-mongodb
팁
If you encounter an error when you run the preceding command, ensure that the MongoDB PHP extension is installed. To learn how to install, see the Install the MongoDB PHP extension step in the Get Started guide.
Configure the database connection.
After the Laravel MongoDB package installation completes, add your MongoDB database connection to the config/database.php file to complete the configuration. Add the following MongoDB configuration to the connections array that contains configurations for other database types:
return [ 'connections' => [ 'mongodb' => [ 'driver' => 'mongodb', 'dsn' => env('MONGODB_URI'), 'database' => 'task_reminder', ], // Other connections here ], ];
Your application obtains the dsn value from the .env file. Navigate to your .env file. Then, create a value for MONGODB_URI and set it to the value of your MongoDB connection string.
팁
To obtain your MongoDB connection string, navigate to your cluster in MongoDB Atlas. Click the Connect button and click the Drivers under Connect your application. Select "PHP" from the Driver selection menu. Copy the connection string from the dialog box. For detailed steps on how to obtain your connection string, see create-a-connection-string.
In your .env file, set the DB_CONNECTION value to mongodb to make it the default connection for your application. Edit the SESSION_DRIVER value and set it to mongodb as shown in the following code:
MONGODB_URI=mongodb+srv://YOUR_MONGODB_CONNECTION_STRING DB_CONNECTION=mongodb // Other DB_ values here ... SESSION_DRIVER=mongodb
Set up authentication with Laravel Breeze.
After installing and configuring your application to work with MongoDB, set up authentication. Laravel simplifies authentication implementation by providing packages such as Laravel Breeze, Laravel Fortify and Laravel Jetstream. This tutorial uses Laravel Breeze for authentication.
Install Laravel Breeze by using Composer:
composer require laravel/breeze --dev
After the installation completes, run the following commands:
php artisan key:generate php artisan breeze:install php artisan migrate php artisan db:seed npm install npm run dev
This prompts you to choose your preferred stack and testing package. For this tutorial, select the first option, Blade with 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 │ └──────────────────────────────────────────────────────────────┘
This command adds authentication views, routes, controllers, and other related resources to your application.
Configure the User model and authentication for MongoDB.
Laravel Breeze creates a default User model for SQL databases. You must update it to work with MongoDB and resolve rate limiting compatibility issues.
Open app/Models/User.php and replace its contents with the following:
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', ]; } }
Serve the project and test the MongoDB connection.
Serve the project by using Laravel's built-in server and confirm that everything works properly. In the Laravel project directory, run the following command:
php artisan serve
The project serves at 127.0.0.1:8000. If port 8000 is already in use, Laravel switches to a new available port, which it prints to the terminal.
To test the authentication system, select the Register button in your application and create a new user account. This stores the user in your MongoDB database and allows you to log in with those credentials. For this tutorial, you can set the username to test@example.com and the password to password.
To verify that the Laravel MongoDB package was configured properly, create a route to ping your MongoDB cluster. Add the following to 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]; });
Visit this route in your browser. With the correct configuration, you see the message "MongoDB is accessible!" in your browser.
Create the task model and controller.
Create the model and controller for the task scheduling feature by using the following command:
php artisan make:model Task --resource --controller
This command creates the Task model in the app/Models directory and the TaskController in the app/Http/Controllers directory with resource methods.
Create a route for the TaskController by navigating to routes/web.php and adding the following code:
use App\Http\Controllers\TaskController; // Other route definitions... Route::resource('tasks', TaskController::class)->middleware('auth');
Configure the Task model.
Navigate to app/Models/Task.php and replace the contents of the file with the following code:
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' ]; }
This code creates the task model with the following specifications:
The
use MongoDB\Laravel\Eloquent\Modelstatement after the namespace is specific to MongoDB models. It overrides the Eloquent features implemented with SQL by using MongoDB queries.The
protected $table = 'tasks'property is optional. It specifies the name of the MongoDB collection used to store the documents from this model.The
protected $fillableproperty specifies the mass-assignable properties.
팁
One of the unique features of MongoDB is that it doesn't require migrations like relational databases. You can add new fields directly to your documents without updating the model or creating migrations. This feature is useful for handling dynamic data.
Create the TaskController logic.
Navigate to app/Http/Controllers/TaskController.php and update the content with the following code:
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.'); } }
The TaskController class contains code that handles the CRUD operations of the task model:
The
index()method retrieves all tasks belonging to the logged-in user and sends them to theindex.blade.phpfile for display.The
create()method returns the form view for creating a new task.The
store()method validates input, assigns the logged-in user's email to the task, and saves it to the database.The
edit()method retrieves the specific task to be edited and displays it in an edit form.The
update()method saves the edited task to the MongoDB task collection.The
destroy()method deletes a specific task.
Each operation redirects back to the task list with a success message for user feedback.
Create view files for the task scheduler.
In the resources/views directory, create a folder named tasks and create the following files in it:
create.blade.phpedit.blade.phpindex.blade.php
Navigate to resources/views/tasks/create.blade.php and add the following content:
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>
The form contains text inputs for title and description and date and time inputs for due date and reminder time.
Navigate to resources/views/tasks/edit.blade.php and add the following content:
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>
The edit form contains the same input fields as the create form and is loaded with the data of the task currently being edited.
Navigate to resources/views/tasks/index.blade.php and add the following content:
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>
This view includes a link to the create form and loops through all the tasks to display those belonging to the authenticated user.
Add navigation link for tasks.
Add a link to the task feature from your application navigation. Go to resources/views/layouts/navigation.blade.php and add the following code after the dashboard navigation link:
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>
At this point, you can test the CRUD operations of your task management system. Ensure that everything works correctly before you move on to the next section.
Create a custom Artisan command for sending reminders.
To implement the reminder system for due tasks, create a custom Artisan command to send reminders through email and register the command for automatic scheduling.
To create a custom Artisan command, run the following code in your terminal:
php artisan make:command SendTaskReminders
After you create the command, update the contents of the app/Console/Commands/SendTaskReminders.php file with the following code:
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; } }
The main logic of the custom Artisan command is written in the handle() method. The code gets the current timestamp by using Carbon::now().
Next, it queries the database to get all the tasks where reminder_time is less than or equal to the current time and where reminder_time is greater than or equal to 10 minutes before the current time. In MongoDB, all dates are stored in UTC. Even if your server uses a different time zone, you don't need to change the time zone.
The query fetches all tasks that are due in the next 10 minutes. The code loops through the results and sends reminders to the user emails of tasks that will be due in the next 10 minutes.
참고
For the task scheduler to work properly, you must configure your application to send emails. Mailtrap.io is a useful tool to test email sending. To learn more, see Send Email in Laravel.
Schedule notifications for task reminders.
To complete the setup, schedule the Artisan command created in the previous step to run every minute. This approach automatically runs php
artisan app:send-task-reminders every minute.
Navigate to routes/console.php and add the following code:
// ...existing code ... Schedule::command('app:send-task-reminders')->everyMinute();
To test that this works, run the following command:
php artisan schedule:run
On a production server, you must configure a cron job to run the php
artisan schedule:run command at regular intervals.
On a Linux- or Unix-based server, you can open your cron configuration file by using the following command:
crontab -e
Add the following code to the cron configuration tab:
* * * * * /usr/bin/php /path-to-your-project/artisan schedule:run >> /dev/null 2>&1
Replace /usr/bin/php with the path to your PHP binary and /path-to-your-project with the full path to your Laravel project on your server. Save and exit the file.
To verify that the cron job is set up correctly, run the following command:
crontab -l
요약
You now have a task scheduler application that uses Laravel and MongoDB. This tutorial demonstrated how to complete the following actions:
Configure a Laravel project to work with MongoDB
Implement CRUD features for the task scheduler
Create a custom Laravel Artisan command for the reminder system
Schedule a task to run the Artisan command at intervals
Configure the cron job on a Linux-based server
다음 단계
To learn more about the concepts covered in this tutorial, see the following resources:
Usage Examples for code examples of common operations
Eloquent Models for working with Eloquent models