protonemedia / laravel-eloquent-scope-as-select
Laravel 包,用于将 Eloquent 范围作为约束添加为子查询选择。
Requires
- php: ^8.1|^8.2|^8.3
- illuminate/support: ^10.0|^11.0
Requires (Dev)
- mockery/mockery: ^1.4.4
- orchestra/testbench: ^8.0|^9.0
- phpunit/phpunit: ^10.4
This package is auto-updated.
Last update: 2024-09-20 14:05:45 UTC
README
停止在 PHP 中重复您的 Eloquent 查询范围和约束。此包允许您通过将它们添加为子查询来重用查询范围和约束。
📺 想要看到这个包的实际应用?加入 12 月 3 日 14:00 CET 的直播:https://youtu.be/0vR8IQSFsfQ
要求
- PHP 8.1+
- Laravel 10.0
此包使用 GitHub Actions 与 MySQL 8.0、PostgreSQL 10.8 和 SQLite 进行测试。
功能
- 基于 查询范围 添加子查询。
- 使用闭包添加子查询。
- 使用字符串或数组调用范围的自定义快捷方式。
- 支持多个子查询。
- 支持翻转结果。
- 无第三方依赖。
相关包: Laravel Eloquent Where Not
赞助我们
❤️ 我们自豪地通过开发和免费提供 Laravel 包来支持社区。如果这个包为您节省了时间或您在专业上依赖它,请考虑 赞助维护和开发 并查看我们最新的高级包: Inertia Table。跟踪问题和拉取请求需要时间,但我们很乐意提供帮助!
博客文章
如果您想了解更多关于此包的背景信息,请阅读博客文章: 停止重复您的 Eloquent 查询范围和约束。使用新的 Laravel 包将它们重用为选择语句。
安装
您可以通过 composer 安装此包
composer require protonemedia/laravel-eloquent-scope-as-select
将 macro
添加到查询构建器中,例如,在您的 AppServiceProvider
中。默认情况下,宏的名称为 addScopeAsSelect
,但您可以使用 addMacro
方法的第一个参数自定义它。
use ProtoneMedia\LaravelEloquentScopeAsSelect\ScopeAsSelect; public function boot() { ScopeAsSelect::addMacro(); // or use a custom method name: ScopeAsSelect::addMacro('withScopeAsSubQuery'); }
简短的 API 描述
对于更实际的解释,请参阅下面的 使用 部分。
使用闭包添加选择。每个 Post
模型,无论是否发布,都将有一个 is_published
属性。
Post::addScopeAsSelect('is_published', function ($query) { $query->published(); })->get();
上面的例子可以通过使用字符串来缩短,其中第二个参数是范围名称
Post::addScopeAsSelect('is_published', 'published')->get();
您可以使用数组调用多个范围
Post::addScopeAsSelect('is_popular_and_published', ['popular', 'published'])->get();
使用关联数组调用动态范围
Post::addScopeAsSelect('is_announcement', ['ofType' => 'announcement'])->get();
如果您的动态范围需要多个参数,请使用关联数组
Post::addScopeAsSelect('is_announcement', ['publishedBetween' => [2010, 2020]])->get();
您还可以混合动态和非动态范围
Post::addScopeAsSelect('is_published_announcement', [ 'published', 'ofType' => 'announcement' ])->get();
该方法有一个可选的第三个参数,用于翻转结果。
Post::addScopeAsSelect('is_not_announcement', ['ofType' => 'announcement'], false)->get();
使用
假设您有一个具有查询范围的 Post
Eloquent 模型。
class Post extends Model { public function scopePublished($query) { return $query->whereNotNull('published_at'); } }
现在您可以通过在查询上调用范围方法来获取所有已发布的帖子
$allPublishedPosts = Post::published()->get();
但如果你想要获取 所有 帖子然后 再 检查帖子是否发布呢?这个范围非常简单,所以你可以很容易地通过检查 published_at
属性来模拟范围的结果
Post::get()->each(function (Post $post) { $isPublished = !is_null($post->published_at); });
当作用域变得更为复杂或链式使用多个作用域时,这会变得更加困难。让我们为Post
模型添加一个关系和另一个作用域。
class Post extends Model { public function comments() { return $this->hasMany(Comment::class); } public function scopePublished($query) { return $query->whereNotNull('published_at'); } public function scopePublishedInCurrentYear($query) { return $query->whereYear('published_at', date('Y')); } }
使用Eloquent,我们可以获取今年至少有十个评论的所有帖子。
$recentPopularPosts = Post::query() ->publishedInCurrentYear() ->has('comments', '>=', 10) ->get();
太好了!现在我们再次获取所有帖子,然后检查帖子是否在今年发布且至少有十个评论。
Post::get()->each(function (Post $post) { $isRecentAndPopular = $post->comments()->count() >= 10 && optional($post->published_at)->isCurrentYear(); });
明白了,这会变得很乱,你还在重复逻辑。
解决方案
利用这个包的强大功能,你可以在获取数据时重用你的作用域。第一个例子(published
作用域)可以缩小到
$posts = Post::addScopeAsSelect('is_published', function ($query) { $query->published(); })->get();
使用PHP 7.4中引入的短闭包功能,这可以更短
$posts = Post::addScopeAsSelect('is_published', fn ($query) => $query->published())->get();
现在每个Post
模型都将有一个is_published
布尔属性。
$posts->each(function (Post $post) { $isPublished = $post->is_published; });
你还可以添加多个选择,例如,结合两种场景
Post::query() ->addScopeAsSelect('is_published', function ($query) { $query->published(); }) ->addScopeAsSelect('is_recent_and_popular', function ($query) { $query->publishedInCurrentYear()->has('comments', '>=', 10); }) ->get() ->each(function (Post $post) { $isPublished = $post->is_published; $isRecentAndPopular = $post->is_recent_and_popular; });
快捷方式
除了使用闭包,还有一些快捷方式可以使用(参见:简短API描述)
使用字符串而不是闭包
Post::addScopeAsSelect('is_published', function ($query) { $query->published(); }); // is the same as: Post::addScopeAsSelect('is_published', 'published');
使用数组而不是闭包,以支持多个作用域和动态作用域
Post::addScopeAsSelect('is_announcement', function ($query) { $query->ofType('announcement'); }); // is the same as: Post::addScopeAsSelect('is_announcement', ['ofType' => 'announcement']);
你也可以使用可选的第三个参数反转结果(默认为true
)
$postA = Post::addScopeAsSelect('is_announcement', ['ofType' => 'announcement'])->first(); $postB = Post::addScopeAsSelect('is_not_announcement', ['ofType' => 'announcement'], false)->first(); $this->assertTrue($postA->is_announcement) $this->assertFalse($postB->is_not_announcement);
测试
composer test
变更日志
请参阅变更日志以获取有关最近更改的更多信息。
贡献
请参阅贡献以获取详细信息。
其他Laravel包
Inertia Table
:Inertia.js的终极表格,内置查询构建器。Laravel Blade On Demand
:Laravel包,用于在内存中编译Blade模板。Laravel Cross Eloquent Search
:Laravel包,用于在多个Eloquent模型中搜索。Laravel FFMpeg
:此包提供了FFmpeg与Laravel的集成。文件的存储由Laravel的文件系统处理。Laravel MinIO Testing Tools
:针对MinIO S3服务器运行测试。Laravel Mixins
:Laravel好东西的集合。Laravel Paddle
:Paddle.com API的Laravel集成,支持webhooks/events。Laravel Task Runner
:像Blade组件一样编写Shell脚本,并在本地或远程服务器上运行它们。Laravel Verify New Email
:此包添加了对验证新电子邮件地址的支持:当用户更新其电子邮件地址时,它不会替换旧地址,直到新地址被验证。Laravel XSS Protection
:Laravel中间件,用于防止您的应用遭受跨站脚本(XSS)攻击。它净化请求输入,并可以净化Blade echo语句。
安全
如果您发现任何安全相关的问题,请通过电子邮件pascal@protone.media联系,而不是使用问题跟踪器。
鸣谢
许可证
MIT许可证(MIT)。更多信息请参阅许可证文件。
开源软件
本软件包是Treeware。如果您在生产环境中使用它,我们请求您为世界购买一棵树以感谢我们的工作。通过为Treeware森林做出贡献,您将为当地家庭创造就业机会并恢复野生动物栖息地。