Search by

atlcom / laravel-helper

atlcomgit

Atlcom Laravel Helper library

Package info

github.com/atlcomgit/laravel-helper

pkg:composer/atlcom/laravel-helper

Fund package maintenance!

Yoomoney

Statistics

Installs: 993

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v1.04.83 2026-10-29 04:02 UTC

This package is auto-updated.

Last update: 2026-10-29 04:03:36 UTC


README

Класс помощник для Laravel добавляет функционал во фреймворк:

  • Логирование консольных команд
  • Логирование входящих/исходящих http запросов
  • Логирование изменения моделей, в том числе массовое изменение/удаление
  • Логирование query запросов через Eloquent/Database/Connection
  • Логирование запуска и выполнения очередей
  • Логирование зарегистрированных роутов и их использование
  • Логирование рендеринга blade шаблонов
  • Кеширование http входящих и исходящих запросов через PendingRequest и HttpCacheMiddleware
  • Кеширование query запросов через Eloquent/Database/Connection
  • Кеширование рендеринга blade шаблонов
  • Обработка всех исключений с отправкой логов в телеграмм
  • Внедрение Dto вместо Request в контроллеры, которое поддерживает: правила валидации, мутацию, маппинг, хуки при создании/изменении свойств
  • Регистрация singleton классов DefaultService и DefaultRepository
  • Профилирование методов класса на производительность и потребление памяти
  • Обработка сообщений телеграм бота

Версия и Git-хуки для разработки пакета

Корневой файл VERSION содержит версию с префиксом v, например v1.04.76. Хук .githooks/pre-commit повышает последнюю числовую часть и добавляет VERSION в коммит: v1.04.76 становится v1.04.77, а v1.04.99 становится v1.04.100. Хук .githooks/post-commit читает VERSION из созданного коммита и создаёт аннотированный тег на этот коммит. Он не выполняет push и не перезаписывает существующие теги.

В текущей рабочей копии вызовы подключены через .git/hooks с сохранением проверки защищённых веток и обработчика Prompt Manager. В новой копии без собственных хуков подключение выполняется один раз:

git config --local core.hooksPath .githooks
git config --local push.followTags true

Если хуки уже настроены, не заменяйте их каталог: добавьте вызов bash .githooks/pre-commit после успешных проверок и bash .githooks/post-commit после существующего обработчика. Хук, завершающийся через exit, нужно запускать в отдельной оболочке, проверяя его код завершения.

Обычный порядок работы:

git add <нужные-файлы>
git commit -m "Описание изменений"
git push

При push.followTags=true обычный push также отправляет отсутствующие на сервере аннотированные теги, достижимые из отправляемой истории, а не только последний тег. Без этой настройки используйте git push --follow-tags. Ранее созданные lightweight-теги этим способом автоматически не публикуются.

После публикации тега workflow .github/workflows/release.yml синхронизирует GitHub Release:

  • Для тегов v1.04.* обновляется один существующий релиз серии v1.04, меняется только связанный тег.
  • Для другой серии, например v1.05.*, создаётся новый релиз v1.05, если его ещё нет.
  • Заголовок, описание и загруженные вложения существующего релиза сохраняются; архивы исходников соответствуют новому тегу.
  • Новая серия получает автоматически сформированные GitHub заметки. Серия определяется по тегу релиза, поэтому переименование заголовка не приводит к созданию дубликата.
  • Запуски одной серии выполняются последовательно и выбирают максимальный опубликованный patch; поздний запуск для старого тега не откатывает релиз назад. Старые теги не перемещаются и не удаляются.
  • Неоднозначные релизы одной серии, черновики, prerelease и неизменяемые релизы не изменяются автоматически; причина остановки отображается в Actions. Сохранённые вложения не пересобираются.

Используется встроенный GITHUB_TOKEN с правом contents: write, отдельный секрет не нужен. Для запуска workflow должен попасть в коммит с тегом и быть отправлен на GitHub; простое сохранение файла локально не меняет опубликованные релизы. GitHub Actions должны быть разрешены для репозитория. Рекомендуемый выпуск: отправлять ветку master и теги вместе, чтобы версия workflow совпадала с основной веткой. GitHub ограничивает работу встроенного токена для целевых коммитов с workflow, отличающимся от основной ветки.

