• Час читання ~6 хв
  • 10.03.2023

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

У цій статті ми розглянемо, як використовувати бібліотеку JavaScript під назвою "FilePond" для завантаження файлів у ваші програми Laravel. Ми також коротко обговоримо альтернативні підходи до завантаження файлів у Laravel. Потім ми розглянемо, як ви можете використовувати FilePond для завантаження кількох файлів одночасно та завантаження зображень (з попереднім переглядом зображень). Нарешті, ми розглянемо, як ви можете перевірити завантажені файли, як видалити тимчасові файли та як написати тести для коду завантаження файлів.

Що таке FilePond?

FilePond - це бібліотека JavaScript, яка дозволяє завантажувати файли у ваші веб-програми.

Він забезпечує простий, доступний і візуально привабливий інтерфейс для завантаження файлів. Це може дати вам чудову відправну точку для створення власної функціональності завантаження файлів, не турбуючись про стилізацію та доступність інтерфейсу.

FilePond дозволяє завантажувати синхронно або асинхронно. Це означає, що ви можете або завантажувати файли в одному запиті під час подання форми (синхронно), або ви можете завантажувати файли в окремих запитах перед тим, як надіслати форму (асинхронну). Використання асинхронного підходу зазвичай може забезпечити кращий користувальницький досвід, оскільки користувачі можуть продовжувати заповнювати інші поля форми під час завантаження файлів. Для цілей цієї статті ми зосередимося на асинхронному підході.

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

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

Як працює асинхронний потік завантаження файлів FilePond?

Щоб пояснити, як користувач може завантажити файл у формі асинхронно за допомогою FilePond, давайте розглянемо приклад. Ми уявимо, що користувач оновлює свій профіль, використовуючи форму, яка дозволяє йому оновити своє ім'я та зображення профілю. Ми припускаємо, що користувач хоче завантажити файл аватара.png як нове зображення профілю.

Потік може працювати приблизно так:

  1. Користувач натискає «Огляд» в компоненті FilePond на формі.
  2. З'явиться традиційне діалогове вікно завантаження файлів, щоб користувач міг вибрати аватар.png файл, який він хоче завантажити зі свого пристрою.
  3. Після вибору файлу FilePond надсилає аватар.png файл на сервер як багаточастинні/форм-дані за допомогою запиту POST.
  4. Потім сервер (наша програма Laravel) зберігає файл у тимчасовому, унікальному місці. Наприклад, він може зберегти файл у tmp/12345abcdef/avatar.png.
  5. Потім сервер повертає унікальне місцезнаходження (у цьому випадку 12345abcdef/avatar.png) у текстовій/простій відповіді назад до FilePond.
  6. FilePond додайте це унікальне місце в приховане поле введення на формі.
  7. Поки виконувалися кроки 3-6, користувач міг продовжувати заповнювати решту форми під час завантаження файлу. Після завершення завантаження файлу користувач може надіслати форму (яка тепер включає приховане поле введення).
  8. Сервер (наша програма Laravel) використовує унікальне розташування для переміщення файлу з місця тимчасового зберігання до передбачуваного розташування. Наприклад, він може перемістити файл з tmp/12345abcdef/avatar.png на аватари/user-1.png.

Тепер, коли ми отримали коротке уявлення про те, як працюють асинхронні завантаження файлів, давайте розглянемо їх переваги перед синхронним завантаженням файлів у формах.

Синхронне завантаження файлів блокує інтерфейс користувача

Зазвичай у веб-додатку під час використання синхронного підходу до завантаження файлів користувач може натиснути поле «завантаження файлу» у формі. Потім вони можуть вибрати, який файл вони хочуть завантажити. Після того, як вони вибрали свій файл, файл фактично не завантажується на сервер, поки користувач не надішле форму (на відміну від асинхронного підходу, який ми бачили вище). Це означає, що файл завантажується в одному запиті (з рештою полів форми) при подачі форми.

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

Це відрізняється від того, як працюють асинхронні завантаження файлів. При асинхронному підході файл вже був би завантажений на сервер (або був би в процесі завантаження) в окремому запиті до того, як форма буде подана. Проблеми синхронного завантаження файлів з безсерверними

