Популярність Laravel останнім часом зросла, адже все більше розробників починають використовувати цю технологію. Laravel має зрозумілий синтаксис, що підвищує продуктивність, дозволяючи розробнику зосередитися на основних функціях свого додатку, не витрачаючи час на рутинні завдання, такі як автентифікація та надсилання електронних листів. У Laravel існує жвава спільнота користувачів і безліч навчальних матеріалів.
Новостворені програми на Laravel налаштовані на використання реляційних баз даних. Мета цього уроку — показати, як використовувати MongoDB у додатку Laravel. Ми розробимо просту систему нагадування про завдання для досягнення цієї мети.
Для ефективного проходження цього уроку вам знадобляться наступні інструменти та технології:
Щоб працювати з MongoDB, потрібно налаштувати наше середовище розробки. Переконайтеся, що всі необхідні залежності розробки встановлені та налаштовані. Вам знадобиться:
Налаштування проекту
Щоб розпочати створення нашої системи нагадування, перше, що потрібно зробити, це створити новий проект Laravel. Це можна зробити за допомогою Composer, виконуючи наступну команду:
composer create-project laravel/laravel LaravelMongodbProject
cd LaravelMongodbProject
Встановлення пакету MongoDB для Laravel
Новий проект Laravel за замовчуванням налаштований на реляційні бази даних, такі як MySql і PostgreSQL. MongoDB не підтримується в Laravel за замовчуванням, тому потрібно встановити пакет Laravel MongoDB та здійснити деяку конфігурацію у файлі config/database.php. Виконайте команду:
composer require mongodb/laravel-mongodb
Налаштуйте базу даних
Після завершення встановлення пакету MongoDB для Laravel, наступний крок — додати підключення до нашої бази даних MongoDB у файл config/database.php. Скопіюйте код нижче і вставте в масив connections
, який містить конфігурації для інших типів баз даних:
return [
'connections' => [
'mongodb' => [
'driver' => 'mongodb',
'dsn' => env('MONGODB_URI'),
'database' => 'YOUR_DATABASE_NAME',
],
//Інші існуючі підключення залиште
],
Давайте пояснимо. Значення dsn
береться з файлу .env. У файлі .env створіть значення для 'MONGODB_URI'
та встановіть його у вигляді рядка підключення до MongoDB Atlas:
MONGODB_URI="<<MONGODB_ATLAS_CONNECTION_STRING>>"
DB_CONNECTION=mongodb
Автентифікація з Laravel Breeze
Ми встановили та налаштували наш додаток для роботи з MongoDB. Тепер давайте перейдемо до автентифікації. Laravel спрощує реалізацію автентифікації за допомогою пакетів, таких як Laravel Breeze, Laravel Fortify та Laravel Jetstream. У цьому уроці ми будемо використовувати 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
Ця команда запропонує вам вибрати свій стек і пакет тестування, як показано нижче. Для цілей цієї статті ми виберемо перший варіант (Blade та 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
Після цього буде додано автентифікаційні уявлення, маршрути, контролери та інші пов’язані ресурси у ваш додаток.
На даний момент давайте запустимо проект за допомогою вбудованого сервера Laravel і перевіримо, що все правильно працює. Використовуйте команду:
php artisan serve
Проект повинен працювати на 127.0.0.1:8000
. Якщо порт 8000
вже зайнятий, Laravel перейде на новий доступний порт. Якщо все було зроблено правильно, ваш екран має виглядати як на зображенні нижче:
Ви можете увійти за такими обліковими даними: електронна адреса "test@example.com" та пароль "password".
Щоб перевірити, чи пакет Laravel MongoDB налаштовано правильно, давайте створимо маршрут для підключення до нашого кластера MongoDB. Додайте наступне в route/web.php:
Route::get('/ping', function (Request $request) {
$connection = DB::connection('mongodb');
try {
$connection->command(['ping' => 1]);
$msg = 'MongoDB доступний!';
} catch (Exception $e) {
$msg = 'Ви не підключені до MongoDB. Помилка: ' . $e->getMessage();
}
return ['msg' => $msg];
});
Перейдіть за цим маршрутом у браузері. Ваш екран має виглядати як на зображенні нижче, якщо все було зроблено правильно:
Давайте створимо нашу модель і контролер для функції планування завдань. Для цього використовуйте команду:
php artisan make:model Task --resource --controller
Команда вище створить модель Task
у директорії app/Models і контролер TaskController
у директорії app/Http/Controllers з ресурсними методами.
Давайте створимо маршрут для TaskController
. Перейдіть до routes/web.php і додайте наступне:
use App\Http\Controllers\TaskController;
Route::resource('tasks', TaskController::class)->middleware('auth');
Тепер давайте модифікуємо вміст моделі завдання на наші потреби. Перейдіть до app/Models/Task.php та замініть вміст на наступний:
<?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. Він замінює реалізації Eloquent, що використовують SQL, на запити MongoDB.protected $table = 'tasks'
є необов’язковим. Це назва колекції MongoDB, яка використовується для зберігання документів з цієї моделі.protected $fillable = ['title', 'description', 'due_date', 'email', 'reminder_time']
визначає масово доступні властивості.Однією з унікальних особливостей MongoDB є те, що вона не потребує міграцій, як реляційні бази даних. Це означає, що ви можете безпосередньо додавати нові поля до своїх документів, не оновлюючи модель або створюючи міграції. Це особливо корисно для роботи з динамічними даними.
Тепер давайте модифікуємо наш контролер. Перейдіть до app/Http/Controllers/TaskController.php і оновіть вміст за допомогою коду нижче:
<?php
namespace App\Http\Controllers;
use App\Models\Task;
use Carbon\Carbon;
use Illuminate\Http\Request;
class TaskController extends Controller
{
/**
* Відображення списку ресурсів.
*/
public function index()
{
$tasks = Task::where('email', auth()->user()->email)->get();
return view('tasks.index', compact('tasks'));
}
/**
* Показати форму для створення нового ресурсу.
*/
public function create()
{
return view('tasks.create');
}
/**
* Зберегти новостворений ресурс у сховищі.
*/
public function store(Request $request)
{
$request->validate([
'title' => 'required|string|max:255',
'description' => 'nullable|string',
'due_date' => 'required|date',
'reminder_time' => 'required|date',
]);
$data = $request->all();
$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', 'Завдання успішно створено.');
}
/**
* Відобразити вказаний ресурс.
*/
public function show(string $id)
{
//
}
/**
* Показати форму для редагування вказаного ресурсу.
*/
public function edit(string $id)
{
$tasks = Task::where('id', $id)->get();
return view('tasks.edit', ['tasks' => $tasks]);
}
/**
* Оновити вказаний ресурс у сховищі.
*/
public function update(Request $request, string $id)
{
$task = Task::findOrFail($id);
$data = $request->all();
$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', 'Завдання успішно оновлено.');
}
/**
* Видалити вказаний ресурс зі сховища.
*/
public function destroy(string $id)
{
$task = Task::findOrFail($id);
$task->delete();
return redirect()->route('tasks.index')->with('success', 'Завдання успішно видалено.');
}
}
Наш новостворений TaskController
містить код, який обробляє CRUD-операції нашої моделі завдання. Метод index отримує всі завдання, що належать увімкненому користувачеві, і передає їх до файлу index.blade.php для відображення на фронті.
Метод create повертає форму для створення нового завдання, а метод store перевіряє вхідні дані, призначає електронну адресу увімкненого користувача завданню та зберігає його в базі даних.
Для оновлень, метод edit отримує конкретне завдання для редагування та відображає його у формі редагування. Коли ця форма надсилається, вона викликає метод update, який зберігає відредаговане завдання в колекції завдань MongoDB.
Метод destroy видаляє конкретне завдання. Кожна операція перенаправляє назад до списку завдань з повідомленням про успішність для зворотного зв’язку користувача.
Давайте створимо файли вигляду для нашого планувальника завдань. У директорії resources/views створіть папку з назвою /tasks та створіть у ній такі файли:
Відкрийте resources/views/create.blade.php та замініть вміст сторінки на:
<x-app-layout>
<x-slot name="header">
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
{{ __('Завдання') }}
</h2>
</x-slot>
<div class="py-12">
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
<div class="bg-white overflow-hidden shadow-sm sm:rounded-lg">
<div class="container mx-auto p-4">
<h2 class="text-2xl font-bold mb-4">Створити нове завдання</h2>
<form action="{{ route('tasks.store') }}" method="POST">
@csrf
<div class="mb-4">
<label for="title" class="block text-gray-700">Назва:</label>
<input type="text" name="title" id="title" required class="border border-gray-300 p-2 w-full" value="{{ old('title') }}">
@error('title')
<p class="text-red-500">{{ $message }}</p>
@enderror
</div>
<div class="mb-4">
<label for="description" class="block text-gray-700">Опис:</label>
<textarea name="description" id="description" class="border border-gray-300 p-2 w-full">{{ old('description') }}</textarea>
</div>
<div class="mb-4">
<label for="due_date" class="block text-gray-700">Дедлайн:</label>
<input type="date" name="due_date" id="due_date" required class="border border-gray-300 p-2 w-full" value="{{ old('due_date') }}">
@error('due_date')
<p class="text-red-500">{{ $message }}</p>
@enderror
</div>
<div class="mb-4">
<label for="reminder_time" class="block text-gray-700">Час нагадування:</label>
<input type="datetime-local" name="reminder_time" id="reminder_time" class="border border-gray-300 p-2 w-full" value="{{ old('reminder_time') }}">
</div>
<button type="submit" class="bg-green-600 text-white text-gray-399 p-2 border rounded">Створити завдання</button>
</form>
</div>
</div>
</div>
</div>
</x-app-layout>
У наведеному коді ми додали HTML
форму створення. Форма містить текстове поле для назви
та опису
, а також поля дати та часу для дедлайну
та часу нагадування
. Якщо ваш код правильний, ваш екран має виглядати як на зображенні нижче.
Повторіть те саме для edit.blade.php. Перейдіть до resources/views/edit.blade.php і додайте код нижче:
<x-app-layout>
<x-slot name="header">
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
{{ __('Редагувати завдання') }}
</h2>
</x-slot>
<div class="py-12">
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
<div class="bg-white overflow-hidden shadow-sm sm:rounded-lg">
<div class="p-6 text-gray-900">
@foreach($tasks as $task)
<form action="{{ route('tasks.update', $task->id) }}" method="POST">
@csrf
@method('PUT')
<div class="mb-4">
<label for="title" class="block text-gray-700">Назва:</label>
<input type="text" name="title" id="title" required class="border border-gray-300 p-2 w-full" value="{{ old('title', $task->title) }}">
@error('title')
<p class="text-red-500">{{ $message }}</p>
@enderror
</div>
<div class="mb-4">
<label for="description" class="block text-gray-700">Опис:</label>
<textarea name="description" id="description" class="border border-gray-300 p-2 w-full">{{ old('description', $task->description) }}</textarea>
</div>
<div class="mb-4">
<label for="due_date" class="block text-gray-700">Дедлайн:</label>
<input type="date" name="due_date" id="due_date" required class="border border-gray-300 p-2 w-full" value="{{ old('due_date', $task->due_date) }}">
@error('due_date')
<p class="text-red-500">{{ $message }}</p>
@enderror
</div>
<div class="mb-4">
<label for="reminder_time" class="block text-gray-700">Час нагадування:</label>
<input type="datetime-local" name="reminder_time" id="reminder_time" class="border border-gray-300 p-2 w-full" value="{{ old('reminder_time', $task->reminder_time) }}">
</div>
<button type="submit" class="bg-blue-500 text-white p-2 rounded">Оновити завдання</button>
</form>
@endforeach
</div>
</div>
</div>
</div>
</x-app-layout>
Форма edit
містить ті самі поля введення, що й форма create
вище. Вона заповнена даними завдання, яке редагується.
Наостанок перейдіть до resources/views/index.blade.php і замініть вміст на код нижче:
<x-app-layout>
<x-slot name="header">
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
{{ __('Завдання') }}
</h2>
</x-slot>
<div class="py-12">
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
<div class="bg-white overflow-hidden shadow-sm sm:rounded-lg">
<div class="p-6 text-gray-900">
<div class="mb-2">
<a href="{{ route('tasks.create') }}" class="p-2 border mb-4">Створити нове завдання</a>
</div>
<ul class="mt-4">
@foreach ($tasks as $task)
<div class="mt-2">
<hr>
</div>
<li>
<h1 class="text-2xl">
<strong>{{ $task->title }}</strong> - Дедлайн: {{ $task->due_date }}
</h1>
<p class="text-gray-600">
{{ $task->description }}
</p>
<div class="flex gap-2 mt-4">
<div class="p-2 text-white bg-gray-700">
<a href="{{ route('tasks.edit', $task->id) }}">Редагувати</a>
</div>
<div class="p-2 text-white bg-red-700 rounded">
<form action="{{ route('tasks.destroy', $task->id) }}" method="POST" style="display:inline;">
@csrf
@method('DELETE')
<button type="submit">Видалити</button>
</form>
</div>
</div>
</li>
@endforeach
</ul>
</div>
</div>
</div>
</div>
</x-app-layout>
У наведеному коді ми додали посилання на форму create
. Він також проходить через всі нагадування і відображає ті, що належать цьому користувачеві.
Додати маршрут
Тепер нам потрібно додати посилання на функцію завдань у навігації нашого додатка. Відкрийте resources/views/layouts/navigation.blade.php і додайте наступний рядок коду одразу після посилання на панель приладів.
//...існуючий код ...
<div class="hidden space-x-8 sm:-my-px sm:ms-10 sm:flex">
<x-nav-link :href="route('tasks.index')":active="request()->routeIs('tasks.index')">
{{ __('Завдання') }}
</x-nav-link>
</div>
На цьому етапі ми повинні протестувати CRUD-операції нашої системи керування завданнями. Переконайтеся, що все працює правильно, перш ніж переходити до наступного розділу.
Налаштування нагадувань з використанням завдань Laravel
Давайте перейдемо до реалізації системи нагадування для термінових завдань. Для цього ми:
php artisan make:command SendTaskReminders
Після створення команди, оновіть вміст файлу app/Console/Commands/SendTaskReminders.php кодом нижче:
<?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
{
/**
* Назва та підпис команди консолі.
*
* @var string
*/
protected $signature = 'app:send-task-reminders';
/**
* Опис команди консолі.
*
* @var string
*/
protected $description = 'Опис команди';
/**
* Виконати команду консолі.
*/
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 = <<title}
Опис: {$task->description}
Дедлайн: {$task->due_date}
Будь ласка, переконайтеся, що ви завершите його вчасно!
З повагою,
Ваш додаток нагадування про завдання
EOF;
Mail::raw($emailBody, function ($message) use ($task) {
$message->to($task->email)
->subject("Нагадування про завдання: {$task->title}");
});
$task->last_notification_date = $now;
$task->save();
$this->info("Лист-нагадування надіслано для завдання: {$task->title}");
}
return self::SUCCESS;
}
}
Основна логіка нашої команди Artisan написана в методі handle()
. У коді вище ми отримуємо поточний штамп часу за допомогою Carbon::now()
.
Далі ми запитуємо базу даних, щоб отримати всі завдання, де reminder_time
менше або дорівнює поточному часу (значення $now
) та де reminder_time
більше або дорівнює 10 хвилинам до цього часу, з цією рядком коду: 'reminder_time','>=',$now->clone()->subMinutes(10)
. У MongoDB всі дати зберігаються в UTC. Навіть якщо ваш сервер використовує інший часовий пояс, вам не потрібно цього змінювати.
Для більшого пояснення, припустимо, що поточний час $now = 2024-10-22 15:00:00
. Запит на нагадування про завдання отримує всі завдання між 2024-10-22 14:50:00
та 2024-10-22 15:00:00
. Ми отримуємо всі завдання, термін виконання яких настане через 10 хвилин.
Потім ми проходимо через результат і надсилаємо нагадування електронною поштою користувачам про завдання, які будуть терміновими протягом наступних 10 хвилин.
Щоб планувальник завдань працював правильно, ви повинні налаштувати свій додаток на відправку електронних листів.
Mailtrap.io — чудовий інструмент для тестування надсилання електронних листів. Отримайте детальну інформацію про як налаштувати свій додаток для відправки електронних листів за допомогою Mailtrap.
Планування сповіщень для нагадувань про завдання
Щоб закрити все, нам потрібно запланувати виконання команди Artisan, яку ми створили вище, на кожну хвилину. Вважайте це способом автоматичного запуску php artisan app:send-task-reminders
щоранку.
Є кілька способів запланювати виконання завдання в Laravel. У цьому уроці ми працюємо з версією Laravel 11.9, яка є найновішою версією на момент написання цього матеріалу. Щоб продовжити, перейдіть до routes/console.php і додайте наступне:
//...існуючий код ...
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
шляхом до вашого PHP-бінарного файлу та /path-to-your-project
на повний шлях до вашого проекту Laravel на сервері, а потім збережіть і вийдіть.
Ви можете переконатися, що все працює, набравши цю команду:
crontab -l
Висновок
Ми підійшли до завершення цього уроку; чудова робота, якщо ви слідкували за нами. Для підсумку, в цьому уроці ми пройшли процес створення планувальника завдань у Laravel та MongoDB. Декілька ключових елементів реалізації:
Знайдіть проект на GitHub. Не соромтеся клонувати його, зареєструватися на MongoDB Atlas та налаштувати його під ваші потреби. Для додаткової підтримки приєднуйтесь до спільноти розробників MongoDB.