Уже опубликованный тег можно обработать через Actions → «Синхронизация GitHub Release» → Run workflow, указав, например, v1.04.77. Для ручного запуска workflow сначала должен появиться в основной ветке. Это синхронизирует всю серию с максимальным patch и не создаёт новый тег или коммит.

Повтор после отмены коммита использует уже подготовленную версию без дополнительного повышения. Занятые локальные номера пропускаются; перед работой в нескольких клонах синхронизируйте теги через git fetch --tags. Одновременное выделение номеров между разными клонами не координируется. Не редактируйте VERSION вручную: изменённое значение, не совпадающее с исходной или следующей версией, останавливает коммит. Старшие части версии и ведущие нули сохраняются; patch ограничен 18 цифрами.

Используйте коммит подготовленного индекса или git commit -a, а не git commit <пути> / --only. Пустые коммиты и обход pre-commit через --no-verify не повышают версию. Не переписывайте уже опубликованные релизы через amend/rebase: прежние теги сохраняют исходные коммиты. При ошибке post-commit сам коммит остаётся созданным; после устранения причины тег можно восстановить командой bash .githooks/post-commit. Повтор для уже правильно установленного тега ничего не меняет.

Проверка синтаксиса без создания коммитов и тегов:

bash -n .githooks/pre-commit
bash -n .githooks/post-commit

Подключение пакета

1. Установка пакета
composer require atlcom/laravel-helper
2. Публикация настроек и миграций пакета
php artisan vendor:publish --tag="laravel-helper"
3. Настройка параметров пакета в .env

/config/laravel-helper.php

/.env.example

4. Оптимизация приложения
php artisan optimize
5. Миграция базы данных
php artisan migrate

Примеры логирования

ConsoleLog

Логирование выполнения консольных команд

use Atlcom\LaravelHelper\Defaults\DefaultCommand;

class ExampleCommand extends DefaultCommand
{
	protected ?bool $withTelegramLog = true;
	protected mixed $telegramComment = null;
	protected ?bool $withConsoleLog = true;

	public function handle(): int
	{
		$this->outputBold($this->description);
		$this->outputEol();

		// ...

		$this->telegramLog = isLocal() || isDev() || isProd();
		$this->telegramComment = 'Комментарий';

		return self::SUCCESS;
	}
}

// или

Artisan::call(ExampleCommand::class, ['--telegram', '--log']);
HttpLog

Логирование входящих запросов в таблице helper_http_logs

use Atlcom\LaravelHelper\Middlewares\HttpLogMiddleware;
use Illuminate\Support\Facades\Route;

Route::get('/', function (Request $request) {
    return '';
})->middleware(HttpLogMiddleware::class);

Логирование исходящих запросов в таблице helper_http_logs

use Atlcom\LaravelHelper\Defaults\DefaultService;
use Atlcom\LaravelHelper\Enums\HttpLogHeaderEnum;
use Illuminate\Support\Facades\Http;

class HttpServiceProvider
{
	public function boot(): void
	{
		Http::macro(
            'exampleRu',
            fn () => Http::baseUrl(rtrim(config('example.url'), '/'))
                ->replaceHeaders(HttpLogService::getLogHeaders(HttpLogHeaderEnum::SmsRu))
        );
	}
}

class ExampleService extends DefaultService
{
	public function getHttp(): Http|PendingRequest
    {
        return Http::exampleRu();
    }

	public function request(): void
	{
		$response = $this->getHttp()->post("/", []);

		// ...
	}
}

Тело запроса и ответа длиннее HELPER_HTTP_LOG_DATA_MAX_LENGTH байт (по умолчанию 1 МБ, 0 — без ограничения) обрезается при создании лога без разрыва символов UTF-8, в info добавляется request_data_truncated или response_data_truncated, а *_data_size показывает полный размер. Обрезанное тело уже не является JSON, поэтому в таблицу попадает, как любой текст не в формате JSON, его начало до 2048 символов; тело в пределах лимита сохраняется как прежде. Для ответа-файла, удалённого после отправки (deleteFileAfterSend), размер и тип берутся из заголовков ответа.