платформами

Якщо ви використовуєте свою програму на безсерверній платформі, наприклад AWS Lambda, синхронне завантаження файлів може швидко стати проблематичним. На момент написання цієї статті, згідно з документацією AWS Lambda, максимальний розмір запиту становить 6 Мб. Це означає, що вам потрібно буде переконатися, що розмір даних у вашій формі (включно з завантаженими файлами) не перевищує це обмеження.

Це означає, що вам потрібно прийняти асинхронний підхід до завантаження файлів, якщо ви маєте намір запускати свої програми на безсерверній платформі. Залежно від вашої програми, ви можете завантажити їх безпосередньо до свого постачальника сховища (наприклад, AWS S3) зі свого браузера. В результаті цього це означає, що ви можете взагалі уникнути файлів, що торкаються вашого сервера. Це не тільки може бути більш безпечним (оскільки ви уникаєте обробки потенційно шкідливих файлів на вашому сервері), але також може бути більш ефективним (оскільки вам не потрібно спочатку завантажувати файли на свій сервер) і дозволяє уникнути обмеження в 6 МБ.

Хоча загальні принципи, описані в цій статті, можуть бути застосовані до завантаження файлів безпосередньо до вашого постачальника сховища, ми зосередимося спочатку на завантаженні файлів на ваш сервер, а потім перенесемо їх до постачальника сховища. Однак, якщо ви використовуєте Laravel Vapor, ви можете ознайомитися з документацією , щоб дізнатися більше про те, як завантажувати файли безпосередньо у свій блок AWS S3. Налаштування FilePond

на передньому краї

Тепер, коли ми зрозуміли асинхронний потік завантаження файлів, давайте подивимося, як ми можемо налаштувати FilePond на передній частині нашої програми Laravel.

FilePond надає кілька адаптерів, які можна використовувати з різними фреймворками, такими як Vue, React і Angular. Однак у цій статті ми просто будемо використовувати ванільний JavaScript-адаптер.

Ми зробимо припущення, що ми працюємо над свіжою установкою Laravel, яка використовує Vite для компіляції активів.

Візьмемо базовий приклад. Ми збираємося уявити, що ми створюємо функцію імпорту CSV, яка дозволяє користувачам завантажувати файл CSV, що містить деталі продукту, який буде створено в нашому веб-додатку.Для початку давайте

зробимо дуже простий вигляд Blade, який містить форму з одним полем введення "файлу":

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">

        <title>FilePond Tutorial</title>

        <meta name="csrf-token" content="{{ csrf_token() }}">

        @vite('resources/js/app.js')
    </head>

    <body>
        <form action="{{ route('products.import') }}" method="POST">
            @csrf
            <input type="file" name="csv" class="filepond"/>

            <button type="submit">Import Products</button>
        </form>
    </body>
</html>

Тепер давайте встановимо FilePond через NPM, запустивши таку команду:

npm i filepond --save

Потім ми можемо відкрити наш файл ресурсів / js / app .js та додати функціональність, щоб увімкнути FilePond у нашому полі введення:

import * as FilePond from 'filepond';
import 'filepond/dist/filepond.min.css';

const inputElement = document.querySelector('input[type="file"].filepond');

const csrfToken = document.querySelector('meta[name="csrf-token"]').getAttribute('content');

FilePond.create(inputElement).setOptions({
    server: {
        process: './uploads/process',
        headers: {
            'X-CSRF-TOKEN': csrfToken,
        }
    }
});

Давайте швидко подивимося, що робиться у наведеному вище коді. По-перше, ми імпортуємо файли FilePond JavaScript і CSS, які забезпечують необхідні нам функціональність і стилі.

Потім ми перейшли до пошуку поля введення, яке ми хочемо перетворити на поле FilePond. Зверніть увагу, як ми додали клас filepond до селектора запитів. Це робиться для того, щоб ми могли розрізняти поля введення, які ми хочемо перетворити в поля FilePond, і ті, які ми, можливо, не хочемо.

