PHPackages                             vasichmen/laravel-foundation - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Framework](/categories/framework)
4. /
5. vasichmen/laravel-foundation

ActiveLibrary[Framework](/categories/framework)

vasichmen/laravel-foundation
============================

Laravel Package Foundation

v2.17.15(1mo ago)01741MITPHPPHP ^8.4

Since Apr 10Pushed 1mo ago1 watchersCompare

[ Source](https://github.com/vasichmen/laravel-foundation)[ Packagist](https://packagist.org/packages/vasichmen/laravel-foundation)[ RSS](/packages/vasichmen-laravel-foundation/feed)WikiDiscussions master Synced 1mo ago

READMEChangelogDependencies (4)Versions (87)Used By (1)

- [Описание](#%D0%BE%D0%BF%D0%B8%D1%81%D0%B0%D0%BD%D0%B8%D0%B5)
- [Установка](#%D1%83%D1%81%D1%82%D0%B0%D0%BD%D0%BE%D0%B2%D0%BA%D0%B0)
- [Примеры](#%D0%BF%D1%80%D0%B8%D0%BC%D0%B5%D1%80%D1%8B-%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F)
    - [Сервис-провайдер](#appserviceprovider)
    - [Базовая авторизация](#%D0%B1%D0%B0%D0%B7%D0%BE%D0%B2%D0%B0%D1%8F-%D0%B0%D0%B2%D1%82%D0%BE%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F)
    - [Полезные трейты](#%D0%BF%D0%BE%D0%BB%D0%B5%D0%B7%D0%BD%D1%8B%D0%B5-%D1%82%D1%80%D0%B5%D0%B9%D1%82%D1%8B)
        - [Первод Enum](#enumtranslatable)
        - [Значения Enum](#enumvalues)
        - [Обновление полей enum в миграциях](#enumdbcheckalterable)
        - [Партиционирование таблиц](#partitionedbyhash)
        - [Логирование](#logger)
    - [Реквест и DTO](#%D1%80%D0%B5%D0%BA%D0%B2%D0%B5%D1%81%D1%82-%D0%B8-dto)
    - [Модель](#%D0%BC%D0%BE%D0%B4%D0%B5%D0%BB%D1%8C)
    - [Репозиторий](#%D1%80%D0%B5%D0%BF%D0%BE%D0%B7%D0%B8%D1%82%D0%BE%D1%80%D0%B8%D0%B9)
    - [Ресурс](#%D1%80%D0%B5%D1%81%D1%83%D1%80%D1%81)
    - [Презентер](#%D0%BF%D1%80%D0%B5%D0%B7%D0%B5%D0%BD%D1%82%D0%B5%D1%80)

Описание
--------

[](#описание)

Пакет с базовыми классами репозиториев, сервисов, реквестов для приложений на laravel. Базовый функционал включает в себя наиболее часто требующиеся методы и классы в любом приложении.

Установка
---------

[](#установка)

- Установить пакет

```
composer require vasichmen/laravel-foundation
```

Примеры использования
---------------------

[](#примеры-использования)

### AppServiceProvider

[](#appserviceprovider)

```
use Laravel\Foundation\Abstracts\AbstractAppServiceProvider;

class AppServiceProvider extends AbstractAppServiceProvider
{
    protected array $modelList = [
        User::class, //репозитории подключатся по классам моделей из App\Repositories как singleton, будут доступны через app(UserRepository::class)
    ];

    protected array $serviceList = [
        AuthService::class,  //сервисы подключаются как singleton и доступны через app(AuthService::class)
    ];

}
```

### Базовая авторизация

[](#базовая-авторизация)

Создаем новый мидлвар, наследуясь от [AbstractBasicAuthMiddleware.php](src%2FAbstracts%2FAbstractBasicAuthMiddleware.php)

```
use Laravel\Foundation\Abstracts\AbstractBasicAuthMiddleware;

class ExternalApiAuthMiddleware extends AbstractBasicAuthMiddleware
{
    protected string $key = 'external_api';

}
```

Регистрируем в Http\\Kernel.php в поле $routeMiddleware:

```
'external-auth' => ExternalBasicAuthMiddleware::class,
```

После чего надо добавить в конфиг auth.php секцию с настройками логинов и паролей:

```
 'basic' => [
        'external_api' => [
            'user' => env('EXTERNAL_API_USER', 'user'),
            'password' => env('EXTERNAL_API_PASSWORD', 'password'),
        ],
    ],
```

Используем как обычный мидлвар на любых роутах или группах:

```
Route::prefix('external')
    ->middleware('external-auth')
    ->group(function () {
        Route::get('test-user-token', [AuthController::class, 'testUserToken']);
    });
```

### Полезные трейты

[](#полезные-трейты)

#### [EnumTranslatable](src%2FTraits%2FEnum%2FEnumTranslatable.php)

[](#enumtranslatable)

Трейт, который можно подключить в любой enum, он добавляет метод trans() в элемент перечисления. Чтобы заработал перевод надо добавить файл `/lang//enums.php` с содержимым примерно такого вида:

```
return [
    SystemStereotypeEnum::class => [
        SystemStereotypeEnum::Typical->value => 'Типовая система',
        SystemStereotypeEnum::Real->value => 'Реальная система',
    ],
]
```

Получить перевод можно так:

```
 SystemStereotypeEnum::Typical->trans($args);
```

Параметром `$args` можно передать массив аргументов для функции laravel trans(). Этот метод используется в методе AbstractResource-&gt;getEnum()

#### [EnumValues](src%2FTraits%2FEnum%2FEnumValues.php)

[](#enumvalues)

Добавляет к перечислениям статический метод values(), который возвращает массив всех значений этого перечисления

#### [EnumDBCheckAlterable](src%2FTraits%2FMigration%2FEnumDBCheckAlterable.php)

[](#enumdbcheckalterable)

Добавляет в миграцию метод alterEnum() для изменения поля с ограничением значений.

```
$this->alterEnum('subscriptions', 'type', ['tag','space','user']);
```

#### [PartitionedByHash](src%2FTraits%2FMigration%2FPartitionedByHash.php)

[](#partitionedbyhash)

Добавляет в миграцию метод `makePartitionedTable`, создающий таблицу, разделенную на партиции (только для Postgres)

```
$this->makePartitionedTable('materials', 100, function (Blueprint $table) {
            $table->string('name');
            $table->uuid('owner_id');
            $table->uuid('author_id');
            $table->timestamps();

            $table->foreign('owner_id')->references('id')->on('users');
            $table->foreign('author_id')->references('id')->on('users');
        });
```

#### [Logger](src%2FTraits%2FLogger.php)

[](#logger)

Добавляет метод formatLogMessage, который работает по принципу sprintf, но может красиво форматировать эксепшены, массивы, коллекции итд.

### Реквест и DTO

[](#реквест-и-dto)

Реквест определяет правила валидации и (при необходимости) сообщения об ошибках, наследуется от [AbstractRequest](src%2FAbstracts%2FAbstractRequest.php). DTO определяет структуру данных для прозрачности передачи данных внутри приложения, наследуется от [AbstractDto](src%2FAbstracts%2FAbstractDto.php). Для стандартизации форматов запросов есть [GetListRequestDTO](src%2FDTO%2FGetListRequestDTO.php), в нем определены основные поля, используемые при получении списков с фильтрацией и пагинацией.

Для подключения валидации надо добавить `\Laravel\Foundation\ServiceProviders\RequestServiceProvider::class` в конфиг `app.php`

Чтоб подключить DTO к реквесту надо в реквесте переопределить поле $dtoClassName - имя класса DTO. При вызове метода `$request->validated()` проверяется существование класса DTO, его принадлежность к базовому классу и в конструктор передается массив параметров из реквеста. Внутри DTO в конструкторе ключи массива из реквеста приводятся в camelCase и данные из них записываются в соответствующие поля класса DTO. Таким образом для создания DTO достаточно только определить список полей с такими же именами, как в реквесте, но в camelCase. Для обратного преобразования в массив в DTO есть метод toArray().

#### Пример реквеста с сортировкой и постраничкой

[](#пример-реквеста-с-сортировкой-и-постраничкой)

```
use App\DTO\Requests\RefreshTokenRequestDTO;
use Laravel\Foundation\Abstracts\AbstractRequest;

class RefreshTokenRequest extends AbstractRequest
{
    use \Laravel\Foundation\Traits\RequestSortable;

    protected ?string $dtoClassName = RefreshTokenRequestDTO::class;

    public function rules()
    {
        return [
            'some_long_parameter' => 'required',
            ...$this->sorted(),
            ...$this->paginated(),
        ];
    }
}
```

#### Пример DTO

[](#пример-dto)

```
use Laravel\Foundation\Abstracts\AbstractDto;

class RefreshTokenRequestDTO extends AbstractDto
{
    public string $someLongParameter;
    public array $sort;
    public int $page;
    public int $perPage;
}
```

Такой реквест при вызове у него метода validated() вернет объект DTO. Чтобы возвращался массив, надо убрать указание DTO из реквеста. В поле `sort` в DTO вернется массив ключ=&gt;значение, где ключ - название столбца, значение - направление сортировки

Если в классе DTO поле не будет найдено, то сгенерируется исключение [DTOPropertyNotExists](src%2FExceptions%2FDTOPropertyNotExists.php). Такое поведение задано по умолчанию для самопроверки, его можно изменить, переопределив метод parseData(), передав вторым параметром false, например вот так:

```
class RefreshTokenRequestDTO extends AbstractDto
{
    protected function parseData(array $data, bool $throwIfNoProperty = true): void
    {
        parent::parseData($data, false);
    }
}
```

### Модель

[](#модель)

```
class User extends \Laravel\Foundation\Abstracts\AbstractModel
{
 ...

   // Можно переопределить метод сброса кастомного кэша
   // Метод вызывается при обновлении/удалении модели, в нем надо определить сброс кэша по кастомным тегам
   public static function invalidateCustomCache(AbstractModel $user): void
    {
        /** @var User $user */
        Cache::tags(['tag_1','tag_2'])
            ->forget(self::getCacheKey('some key data'));
    }
}
```

#### Использование кэширования при работе с моделями

[](#использование-кэширования-при-работе-с-моделями)

Подключить провайдер `\Laravel\Foundation\ServiceProviders\CacheServiceProvider::class` в конфиг app.php

Простое кэширование с автоматическим сбросом при вызове событий eloquent: updated,created,deleted:

```
$result = $abstractModel
            ->cacheFor(config('cache.ttl'))
            ->where('feed_id',$feedId)
            ->get();
```

Установка кастомных тегов кэша. Такой кэш автоматически сбрасываться не будет, для сброса надо переопределять метод invalidateCustomCache в модели

```
$result = $abstractModel
            ->cacheFor(config('cache.ttl'))
            ->cacheTags([self::getCacheTag('feeds', $feedId)]) //устанавливаем кастомные теги
            ->cacheKey(self::getCacheKey($feedId)) //задаем ключ кэша
            ->where('feed_id',$feedId)
            ->get();
```

Для корректного хранения кэша в одной БД redis от нескольких микросервисов надо задать переменную SERVICE\_NAME в .env

Методы getCacheTag, getCacheKey подключаются из трейта [CacheKeysTrait](src%2FTraits%2FCache%2FCacheKeysTrait.php)

### Репозиторий

[](#репозиторий)

Все репозитории наследуются от [AbstractRepository](src%2FAbstracts%2FAbstractRepository.php). Для каждой модели создается репозиторий и регистрируется через провайдер. Для создания select запросов используется [RepositoryBuilder](src%2FRepository%2FRepositoryBuilder.php). В нем определены основные методы фильтрации, получения связей и выборки результатов. Можно вызывать из RepositoryBuilder напрямую методы [Builder](src%2FCache%2FBuilder.php), они проксируются на внутренний объект построителя запросов. Для остальных операций есть статические методы в `AbstractRepository`: create, update, updateOrCreate, delete, getModel.

Примеры:

```
UserRepository::query()
    ->filters(['code'=>'code_1','count'=>1])
    ->query('query string',['column1','column2']) //поисковый запрос по определенным столбцам
    ->cacheFor(config('cache.ttl')) //длительность хранения кэша
    ->orderBy(['name'=>'asc','id'=>'desc'])
    ->with(['roles']) //загрузка отношений
    ->withCount(['subscribers']) //получение числа связанных объектов
    ->get(); //полная выборка в виде Collection

 UserRepository::query()
    ->filters(['code'=>'code_1', 'count'=>1]) //применение фильтров
    ->orderBy(['name'=>'asc',]) //сортировка по полю name по возрастанию
    ->limit(10) //10 элементов на странице
    ->offset(1) //первая страница
    ->paginate() //Возвращается LengthAwarePaginator

UserRepository::query()
    ->fromGetListDto($someGetListDto) //установка настроек из заданного объекта GetListRequestDTO
    ->paginate();
```

### Ресурс

[](#ресурс)

Ресурсы делаются под каждую возвращаемую сущность (обычно это модели). Все ресурсы наследуются от [AbstractResource](src%2FAbstracts%2FAbstractResource.php). По сути ресурсы повторяют собой стандартные laravel JsonResource, но дополняются некоторыми методами.

Пример ресурса:

```
use Laravel\Foundation\Abstracts\AbstractResource;

class UserResource extends AbstractResource
{
    /**
     * Transform the resource into an array.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
     */
    public function toArray($request)
    {
        return [
            'id' => $this->id,
            'name' => $this->name,
            'login' => $this->login,
            ...$this->getEnum('information_processed')
            ...$this->getRelation('roles', RoleResource::class),
        ];
    }
}
```

Метод `$this->getEnum` рендерит enum в структуру вида `{code:,name:}`. Для получения названия вызывается метод `trans` трейта [EnumTranslatable](src%2FTraits%2FEnumTranslatable.php). Если enum не расширен этим трейтом, то будет ошибка `NeedTranslatableEnumException`.

Метод `$this->getRelation` добавляет в выдачу связь eloquent модели. Первым параметром передается название связи, вторым - класс ресурса для элементов этой связи. Если связь не загружена, то ключ добавлен не будет. Если связь загружена, то в ответ добавится ключ с названием связи.

Если надо вывести коллекцию элементов через ресурс, то есть стандартный статический метод collection:

```
return new DataResultPresenter(
            'bookmarks' => BookmarkResource::collection($bookmarkCollection),
        );
```

### Презентер

[](#презентер)

Обычно не требуется создавать кастомные презенторы и всегда пользуемся [DataResultPresenter](src%2FPresenters%2FDataResultPresenter.php) для вывода простых данных или расширяем этот класс.

```
  return new DataResultPresenter([
            'token' => new TokenResource($token),
            'user' => new UserResource($user),
        ]);
```

#### Презентер с пагинацией

[](#презентер-с-пагинацией)

В качестве основного презентера с пагинацией выступает [PaginatedDataPresenter](src%2FPresenters%2FPaginatedDataPresenter.php)

Пример использования без агрегаций:

```
return new PaginatedDataPresenter($lengthAwarePaginatedData, null, SomeModelResource::class);
```

Первым параметром передается объект LengthAwarePaginator, полученный из метода getList репозитория. Если коллекция получена другим способом, то можно установить в пагинатор нужную коллекцию через метод setCollection.

Вторым параметром передается коллекция или массив агрегаций (то, что рендерится в ключе filters). Обычно агрегации это возможные значения фильтров при установленных текущих фильтрах. Стандартная реализация заточена под ответ от elasticsearch, но можно переопределить метод aggregationToArray и задать любую другую логику.

Третьим параметром передается класс ресурса, который надо применить к элементам коллекции. Если надо рендерить элемент массива не через ресурс, а каким-то другим способом, то можно передать третьим параметром null и переопределить метод bodyToArray, задать в нем свою логику обработки элемента коллекции.

###  Health Score

50

—

FairBetter than 95% of packages

Maintenance90

Actively maintained with recent releases

Popularity12

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity78

Established project with proven stability

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~12 days

Recently: every ~6 days

Total

86

Last Release

47d ago

Major Versions

v1.2.0 → v2.0.02023-07-10

PHP version history (2 changes)v1.0.0PHP ^8.1

v2.17.1PHP ^8.4

### Community

Maintainers

![](https://www.gravatar.com/avatar/b1e88e04080699dd6bc9ec4a655ed8d63e0f8463ec73f829c919577c135dd789?d=identicon)[vasichmen](/maintainers/vasichmen)

### Embed Badge

![Health badge](/badges/vasichmen-laravel-foundation/health.svg)

```
[![Health](https://phpackages.com/badges/vasichmen-laravel-foundation/health.svg)](https://phpackages.com/packages/vasichmen-laravel-foundation)
```

###  Alternatives

[bagisto/bagisto

Bagisto Laravel E-Commerce

26.2k161.6k7](/packages/bagisto-bagisto)[krayin/laravel-crm

Krayin CRM

22.0k32.8k1](/packages/krayin-laravel-crm)[unopim/unopim

UnoPim Laravel PIM

9.4k1.8k](/packages/unopim-unopim)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
