Skip to content

Расширение кода ​

JournalPHP расширяется стандартными средствами Laravel и новым кодом по соглашениям проекта.

Обзор ​

Новая функциональность добавляется сервис-провайдерами, событиями, middleware и классами по тем же соглашениям, что и существующий код: Actions, репозитории с интерфейсами, сервисы со сменными драйверами. Соглашения описаны в разделе Архитектура проекта.

Сервис-провайдеры ​

Провайдеры приложения зарегистрированы в config/app.php → providers:

ПровайдерНазначение
AppServiceProviderОбщая инициализация, включая FORCE_HTTPS
AuthServiceProviderПолитики авторизации
EventServiceProviderСобытия, слушатели, провайдеры Socialite
RouteServiceProviderЗагрузка маршрутов и лимиты запросов
BroadcastServiceProviderКаналы WebSocket-вещания
RepositoryServiceProviderАвтоматическая регистрация репозиториев
MetaBuilderServiceProviderSEO-билдеры страниц
MailServiceProviderSMTP из настроек админ-панели
MediaServiceProviderПривязка хранилища файлов через UploaderManager
AiServiceProviderПривязка AI-сервиса через AiManager
ImageModerationServiceProviderПривязка модерации изображений через ImageModerationManager
ScoutConfigServiceProviderПоисковый движок из настроек админ-панели
HorizonServiceProvider, LogViewerServiceProviderДоступ к Horizon и Log Viewer
SlowQueryServiceProviderЛогирование SQL-запросов дольше 700 мс

Свои привязки добавляйте в AppServiceProvider::register() или в отдельный провайдер, зарегистрированный в config/app.php:

php
$this->app->bind(MyServiceInterface::class, MyService::class);

Actions ​

Бизнес-операции оформляются как Action-классы с методом execute():

php
namespace App\Actions\MyFeature;

class DoSomethingAction
{
    public function __construct(
        protected DoSomethingRepositoryInterface $repository,
    ) {}

    public function execute(User $user, array $data): Result
    {
        // бизнес-логика
    }
}

Зависимости внедряются через конструктор, Action — через параметр метода контроллера:

php
public function store(MyRequest $request, DoSomethingAction $action): RedirectResponse
{
    $action->execute($request->user(), $request->validated());

    return back();
}

Репозитории ​

Создайте интерфейс в подкаталоге Interfaces/ и реализацию рядом с ним:

app/Repositories/MyFeature/
├── Interfaces/
│   └── GetSomethingRepositoryInterface.php
└── GetSomethingRepository.php

RepositoryServiceProvider зарегистрирует привязку автоматически, если имя реализации совпадает с именем интерфейса без суффикса Interface.

Новая настройка в админ-панели ​

  1. Репозиторий: в app/Repositories/Config/MyFeature/ создайте репозиторий чтения настройки из таблицы config. Значение по умолчанию верните из репозитория или добавьте в ConfigSeeder.

  2. Контроллер: app/Http/Controllers/Admin/MyFeatureSettingsController.php с методами edit и update. Сохраняйте значение через Config::updateOrCreate('myFeature', $value) — модель сама сбросит кэш.

  3. Маршруты: в routes/admin.php:

    php
    $route->get('/settings/my-feature', [MyFeatureSettingsController::class, 'edit'])->name('settings.my-feature.edit');
    $route->put('/settings/my-feature', [MyFeatureSettingsController::class, 'update'])->name('settings.my-feature.update');
  4. Раздел: в config/admin_sections.php добавьте ключ, совпадающий с путём после /admin-panel/:

    php
    'settings/my-feature' => 'Моя настройка',
  5. Страница: Inertia-страница в resources/js/Admin/Pages/Settings/MyFeature/Edit.vue.

  6. Меню: пункт в resources/js/Admin/Layout/AppSidebar.vue с тем же путём.

WARNING

Путь, для которого нет ключа в config/admin_sections.php, доступен любому администратору. Добавляйте ключ для каждого нового раздела.

Вход через новый OAuth-провайдер ​

  1. Установите пакет провайдера из SocialiteProviders.
  2. Добавьте его обработчик в SocialiteWasCalled в EventServiceProvider::$listen.
  3. Добавьте redirect провайдера в config/services.php → oauth.
  4. Добавьте поля Client ID и Client Secret в AuthSettingsController, репозиторий настройки в app/Repositories/Config/Auth/ и форму в resources/js/Admin/Pages/Settings/Auth/Edit.vue.
  5. Добавьте провайдер в список публичных провайдеров в GetSharedInertiaConfigRepository, чтобы кнопка появилась в окне входа.