Потім ми схопили токен CSRF з мета-тегу, який ми додали до перегляду Blade. Це для того, щоб ми могли передати його в FilePond, щоб його можна було надіслати на наш сервер при спробі завантажити файл. Не додаючи цього, ви отримаєте відповідь на помилку HTTP 419 щоразу, коли намагаєтеся завантажити файл.

Потім ми створили наш екземпляр FilePond і уточнили, що коли ми хочемо завантажити новий файл, його слід надіслати на URL-адресу /uploads/process на нашому сервері. FilePond також надає функціональність, щоб ми могли вказати URL-адресу для видалення тимчасово завантажених файлів, але ми не будемо використовувати цю функціональність у цьому посібнику.

Передня частина тепер повинна бути готова до використання. Якщо користувач повинен був вибрати файл CSV, він буде надісланий на URL-адресу /uploads/process і тимчасово збережений. Приховане поле csv у формі буде заповнено шляхом до файлу, де ми тимчасово зберігали файл. Налаштування FilePond

на бекенді

Тепер ми можемо налаштувати задню частину нашої програми Laravel для обробки завантажень файлів, що надходять із FilePond. Для цього нам потрібно буде створити маршрут і контролер, які відповідають за тимчасове зберігання завантажених файлів.

Як я вже згадував раніше, FilePond дійсно надає можливість завантажувати файли шматками. Але для цілей цього підручника ми збираємося зробити все простим і дивитися на завантаження файлів лише в одному запиті.

Спочатку ми почнемо зі створення нового FileUploadController, виконавши таку команду:

php artisan make:controller FileUploadControlle

Потім ми можемо додати метод процесу до контролера, який обробляє завантаження файлу та зберігає файл у каталозі tmp у сховищі:

declare(strict_types=1);

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Str;

final class FileUploadController extends Controller
{
    public function process(Request $request): string
    {
        // We don't know the name of the file input, so we need to grab
        // all the files from the request and grab the first file.
        /** @var UploadedFile[] $files */
        $files = $request->allFiles();

        if (empty($files)) {
            abort(422, 'No files were uploaded.');
        }
        if (count($files) > 1) {
            abort(422, 'Only 1 file can be uploaded at a time.');
        }
        // Now that we know there's only one key, we can grab it to get
        // the file from the request.
        $requestKey = array_key_first($files);

        // If we are allowing multiple files to be uploaded, the field in the
        // request will be an array with a single file rather than just a
        // single file (e.g. - `csv[]` rather than `csv`). So we need to
        // grab the first file from the array. Otherwise, we can assume
        // the uploaded file is for a single file input and we can
        // grab it directly from the request.
        $file = is_array($request->input($requestKey))
            ? $request->file($requestKey)[0]
            : $request->file($requestKey);

        // Store the file in a temporary location and return the location
        // for FilePond to use.
        return $file->store(
            path: 'tmp/'.now()->timestamp.'-'.Str::random(20)
        );
    }
}

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

Якщо користувач завантажує файл до цього контролера, буде повернуто рядок, подібний до наступного:

tmp/1678198256-88eXsQV7XB2RU5zXdw0S/9A4eK5mRLAtayW78jhRo3Lc3WdSSrsihpVHhMvzr.png

Потім ми можемо зареєструвати маршрут /uploads/process у нашому Інтернеті.php такий файл:

use App\Http\Controllers\FileUploadController;
use Illuminate\Support\Facades\Route;

Route::post('uploads/process', [FileUploadController::class, 'process'])->name('uploads.process');

Тепер ваша програма повинна успішно завантажувати файли та зберігати їх у тимчасовому каталозі.

Доступ до завантаженого файлу в контролері

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

Почнемо зі створення нового контролера, який відповідає за імпорт продуктів з файлу CSV. Ми можемо зробити це, запустивши таку команду:

php artisan make:controller ImportProductController -i

Потім ми можемо оновити наш новостворений ImportProductController для обробки імпорту файлів:

declare(strict_types=1);

namespace App\Http\Controllers;

use App\Services\ProductImportService;
use Illuminate\Http\File;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;

