• Час читання ~8 хв
  • 14.07.2023

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

Сучасні PHP-фреймворки, такі як Laravel і Symfony, взаємодіють з базами даних через Object-relational mappers (ORMs); Symfony використовує Doctrine як стандартний ORM, а Laravel використовує Eloquent.

Обидва використовують різні підходи до взаємодії з базами даних. За допомогою Eloquent Моделі генеруються для кожної таблиці бази даних, формуючи основу взаємодії. Доктрина, однак, використовує шаблон репозиторію, де кожна сутність має відповідний репозиторій, що містить допоміжні функції для взаємодії з базою даних. Хоча Laravel не забезпечує цю функціональність з коробки, можна використовувати шаблон Repository в проектах Laravel.

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

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

У цій статті я покажу вам, як реалізувати шаблон Repository у ваших програмах Laravel. Для цього ми створимо API для управління замовленнями, отриманими від клієнтів для компанії.

Передумови

Приступаємо до роботи

Створіть новий проект Laravel і компакт-диск в каталозі за допомогою наступних команд.

laravel new order_api
cd order_api

Налаштування бази даних Для цього підручника ми будемо використовувати MySQL як нашу базу даних

. Для цього у файлі . env оновіть параметри, пов'язані з базою даних, як показано нижче.

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=order_api
DB_USERNAME=<YOUR_DATABASE_USERNAME>
DB_PASSWORD=<YOUR_DATABASE_PASSWORD>

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

Генерація вихідних даних для бази даних

Ми створюємо додаток для керування замовленнями, тому давайте створимо модель для нього, запустивши таку команду.

php artisan make:model Order -a

Аргумент -a дає Artisan знати, що ми хочемо створити файл міграції , сівалку, фабрику та контролер для моделі замовлення .

Команда вище створить п'ять нових файлів:

  • Контролер у app/Http/Controllers/OrderController.php
  • Фабрика баз даних у базі даних/фабриках/orderFactory.php
  • Файл міграції в базі даних/migrations/YYYY_MM_DD_HHMMSS_create_orders_table.php
  • Модель, розташована в додатку/Моделі/Замовити.php
  • Файл сівалки в базі даних/сівалках/OrderSeeder.php та

У розділі database/migrations/YYYY_MM_DD_HHMMSS_create_orders_table.php оновіть функцію, up щоб вона відповідала наведеному нижче.

public function up()
{
    Schema::create('orders', function (Blueprint $table) {
        $table->id();
        $table->text('details');
        $table->string('client');
        $table->boolean('is_fulfilled')->default(false);
        $table->timestamps();
    });
 }

Як зазначено у файлі міграції, таблиця матиме такі стовпці:

  1. An ID. This will be the table's primary key.
  2. The details of the order.
  3. The name of the client who placed the order.
  4. Whether or not the order has been fulfilled.
  5. When the order was created and updated, created_at and updated_at, provided by the timestamps function.

Далі, давайте оновимоOrderFactory, order щоб вона могла створити фіктивний порядок для посіву бази даних. У розділі database/factories/OrderFactory.php оновіть функцію, definition щоб вона відповідала наведеному нижче.

public function definition() 
{
    return [
        'details'       => $this->faker->sentences(4, true),
        'client'         => $this->faker->name(),
        'is_fulfilled' => $this->faker->boolean(),
    ];
}

Далі відкрийте базу даних/сівалки/OrderSeeder.php і оновіть функцію, run щоб вона відповідала наведеним нижче.

public function run() 
{
    Order::factory()->times(50)->create();
}

Це використовується OrderFactory для створення 50 замовлень у базі даних.

Не забудьте додати цей імпорт:

use App\Models\Order;

У src/database/seeders/DatabaseSeeder.php додайте до функції наступнеrun.

$this->call(
    [
        OrderSeeder::class
    ]
); 

Це запускається, QuoteSeeder коли виконується команда ремісникаdb:seed.

Нарешті, запустіть міграцію та створіть базу даних за допомогою такої команди.

php artisan migrate --seed

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

List of Orders

Створення репозиторію

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

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

