Overview
在本教程中,您可以通过构建简单的任务提醒系统来学习;了解如何在 Laravel应用程序中使用MongoDB 。该应用程序允许您创建、读取、更新和删除任务。此外,它还会根据计划时间发送有关即将执行的任务的电子邮件提醒。
先决条件
在开始本教程之前,请确保您已在开发环境中安装以下组件:
您还必须设立一个MongoDB Atlas 集群。要学习;了解如何设立集群,请参阅快速入门指南。
步骤
安装MongoDB Laravel包。
要在应用程序中使用MongoDB ,必须安装 Laravel MongoDB包并在 config/database.php文件中进行配置。
使用以下命令安装此包:
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.
配置数据库连接。
Laravel MongoDB包安装完成后,将MongoDB 数据库连接添加到 config/database.php文件以完成配置。将以下MongoDB配置添加到包含其他数据库类型配置的 connections数组:
return [ 'connections' => [ 'mongodb' => [ 'driver' => 'mongodb', 'dsn' => env('MONGODB_URI'), 'database' => 'task_reminder', ], // Other connections here ], ];
您的应用程序从 .env文件中获取 dsn 值。导航到您的 .env文件。然后,为 MONGODB_URI 创建一个值并将其设立为MongoDB连接字符串的值。
提示
要获取MongoDB连接字符串,请导航到MongoDB Atlas中的集群。单击 Connect 按钮,然后单击 Connect your application 下的 Drivers。从 Driver 选择菜单中选择“PHP”。从对话框中复制连接字符串。有关如何获取连接字符串的详细步骤,请参阅创建连接字符串。
在 .env文件中,将 DB_CONNECTION 值设立为 mongodb,使其成为应用程序的默认连接。编辑 SESSION_DRIVER 值并将其设立为 mongodb,如以下代码所示:
MONGODB_URI=mongodb+srv://YOUR_MONGODB_CONNECTION_STRING DB_CONNECTION=mongodb // Other DB_ values here ... SESSION_DRIVER=mongodb
使用 Laravel Breeze 设置身份验证。
安装并配置应用程序以与MongoDB一起使用后,设立身份验证。Laravel 通过提供 Laravel Breeze、Laravel Fortify 和 Laravel Jetstream 等包来简化身份验证实现。本教程使用 Laravel Breeze 进行身份验证。
使用 Composer 安装 Laravel Breeze:
composer require laravel/breeze --dev
安装完成后,运行以下命令:
php artisan key:generate php artisan breeze:install php artisan migrate php artisan db:seed npm install npm run dev
这会提示您选择首选的堆栈和测试包。对于本教程,请选择第一个选项,即带有 Alpine 的 Blade:
┌ 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 │ └──────────────────────────────────────────────────────────────┘
此命令将身份验证视图、路由、控制器和其他相关资源添加到应用程序。
为MongoDB配置用户模型和身份验证。
Laravel Breeze 为SQL数据库创建默认用户模型。您必须对其更新才能与MongoDB一起使用并解决速率限制兼容性问题。
打开 app/Models/User.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', ]; } }
为项目提供服务并测试MongoDB连接。
使用 Laravel 的内置服务器为项目提供服务,并确认一切正常。在 Laravel项目目录中,运行以下命令:
php artisan serve
该项目在 127.0.0.1:8000 上提供服务。如果端口 8000 已被使用,Laravel 会切换到新的可用端口,并将该端口打印到终端。
要测试身份验证系统,请选择应用程序中的 Register 按钮并创建一个新的用户帐户。这会将用户存储在MongoDB 数据库中,并允许您使用这些凭证登录。对于本教程,您可以将用户名设立为 test@example.com,将密码设置为 password。
要验证 Laravel MongoDB包是否配置正确,请创建一个路由来网络探测(ping) MongoDB 集群。将以下内容添加到 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]; });
在浏览器中访问此路由。配置正确后,您会看到“MongoDB is可访问!”消息在浏览器中。
创建任务模型和控制器。
使用以下命令为任务安排功能创建模型和控制器:
php artisan make:model Task --resource --controller
此命令使用资源方法在 app/Models目录中创建 Task 模型,并在 app/Http/Controllers目录中创建 TaskController。
导航到 routes/web.php 并添加以下代码,为 TaskController 创建路由:
use App\Http\Controllers\TaskController; // Other route definitions... Route::resource('tasks', TaskController::class)->middleware('auth');
配置任务模型。
导航到 app/Models/Task.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' ]; }
此代码将创建具有以下规范的任务模型:
命名空间后面的
use MongoDB\Laravel\Eloquent\Model声明特定于MongoDB模型。它通过使用MongoDB查询覆盖通过SQL实现的 Eloquent 功能。protected $table = 'tasks'属性是可选的。它指定用于存储此模型中的文档的MongoDB集合的名称。protected $fillable属性指定可批量分配的属性。
提示
MongoDB的独特功能之一是它不需要像关系数据库那样进行迁移。您可以直接在文档中添加新字段,而无需更新模型或创建迁移。此功能对于处理动态数据非常有用。
创建 TaskController 逻辑。
导航到 app/Http/Controllers/TaskController.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.'); } }
TaskController 类包含处理任务模型的增删改查操作的代码:
index()方法检索属于已登录用户的所有任务并将它们发送到index.blade.php文件以供显示。create()方法返回用于创建新任务的表单视图。store()方法验证输入,将登录用户的电子邮件分配给任务,并将其保存到数据库。edit()方法检索要编辑的特定任务并将其显示在编辑表单中。update()方法将编辑的任务保存到MongoDB任务集合中。destroy()方法删除特定任务。
每个操作都会重定向回任务列表,并显示一条成功消息以供用户反馈。
为任务计划程序创建视图文件。
在 resources/views目录中,创建一个名为 tasks 的文件夹,并在其中创建以下文件:
create.blade.phpedit.blade.phpindex.blade.php
导航到 resources/views/tasks/create.blade.php 并添加以下内容:
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> 69
该表单包含 title 和 description 的文本输入以及 due date 和 reminder time 的日期和时间输入。
导航到 resources/views/tasks/edit.blade.php 并添加以下内容:
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> 70
编辑表单包含与创建表单相同的输入字段,并加载当前正在编辑的任务的数据。
导航到 resources/views/tasks/index.blade.php 并添加以下内容:
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> 60
此视图包含指向创建表单的链接,并循环浏览所有任务以显示属于经过身份验证的用户的任务。
为任务添加导航链接。
从应用程序导航中添加任务功能的链接。Goresources/views/layouts/navigation.blade.php,在仪表盘导航链接后添加以下代码:
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>
点,您可以测试任务管理系统的增删改查操作。在继续下一个部分之前,请确保一切正常。
创建用于发送提醒的自定义 Artisan 命令。
要实现到期任务的提醒系统,请创建自定义 Artisan 命令以通过电子邮件发送提醒,并注册该命令以进行自动安排。
要创建自定义 Artisan 命令,请在终端中运行以下代码:
php artisan make:command SendTaskReminders
创建命令后,使用以下代码更新app/Console/Commands/SendTaskReminders.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; } }
自定义 Artisan 命令的主要逻辑是在 handle() 方法中编写的。代码使用 Carbon::now() 获取当前时间戳。
接下来,它查询数据库以获取 reminder_time 小于或等于当前时间且 reminder_time 大于或等于当前时间前 10 分钟的所有任务。在MongoDB中,所有日期都以 UTC 格式存储。即使您的服务器使用不同的时区域,您也无需更改时区域。
该查询会获取在接下来的 10 分钟内到期的所有任务。代码循环遍历结果,并向用户电子邮件发送有关将在下一个 10 分钟内到期的任务的提醒。
注意
为了使任务计划程序正常工作,必须将应用程序配置为发送电子邮件。Mailtrap.io 是测试电子邮件发送的有用工具。要学习;了解更多信息,请参阅在 Laravel 中发送电子邮件。
安排任务提醒的通知。
要完成设置,安排在上一步中创建的 Artisan 命令每分钟运行。此方法每分钟自动运行 php artisan app:send-task-reminders。
导航到 routes/console.php 并添加以下代码:
// ...existing code ... Schedule::command('app:send-task-reminders')->everyMinute();
要测试其是否有效,运行以下命令:
php artisan schedule:run
在生产服务器上,您必须配置一个 cron作业以定期运行php artisan schedule:run 命令。
在基于Linux或 Unix 的服务器上,可以使用以下命令打开 cron 配置文件:
crontab -e
将以下代码添加到 cron 配置标签页:
* * * * * /usr/bin/php /path-to-your-project/artisan schedule:run >> /dev/null 2>&1
将 /usr/bin/php 替换为PHP二进制文件的路径,将 /path-to-your-project 替换为服务器上 Laravel项目的完整路径。保存并退出文件。
要验证 cron作业是否设立正确,运行以下命令:
crontab -l
总结
您现在拥有一个使用 Laravel 和 MongoDB 的任务计划应用程序。本教程演示了如何完成以下操作:
配置 Laravel项目以使用MongoDB
为任务计划程序实现CRUD功能
为提醒系统创建自定义 Laravel Artisan 命令
安排任务以定期运行Artisan 命令
在基于 Linux 的服务器上配置 cron作业
后续步骤
要学习;了解有关本教程所涵盖概念的更多信息,请参阅以下资源:
使用示例,了解常见操作的代码示例
用于处理 Eloquent 模型的 Eloquent Model 类