final class ImportProductController extends Controller
{
    public function __invoke(
        Request $request,
        ProductImportService $productImportService
    ): RedirectResponse {
        $validated = $request->validate([
            'csv' => 'required|string',
        ]);
        // Copy the file from a temporary location to a permanent location.
        $fileLocation = Storage::putFile(
            path: 'imports',
            file: new File(Storage::path($validated['csv']))
        );
        $productImportService->import(
            csvLocation: $fileLocation
        );
        return redirect()
            ->route('products.index')
            ->with('success', 'Products imported successfully');
    }
}

Давайте подивимося, що робиться в методі контролера вище.

По-перше, ми додали підказку щодо типу для класу ProductImportService, щоб вона була вирішена з контейнера обслуговування для використання нами в нашому методі контролера. Це не клас, який ми розглянемо в цій статті, але ми можемо припустити, що він відповідає за імпорт продуктів із файлу CSV.

Ми також перевіряємо, що запит містить рядок CSV. Ми розглянемо, як ми можемо покращити цю перевірку, далі в статті.

Після цього ми копіюємо файл із його тимчасового розташування до постійного розташування, щоб передати його на наш об'єкт ProductImportService.

Після того, як все це було зроблено, ми повертаємо відповідь перенаправлення на сторінку індексу продуктів із повідомленням про успіх.

Тепер ми можемо зареєструвати маршрут для нашого ImportProductController у нашому веб-файлі.php наприклад:

use App\Http\Controllers\ImportProductController;

Route::post('products/import', ImportProductController::class)->name('products.import');

Завантаження зображень FilePond

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

Щоб використовувати плагін FilePondPluginImagePreview, ми можемо встановити його через NPM, запустивши таку команду:Після його встановлення ми можемо імпортувати наступні рядки в наш додаток.js файл:Після цього ми можемо

npm i filepond-plugin-image-preview --save

 

import FilePondPluginImagePreview from 'filepond-plugin-image-preview';
import 'filepond-plugin-image-preview/dist/filepond-plugin-image-preview.css';

використовувати метод registerPlugin для реєстрації плагіна за допомогою FilePond:

FilePond.registerPlugin(FilePondPluginImagePreview);

Після додавання цих рядків ваш код може виглядати приблизно так:

import * as FilePond from 'filepond';
import 'filepond/dist/filepond.min.css';
import FilePondPluginImagePreview from 'filepond-plugin-image-preview';
import 'filepond-plugin-image-preview/dist/filepond-plugin-image-preview.css';

const inputElement = document.querySelector('input[type="file"].filepond');

const csrfToken = document.querySelector('meta[name="csrf-token"]').getAttribute('content');

FilePond.registerPlugin(FilePondPluginImagePreview);

FilePond.create(inputElement).setOptions({
    server: {
        process: './uploads/process',
        headers: {
            'X-CSRF-TOKEN': csrfToken,
        }
    },
    allowMultiple: true,
});

Ось і все! Тепер у вас повинен бути робочий компонент FilePond, який дозволяє завантажувати зображення та переглядати їх.

Завантаження кількох файлів

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

Для цього ми можемо додати кілька атрибутів до нашого вхідного елемента:

<input type="file" name="csv[]" class="filepond" multiple/>

Ми можемо потім передати дозволитиMultiple: вірно до setOptions метод:

FilePond.create(inputElement).setOptions({
    server: {
        process: './uploads/process',
        fetch: null,
        revert: null,
        headers: {
            'X-CSRF-TOKEN': csrfToken,
        }
    },
    allowMultiple: true,
});

Ось і все, що є для нього! Ми вже переконалися, що наш FileUploadController може обробляти кілька файлів, тому нам не потрібно вносити в нього будь-які зміни.

Якщо користувач намагався завантажити два файли, на сервер буде зроблено два окремих запити на зберігання файлів. Потім до форми буде додано два прихованих поля csv[] з іменами файлів завантажених файлів.

Зверніть увагу, як нам потрібно використовувати csv[] , а не csv. Це пов'язано з тим, що якби ми використовували csv, ми могли б надсилати лише один шлях до файлу щоразу, коли форма надсилається. Використовуючи csv[], ми можемо надіслати кілька шляхів до файлів, до яких потім можна отримати доступ у нашому контролері у вигляді масиву рядків.

Беручи це далі Тепер,

