Разработка кастомного пакета Bagisto
Bagisto строится на концепции Laravel-пакетов: каждая функциональная единица системы — это изолированный модуль со своими моделями, контроллерами, маршрутами и view. Кастомный пакет позволяет добавить любую логику, не трогая vendor-код и не ломая обновления ядра.
Структура пакета
packages/
└── MyCompany/
└── Catalog/
├── src/
│ ├── Http/
│ │ ├── Controllers/
│ │ │ └── Admin/CatalogController.php
│ │ └── Requests/
│ ├── Models/
│ │ └── CustomAttribute.php
│ ├── Repositories/
│ │ └── CustomAttributeRepository.php
│ ├── Database/
│ │ ├── Migrations/
│ │ └── Seeders/
│ ├── Resources/
│ │ ├── assets/
│ │ │ ├── js/
│ │ │ └── css/
│ │ └── views/
│ │ └── admin/
│ ├── Config/
│ │ └── menu.php
│ ├── Routes/
│ │ ├── admin.php
│ │ └── shop.php
│ └── Providers/
│ └── CatalogServiceProvider.php
└── composer.json
Регистрация пакета
composer.json корневого проекта:
{
"autoload": {
"psr-4": {
"MyCompany\\Catalog\\": "packages/MyCompany/Catalog/src"
}
}
}
composer dump-autoload
ServiceProvider — точка входа пакета:
<?php
namespace MyCompany\Catalog\Providers;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Event;
class CatalogServiceProvider extends ServiceProvider
{
public function register(): void
{
$this->mergeConfigFrom(
__DIR__.'/../Config/menu.php', 'menu'
);
}
public function boot(): void
{
$this->loadRoutesFrom(__DIR__.'/../Routes/admin.php');
$this->loadRoutesFrom(__DIR__.'/../Routes/shop.php');
$this->loadMigrationsFrom(__DIR__.'/../Database/Migrations');
$this->loadViewsFrom(__DIR__.'/../Resources/views', 'mycompany-catalog');
$this->loadTranslationsFrom(__DIR__.'/../Resources/lang', 'mycompany-catalog');
$this->publishes([
__DIR__.'/../Resources/assets' => public_path('vendor/mycompany/catalog'),
], 'mycompany-catalog-assets');
// Подписываемся на события ядра
Event::listen(
'catalog.product.create.after',
'MyCompany\Catalog\Listeners\ProductCreatedListener'
);
}
}
Регистрация в config/app.php:
'providers' => [
// ...
MyCompany\Catalog\Providers\CatalogServiceProvider::class,
],
Репозитории вместо прямых запросов
Bagisto использует паттерн Repository поверх Eloquent. Кастомные репозитории наследуют базовый класс ядра:
<?php
namespace MyCompany\Catalog\Repositories;
use Webkul\Core\Eloquent\Repository;
use MyCompany\Catalog\Models\CustomAttribute;
class CustomAttributeRepository extends Repository
{
public function model(): string
{
return CustomAttribute::class;
}
public function getByProduct(int $productId): \Illuminate\Support\Collection
{
return $this->where('product_id', $productId)
->where('is_active', true)
->orderBy('sort_order')
->get();
}
}
Регистрация в ServiceProvider:
$this->app->bind(
\MyCompany\Catalog\Repositories\CustomAttributeRepository::class
);
Добавление пункта в меню администратора
// Config/menu.php
return [
[
'key' => 'mycompany',
'name' => 'MyCompany',
'route' => 'mycompany.catalog.index',
'sort' => 10,
'icon' => 'icon-catalog',
],
[
'key' => 'mycompany.catalog',
'name' => 'Каталог',
'route' => 'mycompany.catalog.index',
'sort' => 1,
'icon' => '',
],
];
Vue-компоненты в пакете
Bagisto 2.x использует Vue 3 + Vite. Компоненты пакета регистрируются глобально:
// packages/MyCompany/Catalog/src/Resources/assets/js/index.js
import CustomAttributeForm from './components/CustomAttributeForm.vue';
export default {
install(app) {
app.component('custom-attribute-form', CustomAttributeForm);
}
}
Подключение в vite.config.js корневого проекта через resolve.alias или через публикацию ассетов.
Перехват событий ядра
Bagisto генерирует события в ключевых точках — это основной механизм расширения без патчинга:
| Событие | Когда срабатывает |
|---|---|
checkout.order.save.after |
После создания заказа |
catalog.product.create.after |
После создания товара |
customer.registration.after |
После регистрации покупателя |
sales.invoice.save.after |
После создания инвойса |
catalog.product.update.after |
После обновления товара |
<?php
namespace MyCompany\Catalog\Listeners;
class ProductCreatedListener
{
public function handle($product): void
{
// Отправка в очередь для индексации в Elasticsearch
dispatch(new \MyCompany\Catalog\Jobs\IndexProduct($product->id));
}
}
Тестирование пакета
<?php
namespace MyCompany\Catalog\Tests\Unit;
use Tests\TestCase;
use MyCompany\Catalog\Repositories\CustomAttributeRepository;
class CustomAttributeRepositoryTest extends TestCase
{
public function test_returns_active_attributes(): void
{
$repo = app(CustomAttributeRepository::class);
$attrs = $repo->getByProduct(1);
$this->assertInstanceOf(\Illuminate\Support\Collection::class, $attrs);
$this->assertTrue($attrs->every(fn($a) => $a->is_active));
}
}
Сроки разработки
| Тип пакета | Срок |
|---|---|
| Простой (CRUD + меню) | 1-3 дня |
| Интеграция с внешним API | 3-7 дней |
| Кастомный checkout-flow | 1-2 недели |
| Полный модуль (marketplace vendor) | 2-4 недели |
Пакет оформляется с composer.json, тестами и документацией — это важно при передаче команде или при обновлении Bagisto до следующей мажорной версии.