Новое хранилище файлов ​

  1. Добавьте значение и название в App\Enums\UploaderDriver.
  2. Создайте класс в app/Services/Uploader/Drivers/, унаследовав AbstractUploader.
  3. Добавьте метод create{Name}Driver() в UploaderManager.
  4. Добавьте поля учётных данных в MediaSettingsController и resources/js/Admin/Pages/Settings/Media/Edit.vue.
  1. Добавьте значение в App\Enums\SearchDriver и перевод названия в resources/lang/*/enums.php.
  2. Реализуйте драйвер в app/Services/Search/Drivers/ с интерфейсами SearchDriverInterface и SearchIndexManagementInterface, а также провайдеры поиска постов и пользователей в app/Services/Search/Providers/.
  3. Зарегистрируйте драйвер методом create{Name}Driver() в SearchManager.
  4. Передайте ключи в конфигурацию Scout в ScoutConfigServiceProvider.
  5. Добавьте поля в UpdateSearchSettingsRequest, UpdateSearchSettingsAction и resources/js/Admin/Pages/Settings/Search/Edit.vue.

Новый сервис GIF ​

  1. Добавьте значение и название в App\Enums\GifDriver.
  2. Создайте класс в app/Services/Gif/Drivers/, унаследовав AbstractGifService, и реализуйте методы endpoint(), params(), results() и next().
  3. Добавьте метод create{Name}Driver() в GifManager.
  4. Добавьте ветку с ключами сервиса в match в Admin/GifSettingsController и секцию с полями в resources/js/Admin/Pages/Settings/Gifs/Edit.vue.

Драйвер возвращает результаты в формате {results, next}.

Новый AI-провайдер ​

  1. Добавьте значение в App\Enums\AiProvider вместе с названием, моделью и адресом API по умолчанию.
  2. Добавьте метод create{Name}Driver() в AiManager. Если провайдер совместим с OpenAI Chat Completions API, метод возвращает OpenAiCompatibleService. Иначе создайте драйвер в app/Services/Ai/Drivers/, унаследовав AbstractAiService и реализовав request().

Провайдер появится в списке в Админ-панель → AI → Настройки автоматически.

Новый драйвер модерации изображений ​

  1. Добавьте значение и название в App\Enums\ImageModerationDriver.
  2. Создайте класс в app/Services/Moderation/Image/Drivers/, унаследовав AbstractImageModerationService и реализовав moderateBatch().
  3. Добавьте метод create{Name}Driver() в ImageModerationManager.
  4. Добавьте поля настроек в ImageModerationSettingsController и resources/js/Admin/Pages/AiIntegrations/ImageModerationSettings/Edit.vue.

Новый платёжный провайдер ​

  1. Добавьте значение в App\Enums\PaymentProviderDriver и перевод названия в resources/lang/*/enums.php.
  2. Реализуйте App\Services\Payments\Contracts\PaymentProviderInterface и клиент API в app/Services/Payments/Providers/{Name}/.
  3. Добавьте метод create{Name}Driver() в PaymentManager.
  4. Добавьте код провайдера в правило in:yookassa,tbank в SubscriptionPaymentProviderController и SubscriptionPaymentController, поля ключей — в SubscriptionPaymentProviderController и форму настроек.
  5. Если провайдер присылает уведомления о платежах, добавьте обработчик в App\Http\Controllers\Payments\PaymentWebhookController.

Новый язык ​

Переводы находятся в resources/lang/:

ФайлыЧто содержат
resources/lang/ru.json, resources/lang/en.jsonСтроки интерфейса сайта
resources/lang/ru/*.php, resources/lang/en/*.phpСерверные тексты: авторизация, валидация, письма, ошибки (errors.php), сообщения (messages.php), подписи значений перечислений (enums.php), мета-теги

JSON-файлы подключаются через laravel-vue-i18n. Добавляя строку, вносите её во все языки с одинаковым ключом.

Чтобы добавить язык:

  1. Создайте resources/lang/{code}.json со строками интерфейса.
  2. Создайте каталог resources/lang/{code}/ и переведите файлы из resources/lang/en/.
  3. Подключите локаль Moment.js в resources/js/app.js по примеру moment/dist/locale/ru.
  4. Добавьте код языка в правило валидации in:en,ru в app/Http/Controllers/Admin/GeneralSettingsController.php, в список языков на странице общих настроек (resources/js/Admin/Pages/Settings/General/Edit.vue) и в список допустимых локалей в app/Http/Middleware/SetLocaleFromConfig.php.

Команды, события, middleware ​

bash
php artisan make:command MyCommand
php artisan make:event SomethingHappened
php artisan make:listener HandleSomething --event=SomethingHappened
php artisan make:middleware MyMiddleware
  • Команды из app/Console/Commands/ загружаются автоматически; расписание — в app/Console/Kernel.php.
  • Слушатели регистрируются в EventServiceProvider::$listen.
  • Middleware регистрируются в app/Http/Kernel.php — глобально, в группе или как псевдоним.
  • Наблюдатели моделей подключаются атрибутом #[ObservedBy] на модели.

Локальные пакеты ​

Код можно вынести в пакет и подключить через path-репозиторий Composer:

json
{
    "repositories": [
        { "type": "path", "url": "./packages/my-package" }
    ]
}

Сервис-провайдер пакета регистрируется автоматически через extra.laravel.providers в его composer.json или вручную в config/app.php.

Форк ​

Обновления из основного репозитория забираются в форк командами:

bash
git remote add upstream https://github.com/ADamCarraway/journalphp.git
git fetch upstream
git merge upstream/master

Released under the MIT License.