В приложении с опубликованным конфигом config/laravel-helper.php добавьте в раздел http_log ключ 'data_max_length' => (int)env('HELPER_HTTP_LOG_DATA_MAX_LENGTH', 1048576): без него переменная окружения не читается и действует значение по умолчанию 1 МБ.

Исключения http_log.in.exclude и http_log.out.exclude проверяются по полным телам: обрезка не отменяет совпадение за границей лимита и не создаёт ложное совпадение с префиксом. Для усечённого поля сохраняется только результат проверки, остальные поля проверяются при отправке задания. Подробные условия и проверки описаны в правиле HTTP-журналирования.

MailLog

Логирование отправки писем в таблице helper_mail_logs

use Atlcom\LaravelHelper\Defaults\DefaultMailable;
use Illuminate\Support\Facades\Mail;

class ExampleMailable extends DefaultMailable
{
    // ...
}

Mail::to('test@test.ru')->send(new ExampleMailable());
ModelLog

Логирование изменений модели в таблице helper_model_logs (withModelLog)

use Atlcom\LaravelHelper\Defaults\DefaultModel;
use Atlcom\LaravelHelper\Traits\ModelLogTrait;
use Illuminate\Database\Eloquent\Model;

// class Example extends Model
class Example extends DefaultModel
{
	// use ModelLogTrait;

    protected ?bool $withModelLog = true;
    public $guarded = ['id'];
    public $timestamps = true;
    protected $casts = [];
}

class ExampleRepository
{
	public function find(): void
	{
		Example::query()->withModelLog()->first();
	}

	public function get(): void
	{
		Example::query()->withModelLog()->get();
	}

	public function create(): void
	{
		Example::query()->withModelLog()->create([]);
	}

	public function update(): void
	{
		Example::query()->withModelLog()->update([]);
	}

	public function delete(): void
	{
		Example::query()->withModelLog()->delete();
	}
}
ProfilerLog

Логирование профилирования методов класса

use Atlcom\LaravelHelper\Defaults\DefaultController;

class Example extends DefaultProfiler
{
	public function example() {}
}

new Example()->_example();

// или

class Example
{
	use ProfilerLogTrait;

	public static function example() {}
}

Example::_example();
RouteLog

Логирование зарегистрированных роутов в таблице helper_route_logs

use Illuminate\Support\Facades\Route;

Route::get('/example', [ExampleController::class, 'example']);
QueryLog

Логирование query запросов в таблице helper_query_logs (withQueryLog или withLog)

use Atlcom\Hlp;
use Atlcom\LaravelHelper\Defaults\DefaultController;
use Atlcom\LaravelHelper\Defaults\DefaultDto;
use Atlcom\LaravelHelper\Defaults\DefaultModel;
use Atlcom\LaravelHelper\Defaults\DefaultRepository;
use Atlcom\LaravelHelper\Traits\ModelLogTrait;
use Illuminate\Database\Eloquent\Model;

// class Example extends Model
class Example extends DefaultModel
{
	// use ModelTrait;
}

class ExampleRepository extends DefaultRepository
{
	public function example(ExampleDto $dto)
	{
		DB::withQueryLog()->select('select * from users');
		DB::withQueryLog()->statement('select * from users');
		DB::table('users')->withQueryLog()->first();
		DB::table('users')->withQueryLog()->insert(['name' => Hlp::fakeName()]);
		DB::table('users')->withQueryLog()->update(['name' => Hlp::fakeName()]);

		Example::withQueryLog()->first();
		Example::withQueryLog()->create(['name' => Hlp::fakeName()]);
		Example::query()->withQueryLog()->count();
		Example::query()->withQueryLog()->exists();
		Example::first()->fill(['name' => Helper::fakeName()])->withQueryLog()->save();
		Example::query()->withQueryLog()->where('id', '>=', 1)->update(['name' => Helper::fakeName()]);
		Example::query()->withQueryLog()->where('id', Example::orderByDesc('id')->first()?->id)->delete();
	}
}