У каталозі програм створіть нову папку під назвою Interfaces. Потім в інтерфейсах створіть новий файл під назвою OrderRepositoryInterface.php і додайте до нього наступний код.

<?php
namespace App\Interfaces;
interface OrderRepositoryInterface 
{
    public function getAllOrders();
    public function getOrderById($orderId);
    public function deleteOrder($orderId);
    public function createOrder(array $orderDetails);
    public function updateOrder($orderId, array $newDetails);
    public function getFulfilledOrders();
}

Далі в папці додатків створіть нову папку під назвою Repositories. У цій папці створіть новий файл з назвою OrderRepository.php і додайте до нього наступний код.

<?php
namespace App\Repositories;
use App\Interfaces\OrderRepositoryInterface;
use App\Models\Order;
class OrderRepository implements OrderRepositoryInterface 
{
    public function getAllOrders() 
    {
        return Order::all();
    }
    public function getOrderById($orderId) 
    {
        return Order::findOrFail($orderId);
    }
    public function deleteOrder($orderId) 
    {
        Order::destroy($orderId);
    }
    public function createOrder(array $orderDetails) 
    {
        return Order::create($orderDetails);
    }
    public function updateOrder($orderId, array $newDetails) 
    {
        return Order::whereId($orderId)->update($newDetails);
    }
    public function getFulfilledOrders() 
    {
        return Order::where('is_fulfilled', true);
    }
}

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

Якщо в майбутньому ми вирішимо отримати лише невиконані замовлення у getAllOrders() функції, нам доведеться внести зміни лише в одному місці, а не відстежувати всі місця, де Order::all() заявлено, ризикуючи пропустити деякі.

Створення контролерів

З нашим репозиторієм давайте додамо трохи коду до нашого контролера. Відкрийте app/Http/Controllers/OrderController.php і оновіть код, щоб він відповідав наведеному нижче.

<?php
namespace App\Http\Controllers;
use App\Interfaces\OrderRepositoryInterface;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
class OrderController extends Controller 
{
    private OrderRepositoryInterface $orderRepository;
    public function __construct(OrderRepositoryInterface $orderRepository) 
    {
        $this->orderRepository = $orderRepository;
    }
    public function index(): JsonResponse 
    {
        return response()->json([
            'data' => $this->orderRepository->getAllOrders()
        ]);
    }
    public function store(Request $request): JsonResponse 
    {
        $orderDetails = $request->only([
            'client',
            'details'
        ]);
        return response()->json(
            [
                'data' => $this->orderRepository->createOrder($orderDetails)
            ],
            Response::HTTP_CREATED
        );
    }
    public function show(Request $request): JsonResponse 
    {
        $orderId = $request->route('id');
        return response()->json([
            'data' => $this->orderRepository->getOrderById($orderId)
        ]);
    }
    public function update(Request $request): JsonResponse 
    {
        $orderId = $request->route('id');
        $orderDetails = $request->only([
            'client',
            'details'
        ]);
        return response()->json([
            'data' => $this->orderRepository->updateOrder($orderId, $orderDetails)
        ]);
    }
    public function destroy(Request $request): JsonResponse 
    {
        $orderId = $request->route('id');
        $this->orderRepository->deleteOrder($orderId);
        return response()->json(null, Response::HTTP_NO_CONTENT);
    }
}

Код вводить OrderRepositoryInterface екземпляр через конструктор і використовує методи відповідного об'єкта в кожному методі контролера.

По-перше, в рамках методу index() він викликає метод, getAllOrders() визначений в orderRepository для отримання списку замовлень, і повертає відповідь у форматі JSON.

Далі store() метод викликає createOrder() метод з для orderRepository створення нового замовлення. Це приймає відомості про порядок, який потрібно створити як масив, і повертає успішну відповідь після цього.

В show() рамках методу в контролері він отримує унікальний порядок Id з маршруту і передає його getOrderById() в як параметр. Це отримує деталі замовлення з відповідним ідентифікатором із бази даних і повертає відповідь у форматі JSON.

