duotek / laravel-basic-components
Laravel basic components
Requires
- php: >=8.0
- intervention/image: ^2.5
- laravel/framework: ^8.3|^9.11|^11.0
- dev-main
- 1.9.0
- 1.8.48
- 1.8.47
- 1.8.46
- 1.8.45
- 1.8.44
- 1.8.43
- 1.8.42
- 1.8.41
- 1.8.40
- 1.8.39
- 1.8.38
- 1.8.37
- 1.8.36
- 1.8.35
- 1.8.34
- 1.8.33
- 1.8.32
- 1.8.31
- 1.8.30
- 1.8.29
- 1.8.28
- 1.8.27
- v1.8.26.x-dev
- 1.8.26
- 1.8.25
- 1.8.24
- 1.8.23
- 1.8.22
- 1.8.21
- 1.8.20
- 1.8.19
- 1.8.18
- 1.8.17
- 1.8.16
- 1.8.15
- 1.8.14
- 1.8.13
- 1.8.12
- 1.8.11
- 1.8.10
- 1.8.9
- 1.8.8
- 1.8.7
- 1.8.6
- 1.8.5
- 1.8.4
- 1.8.3
- 1.8.2
- 1.8.1
- 1.8.0
- 1.7.55
- 1.7.54
- 1.7.53
- 1.7.52
- 1.7.51
- 1.7.50
- 1.7.49
- 1.7.48
- 1.7.47
- 1.7.46
- 1.7.45
- 1.7.44
- 1.7.43
- 1.7.42
- 1.7.41
- 1.7.40
- 1.7.39
- 1.7.38
- 1.7.37
- 1.7.36
- 1.7.35
- 1.7.34
- 1.7.33
- 1.7.32
- 1.7.31
- 1.7.30
- 1.7.29
- 1.7.28
- 1.7.27
- 1.7.26
- 1.7.25
- 1.7.24
- 1.7.23
- 1.7.22
- 1.7.21
- 1.7.20
- 1.7.19
- 1.7.18
- 1.7.17
- 1.7.16
- 1.7.15
- 1.7.14
- 1.7.13
- 1.7.12
- 1.7.11
- 1.7.10
- 1.7.9
- 1.7.8
- 1.7.7
- 1.7.6
- 1.7.4
- 1.7.3
- 1.7.2
- 1.7.1
- 1.7.0
- 1.6.37
- 1.6.36
- 1.6.35
- 1.6.34
- 1.6.33
- 1.6.32
- 1.6.31
- 1.6.30
- 1.6.29
- 1.6.28
- 1.6.27
- 1.6.26
- 1.6.25
- 1.6.24
- 1.6.23
- 1.6.22
- 1.6.21
- 1.6.20
- 1.6.19
- 1.6.18
- 1.6.17
- 1.6.16
- 1.6.15
- 1.6.14
- 1.6.13
- 1.6.12
- 1.6.11
- 1.6.10
- 1.6.9
- 1.6.8
- 1.6.7
- 1.6.6
- 1.6.5
- 1.6.4
- 1.6.3
- 1.6.2
- 1.6.1
- 1.6.0
- 1.5.0
- 1.4.0
- 1.3.0
- 1.2.1
- 1.2.0
- 1.1.4
- 1.1.3
- 1.1.2
- 1.1.1
- 1.1.0
- 1.0.0
This package is auto-updated.
Last update: 2025-05-13 16:01:36 UTC
README
- Установка
- Компоненты и как их использовать
- Трейт
UploadFile (Duotek\LaravelBasicComponents\Traits\Model\UploadFile\UploadFile)
- Класс
Service
(Duotek\LaravelBasicComponents\Service
) - Класс
Definition
(Duotek\LaravelBasicComponents\Definition\Definition
) - Класс
PanelForm
(Duotek\LaravelBasicComponents\PanelForm\PanelForm
) - Класс
QueryBuilder
(Duotek\LaravelBasicComponents\QueryBuilder
) - Класс
PanelSet
(Duotek\LaravelBasicComponents\PanelSet\PanelSet
) - Класс
PanelSetSortable
(Duotek\LaravelBasicComponents\PanelSetSortable\PanelSetSortable
) - Класс
BrowserFilterPresetController
(Duotek\LaravelBasicComponents\Controllers\BrowserFilterPresetController
)
- Трейт
Установка
- Устанавливаем пакет:
composer require duotek/laravel-basic-components
- Выполняем команду (копируем обязательные настройки из пакета):
php artisan vendor:publish --tag="laravel-basic-components-config"
Если в проекте не используется browser
(компонент, который используется в админке), то пункты 4
и 5
не обязательны.
- Извлекаем миграцию для пресетов браузера:
php artisan vendor:publish --tag="laravel-basic-components-migrations"
- Выполняем команду:
php artisan migrate
Компоненты и как их использовать
Трейт UploadFile
(Duotek\LaravelBasicComponents\Traits\Model\UploadFile\UploadFile
)
Зачем нужен?
1) Сохранение\Обновление файлов картинок из параметров Request
с учетом конфигурации в модели
( в модели определяется нарезать ли картинки и как нарезать )
2) При обновлении также удаляются предыдущие файлы с сервера
Как использовать?
- Трейт вставляется в модель, которая имеет файлы в свойствах.
Для правильной конфигурации необходимо в свойство модели$filePropertiesWithSettings
поместить конфиг по примеру ниже:... use UploadFile; ... /** * Если есть константа UPLOAD_FILE_TRAIT_DELETING_FILES и она true, * то при удалении модели также будут удаляться связанные с ней изображения (и нарезки) */ const UPLOAD_FILE_TRAIT_DELETING_FILES = true;
public static $filePropertiesWithSettings = [
'picture' => [
'200' => [200, 200, FileHelper::RESIZE_TYPE_SMART],
'400' => [400, 400, FileHelper::RESIZE_TYPE_FIT_INTO_AREA_WITH_PROPORTIONS],
'600' => [600, 600, FileHelper::RESIZE_TYPE_FIT_INTO_AREA_WITH_PROPORTIONS_AND_COLOR_CANVAS, '#ffffff', 'center'], // Возможные значение 4-го параметра: top-left, top, top-right, left, center, right, bottom-left, bottom, bottom-right
],
'background_picture' => null, // null означает сохранить как есть (без нарезок)
]; ...
2. Для корректного вывода в ресурсах делаем так:
... class UserResource extends JsonResource {
/* @var $resource User */
public $resource;
/**
* @throws InvalidFilePropertiesWithSettingsPropertyConfiguration
*/
public function toArray($request): array
{
return [
'id' => $this->resource->id,
'photo' => $this->resource->getFileLinksBySettings('photo'),
'photo2' => $this->resource->getFileLinksBySettings('photo2', 'http://api.tip.ru'), // возможность кастомно задать домен, не смотря на UPLOAD_FILE_DOMAIN
];
}
}
3. Если нужно чтобы файлы отдавались с абсолютным путем через метод `getFileLinksBySettings` можно:
* Глобально добавить `UPLOAD_FILE_DOMAIN=http://api.tip.ru` в `.env` файл в корне проекта
* Локально добавить `->getFileLinksBySettings('photo', 'http://api.tip.ru')`
4. Если нужно в обособленном ресурсе, не привязываясь к классу, вывести изображения по конфигу модели:
... use Duotek\LaravelBasicComponents\Helpers\FileHelper\FileHelper; ... class UserResource extends JsonResource {
/* @var $resource User */
public $resource;
/**
* @throws InvalidFilePropertiesWithSettingsPropertyConfiguration
*/
public function toArray($request): array
{
return [
'id' => $this->resource->id,
'photo1' => FileHelper::getFileLinksBySettings(User::class, 'photo1', $this->resource->photo1),
'photo2' => FileHelper::getFileLinksBySettings(User::class, 'photo2', $this->resource->photo2),
];
}
}
### <a name="service">Класс `Service` (`Duotek\LaravelBasicComponents\Service`)</a>
#### Зачем нужен?
Сервис является **обязательным** для использования при `POST`-действиях.
Например: `Создание клиента`, `Изменение статуса заказа`, `Обновления данных клиента`, `Удаления клиента`
#### Как использовать?
1. Создаем сервис
namespace App\Services\Finance\BalanceInvoice;
use App\Models\Finance\BalanceInvoice as FinanceBalanceInvoice; use Duotek\LaravelBasicComponents\Service\Service;
class FinanceBalanceInvoiceCreateService extends Service {
public function getRules(): array
{
return [
'user_id' => 'required|int|exists:users_users,id',
'base_type_id' => 'required|string',
'offer_id' => 'required|int|exists:market_offers_offers,id',
'state_id' => 'required|string',
'total' => 'required|numeric',
];
}
public function handle(): FinanceBalanceInvoice
{
$balanceInvoice = new FinanceBalanceInvoice();
$balanceInvoice->user_id = $this->params['user_id'];
$balanceInvoice->offer_id = $this->params['offer_id'];
$balanceInvoice->base_type_id = $this->params['base_type_id'];
$balanceInvoice->state_id = $this->params['state_id'];
$balanceInvoice->total = $this->params['total'];
$balanceInvoice->save();
return $balanceInvoice;
}
}
2. Применяем в контроллере
... public function create(Request $request, FinanceBalanceInvoiceCreateService $financeBalanceInvoiceCreateService): JsonResponse {
return response()->json(
new FinanceBalanceInvoiceResource(
$financeBalanceInvoiceCreateService->setParams($request)->handle()
)
);
} ...
#### Важные нюансы
1. `params` в методе `getRules` доступны в чистом виде (всё что приходит с `Request` или `array`)
2. `params` в методе `handle` очищены от полей, которые отсутствуют в `getRules`
### <a name="definition">Класс `Definition` (`Duotek\LaravelBasicComponents\Definition\Definition`)</a>
#### Зачем нужен?
Используется для хранения констант в определенном формате.
Имеет множество методов для удобной работы с ними.
#### Как использовать?
namespace App\Definitions\Finance\Balance;
use Duotek\LaravelBasicComponents\Definition\Definition;
class InvoiceBaseDefinition extends Definition {
const OFFER = 'OFFER';
public static function items(): array
{
return [
self::OFFER => [
'id' => self::OFFER,
'title' => 'Оплата объявления',
],
];
}
}
#### Как локализовать `title`?
##### Как заполнить локализацию?