Ошибки инфраструктуры QueryLog не изменяют результат бизнес-запроса и не заменяют его исходное исключение. Для асинхронной записи failed-логов из PostgreSQL-транзакций используйте очередь, независимую от основного DB-соединения:

HELPER_QUERY_LOG_QUEUE_CONNECTION=redis
QueueLog

Логирование очередей в таблице helper_queue_logs (withQueueLog или withLog)

use Atlcom\LaravelHelper\Defaults\DefaultDto;
use Atlcom\LaravelHelper\Defaults\DefaultJob;

class ExampleDto extends DefaultDto
{

}

class ExampleJob extends DefaultJob
{
    public bool $withQueueLog = false;

    public function __invoke(): void {}
}

// или

dispatch((new ExampleJob())->withQueueLog());
ViewLog

Логирование рендеринга blade шаблонов в таблице helper_view_logs (withViewLog или withLog)

use Atlcom\LaravelHelper\Defaults\DefaultController;

class ExampleController extends DefaultController
{
	public function example()
	{
		return $this->withViewLog()->view(view: 'example', data: ['test' => true], mergeData: []);
		return $this->withViewLog()->view(view: 'example', data: ['time' => now()], ignoreData: ['time']);
	}
}

Примеры кеширования

HttpCache

Кеширование входящих http запросов (withCache)

use Atlcom\LaravelHelper\Middlewares\HttpCacheMiddleware;
use Illuminate\Support\Facades\Route;

Route::get('/', function (Request $request) {
    return '';
})->middleware(HttpCacheMiddleware::class);

Кеширование исходящий http запросов

use Illuminate\Support\Facades\Http;

Http::withCache()->get('https://timeapi.io/api/Time/current/zone?timeZone=UTC', []);
Http::withCache()->post('https://timeapi.io/api/Time/current/zone?timeZone=UTC', []);
QueryCache

Кеширование query запросов (withQueryCache или withCache)

use Atlcom\Hlp;
use Atlcom\LaravelHelper\Defaults\DefaultController;
use Atlcom\LaravelHelper\Defaults\DefaultDto;
use Atlcom\LaravelHelper\Defaults\DefaultRepository;
use Atlcom\LaravelHelper\Traits\ModelLogTrait;
use Illuminate\Database\Eloquent\Model;

class Example extends Model
{
	use ModelTrait;
}

class ExampleRepository extends DefaultRepository
{
	public function example(ExampleDto $dto)
	{
		DB::withQueryCache()->select('select * from users');
		DB::table('users')->withQueryCache()->first();

		Example::withQueryCache()->first();
		Example::query()->withQueryCache()->count();
		Example::query()->withQueryCache()->exists();
	}
}
ViewCache

Кеширование рендеринга blade шаблонов (withViewCache или withCache)

use Atlcom\LaravelHelper\Defaults\DefaultController;

class ExampleController extends DefaultController
{
	public function example()
	{
		return $this->withViewCache()->view(view: 'example', data: ['time' => now()], ignoreData: ['time']);
	}
}

Примеры расширения классов

DefaultCommand

Расширение класса консольных команд

use Atlcom\LaravelHelper\Defaults\DefaultCommand;

class ExampleCommand extends DefaultCommand
{
	public function handle(): int
}
DefaultController и DefaultDto

Расширение класса контроллера с внедрением Dto (замена Request)

use Atlcom\LaravelHelper\Defaults\DefaultController;
use Atlcom\LaravelHelper\Defaults\DefaultDto;

class ExampleDto extends DefaultDto
{
	public int $id;

	public function rules(): array
	{
		return [
			'id' => ['require', 'numeric'],
		];
	}
}

class ExampleController extends DefaultController
{
	public function example(ExampleDto $dto)
	{
		return $dto->id;
	}
}