коли ми розглянули, як ми можемо завантажувати файли в наші програми Laravel за допомогою FilePond, давайте подивимося на деякі інші речі, які ви, ймовірно, захочете

зробити.Validation

Filepond надає деяких помічників, яких ви можете використовувати для додавання перевірки до компонента завантаження файлу, наприклад, даних максимального розміру файлу. Ви можете додати ці помічники з перевірки до свого вхідного елемента, наприклад так

<input type="file" name="csv" class="filepond" data-max-file-size="3MB"/>

:Однак важливо пам'ятати, що перевірка на стороні клієнта в основному призначена для цілей UI/UX, а не для безпеки. Ви завжди повинні перевіряти свої дані на стороні сервера, щоб переконатися, що дані дійсні.

З цієї причини дуже важливо перевірити файл після надсилання форми, перш ніж намагатися його обробити.

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

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

art make:rule ValidFileUpload

Ми можемо оновити наше правило ValidFileUpload, щоб воно виглядало так:У класі

declare(strict_types=1);

namespace App\Rules;

use Closure;
use Illuminate\Contracts\зробити.Validation\зробити.ValidationRule;
use Illuminate\Support\Facades\Storage;

final class ValidFileUpload implements зробити.ValidationRule
{
    public function __construct(
        private readonly array $validMimeTypes
    ) {
        //
    }
    public function validate(string $attribute, mixed $value, Closure $fail): void
    {
        if (!Storage::exists($value)) {
            $fail('The file does not exist.');
        }
        if (!in_array(Storage::mimeType($value), $this->validMimeTypes, true)) {
            $fail('The file is not a valid mime type.');
        }
    }
}

ValidFileUpload ми визначили конструктор, який приймає масив дійсних типів мімів.

У методі перевірки ми додали дві перевірки:

  1. Перевірка наявності файлу в сховищі.
  2. Перевірте, чи є тип міма файлу в масиві допустимих типів мімів.

Потім ми можемо використовувати це правило для перевірки, наприклад:

use App\Rules\ValidFileUpload;

$validated = $request->validate([
    'csv' => ['required', 'string', new ValidFileUpload(['text/csv'])],
]);

Ви навіть можете зробити цю перевірку ще на крок далі і додати додаткові твердження, наприклад, перевірка розміру файлу, який не перевищує певного розміру.

Очищення тимчасових файлів

З часом велика кількість тимчасових файлів може накопичуватися у вашій папці tmp. Отже, ви можете написати команду Artisan, яку ви можете запланувати для регулярного запуску, щоб видалити папки з папки tmp, які старші за певний проміжок часу.

Давайте розглянемо, як ми можемо це зробити. Ми почнемо зі створення нової команди DeleteTempUploadedFiles, запустивши таку команду:Потім ми

art make:command DeleteTempUploadedFiles

можемо оновити нашу команду DeleteTempUploadedFiles, щоб вона виглядала приблизно так:

declare(strict_types=1);

namespace App\Console\Commands;

use Carbon\Carbon;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Storage;

final class DeleteTempUploadedFiles extends Command
{
    protected $signature = 'app:delete-temp-uploaded-files';

    protected $description = 'Delete temporary uploaded files older than 24 hours.';

    public function handle(): void
    {
        foreach (Storage::directories('tmp') as $directory) {
            $directoryLastModified = Carbon::createFromTimestamp(Storage::lastModified($directory));

            if (now()->diffInHours($directoryLastModified) > 24) {
                Storage::deleteDirectory($directory);
            }
        }
    }
}

У команді вище ми циклічно переглядаємо всі каталоги в папці tmp вашого сховища та перевіряємо, чи каталог старше 24 годин. Якщо це так, ми потім видаляємо каталог.

Потім ми можемо запланувати запуск цієї команди щогодини, додавши її до методу розкладу в додатку / консолі / керні.php класі:

namespace App\Console;

use App\Console\Commands\DeleteTempUploadedFiles;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;

class Kernel extends ConsoleKernel
{
    /**
     * Define the application's command schedule.
     */
    protected function schedule(Schedule $schedule): void
    {
        $schedule->command(DeleteTempUploadedFiles::class)->hourly();
    }
    // ...
}

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

