ratiborro / laravel-scopes
通过数据库列在现有文件中为模型生成本地作用域
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
用于通过数据库列最大程度地简化创建模型本地作用域的包。
可以自动根据模型表的现有列生成作用域,可选地排除按名称指定的列(适用于所有或特定模型),可自定义生成作用域名称的数据库数据类型,以及可自定义每个生成作用域的逻辑(如果默认行为不适用)。
安装
安装包
composer require ratiborro/laravel-scopes --dev
用法
使用一个简单的命令为模型创建作用域
php artisan make:scopes ModelName
命令会找到模型文件(位于配置中的基本模型目录内),根据数据库列生成所有未来作用域的名称(考虑重命名和排除列,以及作用域名称生成逻辑),使用模板填充它们,然后将它们导入模型(如果存在现有作用域,则直接在其后导入,否则在模型类末尾导入)。
对于每个列可以创建无限数量的作用域(如果列上有多个作用域,则存在一些命名限制)。
您可以随意更改创建的作用域,而不用担心丢失您的更改,因为包不会影响已创建的作用域。
配置
发布配置
php artisan vendor:publish --tag=laravel-scopes-config
- 设置模型存储的根目录
- 自定义作用域名称的生成逻辑
- 列:排除不必要的列,更改名称,指定最不寻常类型列的默认类型
- 模板(stubs):设置模板保存路径和类型转换映射(例如,对于bigint类型,使用与int相同的模板生成作用域)
发布Laravel不同对象的模板
php artisan stub:publish
发布创建的作用域模板(用于进一步编辑或创建新模板)
php artisan vendor:publish --tag=laravel-scopes-stubs
示例
例如,有一个模型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 ],
为了为datetime列创建2个作用域,我们需要
- 创建一个名为
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
,在这些作用域中描述了所需的逻辑(从模板中)。
故障排除
错误
模型不存在
:请确保模型的命名空间与配置中指定的相匹配。例如,如果配置中指定了命名空间
App\Models
,则您可以通过其名称调用模型:如果模型位于直接在Models
命名空间中,则使用php artisan make:scopes User
,或者如果模型位于子目录中并且具有不同的命名空间,则使用php artisan make:scopes SubdirectoryName/User
。如果模型位于其他目录中,只需更改配置
models.base_namespace
。错误
无法获取模型表列
:请确保为该模型已存在表(已执行创建表的迁移)。如果错误仍然存在,请通过以下联系方式联系。