Ошибки Laravel-валидации возвращаются со статусом 422 и содержат объект errors, пригодный для привязки сообщений к полям формы.

DefaultEvent

Расширение класса событий

use Atlcom\LaravelHelper\Defaults\DefaultEvent;

class ExampleEvent extends DefaultEvent
{
    public function __construct() {}
}
DefaultException

Расширение класса исключений

use Atlcom\LaravelHelper\Defaults\DefaultException;

class ExampleException extends DefaultException
{
}
DefaultJob

Расширение класса задач для очередей

use Atlcom\LaravelHelper\Defaults\DefaultJob;

class ExampleJob extends DefaultJob
{
    public function __invoke(): void {}
}
DefaultListener

Расширение класса слушателя события

use Atlcom\LaravelHelper\Defaults\DefaultListener;

class ExampleListener extends DefaultListener
{
}
DefaultLogger

Расширение класса логирования

use Atlcom\LaravelHelper\Defaults\DefaultLogger;

class ExampleLogger extends DefaultLogger
{
}
DefaultMailable

Расширение класса отправки писем

use Atlcom\LaravelHelper\Defaults\DefaultMailable;

class ExampleMailable extends DefaultMailable
{
}
DefaultModel

Расширение класса модели

use Atlcom\LaravelHelper\Defaults\DefaultModel;

class ExampleModel extends DefaultModel
{
}
DefaultProfiler

Расширение класса для профилирования методов

use Atlcom\LaravelHelper\Defaults\DefaultProfiler;

class ExampleModel extends DefaultProfiler
{
}
DefaultRepository

Расширение класса репозитория

use Atlcom\LaravelHelper\Defaults\DefaultRepository;

class ExampleRepository extends DefaultRepository
{
}
DefaultRequest

Расширение класса запроса

use Atlcom\LaravelHelper\Defaults\DefaultRequest;

class ExampleRequest extends DefaultRequest
{
}
DefaultResource

Расширение класса ресурса

use Atlcom\LaravelHelper\Defaults\DefaultResource;

class ExampleResource extends DefaultResource
{
}
DefaultService

Расширение класса сервиса

use Atlcom\LaravelHelper\Defaults\DefaultService;

class ExampleService extends DefaultService
{
}
DefaultTest

Расширение класса теста

use Atlcom\LaravelHelper\Defaults\DefaultTest;

class ExampleTest extends DefaultTest
{
}

Итоговый отчёт после всех тестов подключается отдельно: см. «Итоговый отчёт тестов».

Итоговый отчёт тестов

Расширение PHPUnit TestReportExtension после всех тестов печатает отчёт: время прогона и суммарное время в тестах, ускорение и разброс загрузки процессов paratest, пик памяти, число тестов по результатам (успешно, с ошибкой, пропущено, не завершено, рискованные), утверждения, среднюю длительность и скорость, минимальную, медианную, p95 и максимальную длительность, распределение по интервалам, самые медленные тесты и классы, список тестов с ошибкой.

Подключение в phpunit.xml:

<extensions>
    <bootstrap class="Atlcom\LaravelHelper\Testing\TestReportExtension">
        <!-- Тест считается медленным, если дольше slowSeconds секунд; slowLimit — длина списка медленных тестов -->
        <parameter name="slowSeconds" value="1"/>
        <parameter name="slowLimit" value="10"/>
    </bootstrap>
</extensions>
  • Длительность теста измеряется от начала подготовки до завершения, вместе с setUp и tearDown.
  • Обычный PHPUnit печатает отчёт после собственных итогов. При запуске через paratest воркеры сохраняют результаты во временный каталог sys_get_temp_dir(), а главный процесс печатает общий отчёт после итогов paratest и удаляет каталог. Каталог передаётся воркерам через переменную окружения LARAVEL_HELPER_TESTING_REPORT_DIR.
  • Время прогона считается от запуска процесса PHP и включает загрузку, поэтому оно больше строки Time: PHPUnit.
  • Ошибки setUpBeforeClass и tearDownAfterClass учитываются так же, как в итогах PHPUnit.
  • Отчёт не печатается с --teamcity (вывод для IDE) и --no-output и не меняет код завершения тестов.
  • Цвет включён независимо от --colors и отключается стандартной переменной окружения NO_COLOR.
  • Проверено на PHPUnit 10.5 и 11.5, paratest 7.8.