Залежно від вашої програми, ви можете змінити тривалість існування каталогу або частоту їх видалення.

Тестування вашого коду

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

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

  • Файл можна зберігати в папці tmp, якщо поле форми підтримує один файл.
  • Файл може зберігатися в папці tmp, якщо поле форми підтримує кілька файлів.
  • Помилка повертається, якщо в запиті не передано жодного файлу.
  • Помилка повертається, якщо в запиті передано більше одного файлу.

Ми могли б написати кілька основних тестів, щоб охопити ці сценарії, наприклад

declare(strict_types=1);

namespace Tests\Feature\Controllers;

use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
use Tests\TestCase;

final class FileUploadControllerTest extends TestCase
{
    protected function setUp(): void
    {
        parent::setUp();

        // Use a fake storage driver so we don't store files on the real disk.
        Storage::fake();

        // Freeze time and define how `Str::random` should work. This allows us
        // to explicitly check that the file is stored in the correct location
        // and is being named correctly.
        $this->freezeTime();
        Str::createRandomStringsUsing(static fn (): string => 'random-string');
    }
    /** @test */
    public function file_can_be_temporarily_uploaded_for_a_single_file_field(): void
    {
        $file = UploadedFile::fake()->image('avatar.png');

        $expectedFilePath = 'tmp/'.now()->timestamp.'-random-string';

        $this->post(route('uploads.process'), [
            'avatar' => $file,
        ])
            ->assertOk()
            ->assertSee($expectedFilePath);

        Storage::assertExists($expectedFilePath);
    }
    /** @test */
    public function file_can_be_temporarily_uploaded_for_a_multiple_file_field(): void
    {
        $file = UploadedFile::fake()->image('avatar.png');

        $expectedFilePath = 'tmp/'.now()->timestamp.'-random-string';

        $this->post(route('uploads.process'), [
            'avatar' => [
                $file
            ],
        ])
            ->assertOk()
            ->assertSee($expectedFilePath);

        Storage::assertExists($expectedFilePath);
    }
    /** @test */
    public function error_is_returned_if_no_file_is_passed_in_the_request(): void
    {
        $this->post(route('uploads.process'))
            ->assertStatus(422);
    }
    /** @test */
    public function error_is_returned_if_more_than_one_file_is_passed_in_the_request(): void
    {
        $file = UploadedFile::fake()->image('avatar.png');

        $this->post(route('uploads.process'), [
            'avatar' => $file,
            'invalid' => $file,
        ])
            ->assertStatus(422);
    }
}

: Хоча ці тести є досить базовими, вони повинні дати вам хорошу відправну точку для написання власних тестів для функціональності завантаження файлів. Ви можете розширити ці тести, щоб перевірити, чи повернуто правильне повідомлення про помилку. Або ви можете перевірити, чи дозволено передавати файли лише певним користувачам, якщо ви додасте автентифікацію та авторизацію до потоку завантаження файлів.

Ви також можете додати тести для свого правила перевірки. Це може допомогти вам мати більше впевненості в додаванні більшої кількості тверджень у майбутньому, якщо ви вирішите зробити свою перевірку суворішою.

Висновок

У цій статті ми розглянули, як використовувати FilePond для асинхронного завантаження файлів у ваших програмах Laravel. Ми також розглянули, як ви можете видалити тимчасові файли, перевірити завантажені файли та написати тести, щоб переконатися, що завантаження файлів працює.

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

Comments

CrazyBoy49z
CrazyBoy49z 11.03.2023 00:19

test comment

Yurij Finiv

Yurij Finiv

Full stack

Про мене

Professional Fullstack Developer with extensive experience in website and desktop application development. Proficient in a wide range of tools and technologies, including Bootstrap, Tailwind, HTML5, CSS3, PUG, JavaScript, Alpine.js, jQuery, PHP, MODX, and Node.js. Skilled in website development using Symfony, MODX, and Laravel. Experience: Contributed to the development and translation of MODX3 i...

Про автора CrazyBoy49z
WORK EXPERIENCE
Контакти
Ukraine, Lutsk
+380979856297