##### Как вызвать все константы с учётом локализации?
$definition::getItems(withLocale:true) $definition::getItems(withLocale:true, specifiedLocale:'ru')
##### Как вызвать одну константу с учётом локализации?
$definition::getItemByConst('RUS'); $definition::getItemByConst(const:'RUS', withLocale:true, specifiedLocale:'ru'); $definition::getItemByConst(const:'RUS', withLocale:true);
### <a name="panelForm">Класс `PanelForm` (`Duotek\LaravelBasicComponents\PanelForm\PanelForm`)</a>
#### Зачем нужен?
Используется в качестве соглашения с библиотекой на фронтенде для данных, которые должны быть получены для формы.
> Используется исключительно в админках.
#### Как использовать?
1. Создаем `PanelForm`
namespace App\PanelForms\Backoffice\Users;
use App\Http\Resources\Backoffice\Users\User\UserResource; use App\Models\Users\User; use Duotek\LaravelBasicComponents\PanelForm\PanelForm;
class UserPanelForm extends PanelForm {
protected string $model = User::class;
protected string|null $resource = UserResource::class;
protected function getInputs(): array
{
return [];
}
}
2. Применяем в контроллере
... public function form(UserPanelForm $userPanelForm): JsonResponse {
return response()->json($userPanelForm->get());
} ...
### <a name="queryBuilder">Класс `QueryBuilder` (`Duotek\LaravelBasicComponents\QueryBuilder`)</a>
#### Зачем нужен?
Нужен для построения сложных запросов с участнием `Illuminate\Http\Request` и соответственно инкапсуляции логики
#### Как использовать?
1. Создаем `QueryBuilder`
namespace App\Http\QueryBuilders;
use App\Models\Finance\BalanceTransaction; use Duotek\LaravelBasicComponents\QueryBuilder\QueryBuilder; use Illuminate\Database\Eloquent\Collection;
class FinanceBalanceTransactionQueryBuilder extends QueryBuilder {
public function handle(): Collection|array
{
$balanceTransactionQuery = BalanceTransaction::query();
if ($this->request->has('user_id')) {
$balanceTransactionQuery->where('user_id', $this->request->get('user_id'))
}
return $balanceTransactionQuery->get();
}
}
2. Используем в контроллере
... public function list(Request $request): JsonResponse {
return response()->json(
FinanceBalanceTransactionResource::collection(
(new FinanceBalanceTransactionQueryBuilder($request))->handle()
)
);
} ...
#### Важные нюансы
1. `params` в методе `getRules` доступны в чистом виде (всё что приходит с `Request` или `array`)
2. `params` в методе `handle` очищены от полей, которые отсутствуют в `getRules`
### <a name="panelSet">Класс `PanelSet` (`Duotek\LaravelBasicComponents\PanelSet\PanelSet`)</a>
#### Зачем нужен?
Используется в качестве соглашения с библиотекой на фронтенде для определения интерфейса на фронтенде через бэкенд.
> Используется исключительно в админках.
#### Как использовать?
1. Создаем `PanelSet`
namespace App\PanelSet;
use App\Http\Resources\Web\MarketOffer\MarketOfferResource; use App\Models\Market\Offer\Offer as MarketOffer; use Duotek\LaravelBasicComponents\PanelSet\Filters\BooleanFilter; use Duotek\LaravelBasicComponents\PanelSet\Filters\SelectFilter; use Duotek\LaravelBasicComponents\PanelSet\PanelSet;
class MarketOfferPanelSet extends PanelSet {
protected string $model = MarketOffer::class;
public string $resource = MarketOfferResource::class;
public string $browserId = 'market_offers';
/**
* Если необходимо передать кастомный способ поиска отличный от LIKE, делаем как в примере 1
*/
public array $fieldsForDefaultSearchFilter = ['costs_type_id', 'payment_type_id'];
protected array $defaultOrderBy = [
'created_at' => 'desc',
// Пример с мапингом: принимаем `created_at`, а в запрос кладем `tips_codes.created_at`
// 'created_at as tips_codes.created_at' => 'desc'
// Для кастомизации смотри "Пример 2"
];
public array $availableOrderBy = [
'created_at',
// Пример с мапингом: принимаем `created_at`, а в запрос кладем `tips_codes.created_at`
// 'created_at as tips_codes.created_at'
// Для кастомизации смотри "Пример 3"
];
public function __construct()
{
parent::__construct();
/**
* Пример 1
*/
$this->fieldsForDefaultSearchFilter = [
'costs_type_id',
'payment_type_id',
function (Builder $query, string|null $searchString) {
$query->OrWhere('id', '=', $searchString);
}
];
/**
* Пример 2
*/
$this->defaultOrderBy = [
'created_at' => function (\Illuminate\Database\Eloquent\Builder $queryBuilder) {
// Пример кастомизации: здесь пишем как обработать поле 'updated_at'
$queryBuilder->orderByRaw('<RAW SQL QUERY>');
}
];
/**
* Пример 3
*/
$this->availableOrderBy = [
'created_at' => function (\Illuminate\Database\Eloquent\Builder $queryBuilder, $field, $direction) {
// Пример кастомизации: здесь пишем как обработать поле 'updated_at'
$queryBuilder->orderByRaw('<RAW SQL QUERY>');
}
];
}
protected function setFilters()
{
$this->filtersManager->add(SelectFilter::class, 'product_id', 'Продукт', function (SelectFilter $selectFilter) {
$exampleOptions = [
0 => [
'id' => 1,
'title' => 'Продукт1'
],
1 => [
'id' => 2,
'title' => 'Продукт2'
],
];
$selectFilter->setOptions($exampleOptions);
});
$this->filtersManager->add(BooleanFilter::class, 'is_price_per_one_is_set', 'Тест', function (BooleanFilter $booleanFilter) {
// В запрос передаем вместо 'is_price_per_one_is_set' => 'is_price_per_one_is'
$booleanFilter->setFilterParamName('is_price_per_one_is');
// Скрываем из интерфейса, но обрабатываем всё равно
$booleanFilter->hidden();
// Делаем фильтр обязательным
$booleanFilter->required();
});
// Пример кастомного запроса
$this->filtersManager->add(SelectFilter::class, 'randomValue(ни на что не влияет в случае кастома)', 'Участник', function (SelectFilter $selectFilter) {
$selectFilter
->setFilterParamName('user_id');
->setCustomQueryClosure(function (\Illuminate\Database\Eloquent\Builder $builder, $values) {
$builder
->where('market_deals.requester_user_id', $values[0])
->orWhere('market_deals.responser_user_id', $values[0]);
});
});
}
}
2. Используем в контроллере
... /**
- @throws InvalidJsonFormatForFiltersParameterException
- @throws InvalidPanelSetConfigurationException
*/
public function browse(MarketOfferPanelSet $marketOfferPanelSet): JsonResponse
{
return response()->json($marketOfferPanelSet->handle());
}
...
#### Дополнительно: Пример из `POSTMAN` как управляться с фильтрами:
Класс PanelSetSortable
(Duotek\LaravelBasicComponents\PanelSetSortable\PanelSetSortable
)
Зачем нужен?
Используется в качестве соглашения с библиотекой на фронтенде для определения интерфейса на фронтенде через бэкенд.
Нужен для компонента на фронте, который имеет Drag'n'Drop
Компонент определяет порядок записей
и может вкладывать одну запись в другую (опционально)Как использовать?
- Создаем
PanelSetSortable
<?php
namespace App\PanelSets\Backoffice\Suppliers\Levels;
use App\Http\Resources\Backoffice\Suppliers\Levels\LevelListResource; use App\Models\Suppliers\Levels\Level; use Duotek\LaravelBasicComponents\PanelSetSortable\PanelSetSortable;
class LevelPanelSetSortable extends PanelSetSortable {
protected string $model = Level::class;
public string $resource = LevelListResource::class;
/** [Опционально] Определяем нужна ли поддержка вложенности */
protected bool $isNested = false;
/** [Опционально] Колонка в таблице, которое будет отвечать за порядок */
protected string $orderField = 'order_index';
/** [Опционально] Колонка в таблице, которая определяет родителя при включенной вкложенности */
protected string $parentField = 'parent_id';
/** [Опционально] Колонка, содержащая в себе первичный ключ таблицы */
protected string $identifierField = 'id';
}
2. Используем в контроллере
use App\PanelSets\Backoffice\Suppliers\Levels\LevelPanelSetSortable; use Illuminate\Http\JsonResponse;
/**
- GET
- suppliers/levels/browse-sortable
- [backoffice-api]
- Браузер уровней поставщиков сортированный *
- @param LevelPanelSetSortable $levelPanelSetSortable
- @return JsonResponse
*/
public function browseSortable(LevelPanelSetSortable $levelPanelSetSortable): JsonResponse
{
return response()->json($levelPanelSetSortable->handle());
}
- Добавляем метод обновления сортировки\вложенности в контроллер
use Duotek\LaravelBasicComponents\Service\PanelSetSortableUpdateService\PanelSetSortableUpdateService; use App\PanelSets\Backoffice\Suppliers\Levels\LevelPanelSetSortable; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request;
/**
- POST
- suppliers/levels/browse-sortable/update
- [backoffice-api]
- Обновить сортировку браузера *
- @bodyParam items object[] required
- @bodyParam items[].id int required
- @bodyParam items[].parent int required (если вложенность отключена, убираем из доки) *
- @param Request $request
- @return JsonResponse
@throws ValidationException */ public function browseSortableUpdate(Request $request): JsonResponse { (new PanelSetSortableUpdateService(LevelPanelSetSortable::class))->setParams($request)->handle();
return response()->json(['status' => true]); }
Класс BrowserFilterPresetController
(Duotek\LaravelBasicComponents\Controllers\BrowserFilterPresetController
)
Зачем нужен?
Используется в качестве соглашения между фронтендом и бэкэндом.
Содержит в себе контроллер с методами для сохранения\изменения\удаления пользовательских пресетов.
Как использовать?
Вставляем машруты в файл с роутами (там где необходимо).
Используется исключительно в админках, вместе с компонентом
PanelSet
... Route::post('browser/preset/create', [BrowserFilterPresetController::class, 'create']); Route::post('browser/preset/update', [BrowserFilterPresetController::class, 'update']); Route::post('browser/preset/delete', [BrowserFilterPresetController::class, 'delete']); ...