Пример сокращённого отчёта параллельного прогона:

═════════════════════════════════ Итоги тестов ═════════════════════════════════
  Время прогона     62.91 s · в тестах 635.70 s · ускорение ×10.1
  Процессы          12 · в тестах от 52.29 до 53.49 s на процесс · пик памяти 42.0 MB
  Тесты             2320 · успешно 2318 · с ошибкой 1 · пропущено 1
  Утверждения       24957
  Средняя скорость  0.274 s на тест · 37 тестов в секунду
  Длительность      мин 0.000 s · медиана 0.147 s · p95 0.957 s · макс 4.058 s
  Распределение     до 0.1 s: 743 · 0.1–0.5 s: 1256 · 0.5–1 s: 217 · больше 1 s: 104
  Самый быстрый     0.000 s  UserDtoTest::createsFromArray
  Самый медленный   4.058 s  PaymentRoutesTest::partialPaymentsKeepOneBalance

  Медленные тесты, больше 1 s: 104 · 169.80 s · 26.7% времени в тестах
    4.058 s  PaymentRoutesTest::partialPaymentsKeepOneBalance
    3.467 s  PartnerPaymentTest::regenerationChecksCurrentPartner
    … и ещё 102

  Самые долгие классы:
     115.30 s  83 теста     PaymentRoutesTest
      50.96 s  177 тестов   SupportChatControllerTest

  Тесты с ошибкой: 1
    ✘ OrderServiceTest::cancelsExpiredOrder — провал проверки
════════════════════════════════════════════════════════════════════════════════

Примеры телеграм бота

Документация TelegramBot

События хелпера

ConsoleLogEvent::class // Событие логирования консольных команд
ExceptionEvent::class // Событие логирования исключений
HttpCacheEvent::class // Событие кеширования http запросов
HttpLogEvent::class // Событие логирования http запросов
ModelLogEvent::class // Событие логирования моделей
ProfilerLogEvent::class // Событие логирования профилирования методов класса
RouteLogEvent::class // Событие логирования роутов
QueryCacheEvent::class // Событие кеширования query запросов
QueryLogEvent::class // Событие логирования query запросов
QueueLogEvent::class // Событие логирования очередей
TelegramBotEvent::class // Событие входящих/исходящих сообщений бота телеграм
TelegramBotMessageEvent::class // Событие сохранения сообщений бота телеграм
TelegramLogEvent::class // Событие логирования отправки сообщения в телеграм
ViewCacheEvent::class // Событие кеширования рендеринга blade шаблонов
ViewLogEvent::class // Событие логирования рендеринга blade шаблонов

Хелперы

Список вспомогательных функций
lhConfig() // Возвращает настройки хелпера
isDebug() // Возвращает флаг окружения APP_DEBUG
isDebugData() // Возвращает флаг окружения APP_DEBUG_DATA
isDebugTrace() // Возвращает флаг окружения APP_DEBUG_TRACE
isLocal() // Проверяет на локальное окружение
isDev() // Проверяет на dev окружение
isTesting() // Проверяет на тестовое окружение
isProd() // Проверяет на боевое окружение
isCommand() // Проверяет на запуск приложения из консольной команды
isHttp() // Проверяет на запуск приложения из http запроса
isQueue() // Проверяет на запуск приложения из очереди
queue() // Ставит job в очередь и запускает её
sql() // Возвращает сырой sql запрос c заменой плейсхолдеров
json() // Возвращает json строку
telescope() // Включает/Отключает логи telescope
telegram() // Отправляет сообщение в телеграм
user() // Возвращает модель авторизованного пользователя или null
ip() // Возвращает ip адрес из запроса
uuid() // Возвращает uuid v7 или v4 (для более ранних версий Laravel)