Потім, щоб оновити деталі вже створеного замовлення, він викликає updateOrder() метод зі сховища. Для цього потрібно два параметри: унікальний id замовлення і деталі, які потрібно оновити.

Нарешті, метод отримує унікальний ідентифікатор певного замовлення з маршруту і викликає deleteOrder() метод зі сховища, destroy() щоб видалити його.

Додавання маршрутів

Щоб зіставити кожен метод, визначений у контролері, з конкретними маршрутами, додайте наступний код до routes/api.php.

Route::get('orders', [OrderController::class, 'index']);
Route::get('orders/{id}', [OrderController::class, 'show']);
Route::post('orders', [OrderController::class, 'store']);
Route::put('orders/{id}', [OrderController::class, 'update']);
Route::delete('orders/{id}', [OrderController::class, 'delete']);

Не забудьте включити import твердження для OrderController.

use App\Http\Controllers\OrderController;

Прив'язка інтерфейсу та реалізації

Останнє, що нам потрібно зробити, це прив'язатися OrderRepository до OrderRepositoryInterface сервісного контейнера Laravel; ми робимо це через постачальника послуг. Створіть його за допомогою такої команди.

php artisan make:provider RepositoryServiceProvider

Відкрийте app/Providers/RepositoryServiceProvider.php і оновіть register функцію щоб вона відповідала наведеним нижче.

public function register() 
{
    $this->app->bind(OrderRepositoryInterface::class, OrderRepository::class);
 }

Не забудьте включити import твердження для OrderRepository і OrderRepositoryInterface.

use App\Interfaces\OrderRepositoryInterface;
use App\Repositories\OrderRepository;

Нарешті, додайте нового постачальника послуг до providers масиву в config/app.php.

'providers' => [
    // ...other declared providers
    App\Providers\RepositoryServiceProvider::class,
];

Перевірте програму Запустіть програму

за допомогою такої команди.

За замовчуванням додаток, що обслуговується, буде доступно за адресою http://127.0.0.1:8000/. Використовуючи Postman або cURL, ми можемо надсилати запити до нашого новоствореного API.

Запустіть наступну команду, щоб перевірити кінцеву точку /api/orders за допомогою cURL:

curl --silent http://localhost:8000/api/orders | jq

Відповідь була відформатована в JSON за допомогою jq.

Ви побачите вихід JSON, подібний до наведеного нижче прикладу у вашому терміналі, який був скорочений для полегшення читання.

{
  "data": [
    {
      "id": 1,
      "details": "Sit ullam cupiditate dolorem in. Magnam suscipit eaque occaecati facilis amet illum. Dolor perspiciatis velit laboriosam. Enim fugiat excepturi qui natus incidunt dolorem debitis ut.",
      "client": "Cydney Conn V",
      "is_fulfilled": 0,
      "created_at": "2021-09-09T09:18:28.000000Z",
      "updated_at": "2021-09-09T09:18:28.000000Z"
    },
    {
      "id": 2,
      "details": "Eum iste eum molestiae est. Voluptatibus veritatis earum commodi. Quod et laboriosam ratione dolor adipisci. Nam et debitis nobis ea sit.",
      "client": "Willow Herzog",
      "is_fulfilled": 1,
      "created_at": "2021-09-09T09:18:28.000000Z",
      "updated_at": "2021-09-09T09:18:28.000000Z"
    },
    {
      "id": 3,
      "details": "At maxime architecto repellat quidem id. Saepe provident quo eos officiis et tenetur. Et expedita maxime atque. Et consequuntur sequi aperiam possimus odio est ab.",
      "client": "Mr. Peyton Nolan DVM",
      "is_fulfilled": 1,
      "created_at": "2021-09-09T09:18:28.000000Z",
      "updated_at": "2021-09-09T09:18:28.000000Z"
    }
  ]
}

Ось як використовувати шаблон репозиторію в додатку Laravel У цій статті ми дізналися про шаблон Repository і про те, як його використовувати в додатку

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

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

Вся кодова база для цього підручника доступна на GitHub. Не соромтеся досліджувати далі. Вдалого кодування!


Comments

No comments yet
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