Overview
在本教程中,您可以通过构建简单的任务提醒系统来学习;了解如何在 Laravel应用程序中使用MongoDB 。该应用程序允许您创建、读取、更新和删除任务。此外,它还会根据计划时间发送有关即将执行的任务的电子邮件提醒。
先决条件
在开始本教程之前,请确保您已在开发环境中安装以下组件:
您还必须设立一个MongoDB Atlas 集群。要学习;了解如何设立集群,请参阅快速入门指南。
步骤
安装MongoDB Laravel包。
要在应用程序中使用MongoDB ,必须安装 Laravel MongoDB包并在 config/database.php文件中进行配置。
使用以下命令安装此包:
composer require mongodb/laravel-mongodb
提示
如果在运行上述命令时遇到错误,请确保已安装MongoDB PHP扩展。要学习如何安装,请参阅 安装 MongoDB PHP 扩展 步骤,详见入门指南。
配置数据库连接。
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>
该表单包含 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>
编辑表单包含与创建表单相同的输入字段,并加载当前正在编辑的任务的数据。
导航到 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>
此视图包含指向创建表单的链接,并循环浏览所有任务以显示属于经过身份验证的用户的任务。
为任务添加导航链接。
从应用程序导航中添加任务功能的链接。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作业
后续步骤
要学习;了解有关本教程所涵盖概念的更多信息,请参阅以下资源:
使用示例,了解常见操作的代码示例