Додавання автозаповнення до ваших Laravel-додатків

Перекладено ШІ
Оригінал: Laravel News
Оновлено: 04 вересня, 2025
Забезпечення зручного пошуку у веб-додатках стало важливим аспектом для покращення користувацького досвіду. У нашій статті ми покажемо, як реалізувати функцію пошуку фільмів у застосунку на базі Laravel і MongoDB Atlas, щоб користувачі могли шукати улюблені фільми всього за кілька натиснень клавіші. Читайте далі, щоб дізнатися, як створити потужний пошуковий функціонал у вашому проєкті
```html

Реалізація функції пошуку стала надзвичайно важливою для веб-додатків, які цінують зручність користувачів, адже це дозволяє шукати необхідну інформацію без нескінченного прокручування

У цьому посібнику ми створимо додаток для перегляду фільмів, використовуючи MongoDB Atlas Search та Laravel (популярний PHP-фреймворк), щоб побудувати зручну текстову функцію пошуку, що дозволить користувачам знаходити фільми, вводячи кілька символів

# Чому слід використовувати MongoDB Atlas Search?

Гнучка схема MongoDB, можливості Atlas Search і потужні запитувачі в поєднанні з експресивним синтаксисом Laravel дозволяють нам швидко впроваджувати розширені функції пошуку

Джерело цього додатку можна знайти на GitHub

# Передумови

# Налаштування бази даних

Щоб налаштувати наше середовище MongoDB, створіть кластер бази даних, налаштуйте доступ до бази та отримайте рядок підключення, дотримуючись інструкцій з офіційної документації MongoDB

# Визначення бази даних для роботи

Після налаштування кластера завантажте доказові дані, з якими ми будемо працювати, та отримайте наш рядок підключення

Ваш рядок підключення має виглядати так:

mongodb+srv://user:password@cluster0.xxxxx.mongodb.net

Після виконання вказаних вище кроків доказові дані повинні бути завантаженими у ваш кластер. Якщо ні, ознайомтеся з документацією про завантаження доказових даних

Після успішного завантаження даних у нас повинна бути база даних під назвою sample_mflix у нашому кластері. Ми будемо працювати з колекцією movies у базі даних

# Встановлення пакетів Laravel і MongoDB та налаштування середовища

Після налаштування бази даних створимо проект Laravel за допомогою Composer. Для цього вам потрібно переконатися, що PHP, Laravel, Node, npm, Composer і розширення PHP для MongoDB коректно налаштовані. Посилання нижче будуть корисними

Ознайомтеся з інструкціями з інтеграції MongoDB та Laravel. Вони пояснюють, як налаштувати середовище розробки Laravel-MongoDB. Далі ми розглянемо створення додатку Laravel і налаштування MongoDB

# Створення проекту Laravel

Коли наше середовище розробки готове, створимо проект Laravel за допомогою Composer. Виконайте наступну команду в терміналі у вибраному каталозі

composer create-project laravel/laravel movieapp

Ця команда створить новий проект Laravel у папці movieapp. Після завершення встановлення ваша структура папок повинна виглядати так:

Запустіть сервер, виконуючи наступну команду в терміналі

cd movieapp
php artisan serve

Коли сервер запуститься, він буде доступний за адресою http://localhost:8000/. Ви повинні побачити стартову сторінку Laravel, як показано нижче

Також у новому вікні терміналу запустіть команду для запуску фронтенд-сервера.

npm install
npm run dev

Тепер, коли наш сервер запущений, давайте підключимося до нашого кластера MongoDB

# Підключення сервера Laravel до MongoDB

Щоб підключити сервер до раніше створеного кластера MongoDB, дотримуйтеся таких кроків:

  1. По-перше, за допомогою Composer додайте пакет Laravel MongoDB до додатку. У командному рядку перейдіть до каталогу проекту й виконайте наступну команду
composer require mongodb/laravel-mongodb

Це додасть пакет MongoDB до каталогу vendor

  1. Додайте ще один пакет — mongodb/builder. Ми використовуватимемо його для побудови конвеєра агрегації. Виконайте наступну команду для додавання mongodb/builder
composer require mongodb/builder:^0.2
  1. Перейдіть до файлу .env. Оновіть значення DB_CONNECTION та додайте DB_URI так:
DB_CONNECTION=mongodb
DB_URI=mongodb_connection_string_here

Замініть текст mongodb_connection_string_here на ваш рядок підключення до бази даних

  1. Перейдіть до файлу config/database.php та оновіть масив connections так:
'connections' => [
     'mongodb' => [
         'driver' => 'mongodb',
         'dsn' => env('DB_URI'),
         'database' => 'sample_mflix',
     ],
  1. В тому ж файлі config/database.php оновіть рядок default так:
'default' => env('DB_CONNECTION'),

Це налаштує MongoDB як основне з'єднання для додатку

Тепер давайте створимо маршрут у /routes/web.php:

<?php
use Illuminate\Support\Facades\Route;
// Імпортуємо клас Request
use Illuminate\Http\Request;
// Імпортуємо фасад DB
use Illuminate\Support\Facades\DB;
 
Route::get('/', function () {
   return view('welcome');
});
 
// Додаємо маршрут перевірки з'єднання
Route::get('/connect', function (Request $request) {
   $connection = DB::connection('mongodb');
   $msg = 'MongoDB доступний!';
 
   try {
         $connection->getMongoClient()
             ->selectDatabase($connection->getDatabaseName())
             ->command(['ping' => 1]);
   } catch (\Exception $e) {
       $msg = 'MongoDB недоступний. Помилка: ' . $e->getMessage();
   }
 
   return response()->json(['msg' => $msg]);
});

У терміналі виконайте php artisan route

Ви повинні побачити маршрут у списку. У браузері перейдіть за адресою http://localhost:8000/connect/. Ви повинні побачити повідомлення про успіх {"msg":"MongoDB доступний!"}

# Створення моделі фільму (модель Eloquent для MongoDB)

Створимо Eloquent модель для нашої бази даних MongoDB під назвою "Movie", оскільки ми працюватимемо з колекцією movies. За замовчуванням Eloquent вважатиме, що модель Movie містить документи в колекції movies. Виконайте команду в каталозі проекту, щоб створити модель Movie

php artisan make:model Movie

Після завершення команди буде створено файл /app/Models/Movie.php. Відкрийте файл і оновіть його так:

<?php
namespace App\Models;
 
use MongoDB\Laravel\Eloquent\Model;
 
class Movie extends Model
{
    protected $connection = 'mongodb';
}

Тепер давайте відобразимо кілька фільмів на нашій домашній сторінці
Для цього оновіть файл /routes/web.php:

<?php
use Illuminate\Support\Facades\Route;
use App\Models\Movie;
 
Route::get('/', function () {
   $movies = Movie::limit(20)->get(); // Отримати тільки 20 фільмів
   return view('welcome', [
       'movies' => $movies
   ]);
});

Потім оновіть тег body у файлі app/resources/views/welcome.blade.php так:

<body class="font-sans antialiased dark:bg-black dark:text-white/50">
    <div class="bg-gray-50 text-black/50 dark:bg-black dark:text-white/50">
        <img id="background" class="absolute -left-20 top-0 max-w-[877px]"
            src="https://laravel.com/assets/img/welcome/background.svg" alt="Laravel background" />
        <div
            class="relative min-h-screen flex flex-col items-center justify-center selection:bg-[#FF2D20] selection:text-white">
            <div class="relative w-full max-w-2xl px-6 lg:max-w-7xl">
                <div id="movie-list" class=' w-full flex gap-6 justify-around items-center flex-wrap'>
                </div>
            </div>
        </div>
        <script>
            let movies = @json($movies);
            displayMovies(movies)
 
            function displayMovies(movies) {
                const movieListDiv = document.getElementById('movie-list');
                movieListDiv.innerHTML = movies.map(movie => `
                    <div class="movie-card max-w-sm bg-green-500 border border-gray-200 rounded-lg shadow dark:bg-gray-800 dark:border-gray-700">
                        <div class="h-[400px]">
                            <img class="rounded-t-lg object-cover w-full h-full" src="${movie.poster}" alt="${movie.title}" />
                        </div>
                        <div class="p-5">
                            <a href="#">
                                <h5 class="mb-2 text-2xl font-bold tracking-tight text-gray-900 dark:text-white line-clamp-1">
                                    ${movie.title}
                                </h5>
                            </a>
                            <p class="mb-3 font-normal text-gray-700 dark:text-gray-400 line-clamp-2">${movie.plot}</p>
                            <a href="#"
                                class="inline-flex items-center px-3 py-2 text-sm font-medium text-center text-white bg-blue-700 rounded-lg hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800">
                                Дивитися більше
                            </a>
                        </div>
                    </div>
                `).join('');
            }
        </script>
</body>

Оновіть вашу програму за адресою http://localhost:8000. Ви повинні побачити список фільмів на екрані, як показано нижче

Якщо ви отримали помилку E11000 duplicate key error collection: sample_mflix.sessions index: user_id_1 dup key: { user_id: null }, перейдіть до колекції sessions у базі даних sample_mflix, очистіть документ і спробуйте знову

Тепер, коли застосунок працює, давайте перейдемо до панелі керування MongoDB Atlas, щоб створити індекс для пошуку. Але спочатку…

# Створення індексу Atlas Search

Щоб реалізувати функцію пошуку фільмів за їх заголовками, створимо індекс пошуку на панелі керування MongoDB Atlas

У створеному раніше кластері перейдіть до вкладки Browse collections, далі до вкладки Atlas Search та натисніть Create index праворуч на сторінці пошуку. На цій сторінці виберіть JSON editor під Atlas Search, натисніть Next, введіть ім'я індексу (у нашому випадку movie_search), виберіть колекцію films з бази даних sample_mflix та оновіть JSON editor так, як показано нижче. Натисніть Next

{
  "mappings": {
    "dynamic": false,
    "fields": {
      "title": {
        "type": "string"
      }
    }
  }
}

# Створення індексу автозаповнення Atlas Search

Наступним кроком створимо ще один індекс, але цього разу тип буде автозаповнення. Ми будемо використовувати його, щоб реалізувати можливість підказки назв фільмів, коли користувач вводить текст

Створіть ще один індекс, дайте йому ім'я (у нашому випадку movie_title_autocomplete), та оновіть JSON editor так:

{
  "mappings": {
    "dynamic": false,
    "fields": {
      "title": {
        "type": "autocomplete"
      }
    }
  }
}

# Створення API-ендпоінту для пошуку з Laravel Eloquent

Давайте створимо дві функції — searchByTitle та autocompleteByTitle в класі моделі Movie. Ці функції реалізують відповідно функції пошуку та автозаповнення

Оновимо файл app/Models/Movie.php так:

<?php
namespace App\Models;
 
use Illuminate\Support\Collection;
use MongoDB\Laravel\Eloquent\Model;
 
class Movie extends Model
{
    protected $connection = 'mongodb';
 
    public static function searchByTitle(string $input): Collection
    {
        return self::aggregate()
            ->search([
                'index' => 'movie_search',
                'compound' => [
                    'must' => [
                        [
                            'text' => [
                                'query' => $input,
                                'path' => 'title',
                                'fuzzy' => ['maxEdits' => 2] // Додаємо нечітке співпадіння
                            ]
                        ]
                    ]
                ]
            ])
            ->limit(20)
            ->project(title: 1, genres: 1, poster: 1, rated: 1, plot: 1)
        ->get();
    }
 
    public static function autocompleteByTitle(string $input): Collection
    {
        return self::aggregate()
            ->search([
                'index' => 'movie_title_autocomplete',
                'autocomplete' => [
                    'query' => $input,
                    'path' => 'title'
                ],
                'highlight' => [
                    'path' => ['title']
                ]
            ])
            ->limit(5) // Обмежити результат до 5
            ->project(title: 1, highlights: ['$meta' => 'searchHighlights'])
            ->get();
    }
}

Примітка: розміщення коду, що виконує запит на пошук, у класі моделі відокремлює рівень доступу до даних від HTTP контролерів. Це робить код більш тестованим

Давайте створимо контролер для реалізації API пошуку в проекті. Виконайте наступну команду для створення контролера

php artisan make:controller SearchController

Ця команда створить файл app/Http/Controllers/SearchController.php. Оновіть файл так:

<?php
namespace App\Http\Controllers;
 
use App\Models\Movie;
use Illuminate\Http\JsonResponse;
 
class SearchController extends Controller
{
   public function search($search): JsonResponse
   {
       // Визначаємо агрегацію на основі умов пошуку
       if (!empty($search)) {
           $items = Movie::searchByTitle($search);
           return response()->json($items, 200);
       }
       return response()->json(['error' => 'умови не виконано'], 400);
   }
}

Тепер давайте створимо API маршрут

Перейдіть до app/routes/web.php:

// імпортуємо SearchController
use App\Http\Controllers\SearchController;
 
Route::get('/search/{search}', [SearchController::class, 'search']);

Тестуйте API, викликаючи його, наприклад:
http://localhost:8000/search/moving train

# Створення API-ендпоінту для автозаповнення з Laravel Eloquent

Перейдіть до файлу app/Http/Controllers/SearchController.php та додайте нижче функцію після закінчення функції search

public function autocomplete($param): JsonResponse
{
    try {
        $results = Movie::autocompleteByTitle($param);
        return response()->json($results, 200);
    } catch (\Exception $e) {
        return response()->json(['error' => $e->getMessage()], 500);
    }
}

Далі створіть API маршрут. Перейдіть до app/routes/web.php

Route::get('/autocomplete/{param}', [SearchController::class, 'autocomplete']);

Тестуйте API, викликавши його так:

http://localhost:8000/autocomplete/hello

# Реалізація автозаповнення в нашому фронтенд-додатку

Щоб побачити ці зміни в дії, оновіть тег body у файлі app/resources/views/welcome.blade.php так

Отримайте завершений фрагмент коду на GitHub

<body class="font-sans antialiased dark:bg-black dark:text-white/50">
    <script>
        let debounceTimer;
        let movies = @json($movies);
        displayMovies(movies)
 
        function handleSearch(event) {
            const query = event.target.value;
            // Очищаємо попередній таймер
            clearTimeout(debounceTimer);
            // Встановлюємо новий таймер
            debounceTimer = setTimeout(() => {
                if (query.length > 2) { // Шукати тільки при введенні більше 2 символів
                    titleAutocomplete(query);
                }
            }, 300);
        }
         async function titleAutocomplete(query) {
            try {
                const response = await fetch(`/autocomplete/${encodeURIComponent(query)}`);
                const movies = await response.json();
                displayResults(movies);
            } catch (error) {
                console.error('Помилка при отриманні фільмів:', error);
            }
        }
 
        async function fetchMovies(query) {
            try {
                const response = await fetch(`/search/${encodeURIComponent(query)}`);
                const movies = await response.json();
                displayMovies(movies);
                displayResults([]);
            } catch (error) {
                console.error('Помилка при отриманні фільмів:', error);
            }
        }
 
        function displayResults(movies) {
            const resultsDiv = document.getElementById('search-results');
            resultsDiv.innerHTML = movies.map(movie => `
                <div onclick="fetchMovies('${movie.title}')" class='select-none text-gray-600 cursor-pointer flex items-center gap-[10px]'>
                    <div>
                        ${movie.title}
                    </div>
                </div>`).join('');
        }
 
 
        function displayMovies(movies) {
            const movieListDiv = document.getElementById('movie-list');
            movieListDiv.innerHTML = movies.map(movie => `
                <div class="movie-card max-w-sm bg-green-500 border border-gray-200 rounded-lg shadow dark:bg-gray-800 dark:border-gray-700">
                    <div class="h-[400px]">
                        <img class="rounded-t-lg object-cover w-full h-full" src="${movie.poster}" alt="${movie.title}" />
                    </div>
                    <div class="p-5">
                        <a href="#">
                            <h5 class="mb-2 text-2xl font-bold tracking-tight text-gray-900 dark:text-white line-clamp-1">
                                ${movie.title}
                            </h5>
                        </a>
                        <p class="mb-3 font-normal text-gray-700 dark:text-gray-400 line-clamp-2">${movie.plot}</p>
                        <a href="#"
                            class="inline-flex items-center px-3 py-2 text-sm font-medium text-center text-white bg-blue-700 rounded-lg hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800">
                            Дивитися більше
                            <svg class="rtl:rotate-180 w-3.5 h-3.5 ms-2" aria-hidden="true"
                                xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 14 10">
                                <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"
                                    stroke-width="2" d="M1 5h12m0 0L9 1m4 4L9 9" />
                            </svg>
                        </a>
                    </div>
                </div>
            `).join('');
        }
    </script>
</body>

У зроблених змінах:

З усіма змінами перейдіть за адресою http://localhost:8000/ для тестування, як показано нижче

# Висновок

Важливо забезпечити простоту знаходження інформації вашими користувачами на веб-сайті для досягнення високої якості користувацького досвіду. У цьому посібнику я показав, як створити функцію текстового пошуку для додатку про фільми з використанням MongoDB Atlas Search, яка дозволяє користувачам шукати фільми за їхніми заголовками

Atlas Search є потужним механізмом повнотекстового пошуку, що надає розробникам можливість впроваджувати багатий функціонал пошуку в свої додатки. Це дозволяє швидко і ефективно шукати великі обсяги даних

Дізнайтеся більше про MongoDB Atlas Search та використання PHP з MongoDB

```