ratiborro / laravel-scopes
Generating local scopes for model in existing file by database columns
Requires
- php: >=7.1
- doctrine/dbal: ^2.1|^3.0
- illuminate/console: ^5.5|^6|^7|^8
- illuminate/support: ^5.5|^6|^7|^8
README
Пакет для максимально простого создания локальных скоупов моделей по колонкам в базе данных.
Можно автоматически генерировать скоупы по имеющимся колонкам таблицы модели, по желанию исключая колонки по именам (для всех или для конкретных моделей), настраивая как угодно генерацию имён скоупов для каждого типа данных БД, а также как угодно настраивая логику каждого генерируемого скоупа (если не подойдёт поведение по-умолчанию).
Installation
Установите пакет:
composer require ratiborro/laravel-scopes --dev
Usage
Создайте скоупы для модели одной простой командой:
php artisan make:scopes ModelName
Команда найдёт файл модели (в пределах базовой директории моделей из конфига), сгенерирует имена для всех будущих скоупов по колонкам в БД (с учётом переименований и исключений колонок, а также логики генерации имен скоупов), заполнит их логикой из шаблонов, а затем импортирует их в модель (сразу после существующих скоупов при их наличии, иначе - в конец класса модели).
Для каждой колонки можно создавать неограниченное количество скоупов (с некоторым ограничением именования, если скоупов больше одного на колонку).
Вы можете менять созданные скоупы как захотите без страха потери ваших изменений, так как пакет не затрагивает уже созданные скоупы.
Configuration
Публикация конфига:
php artisan vendor:publish --tag=laravel-scopes-config
- Настраивайте корневую папку хранения моделей
- Настраивайте как угодно логику генерации имен скоупов
- Колонки: исключайте ненужные, изменяйте имена, укажите тип по-умолчанию для самых необычных типов колонок
- Шаблоны (stubs): настраивайте путь сохранения шаблонов и карту преобразования типов (например, чтобы для типа bigint генерировался скоуп по такому же шаблону, что и int)
Публикация шаблонов (stubs) различных объектов Laravel:
php artisan stub:publish
Публикация шаблонов создаваемых скоупов (для их дальнейшего редактирования или создания новых):
php artisan vendor:publish --tag=laravel-scopes-stubs
Examples
Например, есть модель User с колонками id
, name
, email
, is_admin
, lovely_word
, team_id
, verified_at
, created_at
, updated_at
.
Если вас устраивает поведение по-умолчанию или вы уже настроили пакет под себя, никаких действий, кроме выполнения команды make:scopes
не требуется. Но мы же не ищем лёгких путей, верно? :)
Сначала опишем свои хотелки:
Допустим, нам не нужна генерация скоупов для колонок
id
,created_at
иupdated_at
.Для колонок с внешними ключами (заканчивающихся на
*_id
) мы хотим такой стиль именования, чтобы было понятно, что это отношения к другим сущностям: например для колонкиteam_id
мы желаем иметь скоупscopeOfTeam
.Для булевых колонок мы хотим следующий стиль именования без is (если есть):
is_admin => scopeAdmin
Конкретно для колонки
name
мы хотим видеть скоупscopeNamed
, просто потому что нам так больше нравится.Название
lovely_word
осталось в базе по историческим причинам (как и другие похожие), поэтому для всех колонок начинающихся наlovely_*
мы хотим изменить слово в скоупе на favorite (lovely_word => scopeFavoriteWord
)Для datetime колонок мы хотим иметь по два скоупа: один для точного поиска по дате и времени, а другой для поиска только по дате.
Для остальных колонок нас устраивает стиль именования camelCase:
scopeColumnName
.
Теперь, чтобы реализовать все наши желания, нам необходимо выполнить следующие действия:
Генерацию скоупов для колонок
id
,created_at
иupdated_at
мы просто отключаем, перечислив эти колонки в конфиге:'columns' => [ ... 'exclude_columns' => ['id', 'created_at', 'updated_at', 'deleted_at'], ... ],
Кейсы 2 и 3 уже вшиты как поведение по-умолчанию (привилегия автора), при необходимости стиль именования можно изменить.
Колонку
name
мы указываем в конфиге в словаре'columns' => [ ... 'dictionary' => [ 'name' => 'named' ] ... ],
Для написания индивидуальной логики именования колонки
lovely_word
мы создадим классCustomScopeNameGenerator
, который будет расширять классRatiborro\LaravelScopes\Helpers\ScopeNameGenerator
, генерирующий имена скоупов. Так как тип колонки строка, мы переопределим методgetStringScopeName
и допишем туда логику наподобие:if (Str::startsWith($name, 'lovely_')) { return 'favorite_' . Str::after($name, 'lovely_'); }
Также важно не забыть указать наш класс в конфиге:
'scopes' => [ 'nameGeneratorClass' => \App\YourPath\ScopeNameGenerator::class ],
Для того, чтобы сделать 2 скоупа для datetime колонок, нам нужно:
- создать шаблон
datetime.stub
. По-умолчанию такого шаблона нет, так как дляdate
иdatetime
колонок скоупы генерируются по одному шаблону и в конфиге прописан маппинг сdatetime
наdate
. Можно просто скопировать шаблонdate.stub
и сохранить какdatetime.stub
, после чего удалить маппинг'datetime' => 'date',
из конфига, чтобы брался шаблон по имени типа колонки. изменить логику в шаблоне, например, на такую:
public function scope{{$name}}($q, $value) { return $q->where('{{$column}}', $value); } public function scope{{$name}}Date($q, $value) { return $q->whereDate('{{$column}}', $value); }
где
$name
- это имя скоупа, созданное генератором имён скоупов,$column
- оригинальное название колонкиТип значения специально не указываем, чтобы можно было прислать как строку даты, так и, например, Carbon объект.
На выходе это даст скоупы с названиями
scopeVerifiedAt
иscopeVerifiedAtDate
. Ограничением в именовании выступает лишь общая часть названия, но она может быть какой угодно, всё ограничивается лишь вашей фантазией.
- создать шаблон
Для остальных колонок мы не делаем никаких специальных действий, и это создаст нам "стандартные" скоупы без ухищрений
На выходе мы получим скоупы с именами: scopeNamed
, scopeEmail
, scopeAdmin
, scopeFavoriteWord
, scopeOfTeam
, scopeVerifiedAt
и scopeVerifiedAtDate
, в которых будет описана та логика, которая нам необходима (из шаблонов).
Troubleshooting
Ошибка
Model not exists
: убедитесь, что namespace модели совпадает с тем, что прописан в конфиге.Например, если в конфиге прописан namespace
App\Models
, то вы можете вызывать модель через её название:php artisan make:scopes User
, если она находится непосредственно в пространстве имён Models, или же черезphp artisan make:scopes SubdirectoryName/User
, если модель находится в подпапке и имеет другой namespace.Если модели лежат в другой папке, просто измените конфиг
models.base_namespace
.Ошибка
Fails to get model table columns
: убедитесь, что таблица для данной модели уже существует (миграция на создание таблицы уже выполнена). Если ошибка остаётся, пожалуйста, обратитесь по нижеуказанным контактам.
Contacts
Author: Ratibor Korobin