protonemedia / laravel-cross-eloquent-search
Laravel包,可搜索多个Eloquent模型。支持分页、预加载关系、单/多列、排序和范围查询。
Requires
- php: ^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
- dev-master
- 3.x-dev
- 3.4.0
- 3.3.0
- 3.2.0
- 3.1.0
- 3.0.1
- 3.0.0
- 2.7.1
- 2.7.0
- 2.6.1
- 2.6.0
- 2.5.0
- 2.4.0
- 2.3.2
- 2.3.1
- 2.3.0
- 2.2.5
- 2.2.4
- 2.2.3
- 2.2.2
- 2.2.1
- 2.2.0
- 2.1.0
- 2.0.4
- 2.0.3
- 2.0.2
- 2.0.1
- 2.0.0
- 1.9.0
- 1.8.0
- 1.7.0
- 1.6.0
- 1.5.0
- 1.4.0
- 1.3.1
- 1.3.0
- 1.2.0
- 1.1.0
- 1.0.0
- 0.3.0
- 0.2.0
- 0.1.0
- dev-php-83
- dev-php-8.2
- dev-postgresql-sqlite
This package is auto-updated.
Last update: 2024-09-20 14:05:42 UTC
README
此Laravel包允许您搜索多个Eloquent模型。它支持排序、分页、范围查询、预加载关系以及单列或多列搜索。
赞助我们
❤️ 我们自豪地通过开发和免费提供Laravel包来支持社区。如果您认为此包节省了您的时间或您在专业上依赖它,请考虑赞助维护和开发,并查看我们的最新高级包:Inertia Table。跟踪问题和拉取请求需要时间,但我们乐于提供帮助!
要求
- PHP 8.2或更高版本
- MySQL 8.0+
- Laravel 10.0+
特性
- 通过一个或多个Eloquent模型进行搜索。
- 支持跨模型分页。
- 通过单列或多列进行搜索。
- 通过(嵌套)关系进行搜索。
- 支持全文搜索,甚至通过关系。
- 按(跨模型)列或相关性排序。
- 使用约束和范围查询。
- 为每个模型预加载关系。
- 对组合结果进行数据库排序。
- 零第三方依赖
📺 想要观看此包的实现?重新观看直播(跳转到13:44以查看精彩内容):https://youtu.be/WigAaQsPgSA
博客文章
如果您想了解更多关于此包背景的信息,请阅读博客文章。
安装
您可以通过composer安装此包
composer require protonemedia/laravel-cross-eloquent-search
从v2升级到v3
- 已将
get
方法重命名为search
。 - 已移除
addWhen
方法,改用when
。 - 默认情况下,结果按updated列排序,在大多数情况下是
updated_at
列。如果您不使用时间戳,现在将默认使用主键。
从v1升级到v2
- 已将
startWithWildcard
方法重命名为beginWithWildcard
。 - 现在默认的排序列由
getUpdatedAtColumn
方法评估。之前它是硬编码为updated_at
。您仍然可以使用另一个列进行排序。 - 已移除
allowEmptySearchQuery
方法及EmptySearchQueryException
类,但您仍然可以通过不进行搜索获取结果。
用法
通过添加一个或多个模型来开始您的搜索查询。调用 add
方法,传入模型的类名和您想要搜索的列。然后,使用搜索词调用 search
方法,您将获得一个包含结果的 \Illuminate\Database\Eloquent\Collection
实例。
默认情况下,结果按 updated 列的升序排序。在大多数情况下,此列是 updated_at
。如果您已自定义了模型的 UPDATED_AT
常量,或者覆盖了 getUpdatedAtColumn
方法,此包将使用自定义的列。如果您根本不使用时间戳,则默认使用主键。当然,您也可以按其他列排序。
use ProtoneMedia\LaravelCrossEloquentSearch\Search; $results = Search::add(Post::class, 'title') ->add(Video::class, 'title') ->search('howto');
如果您关注缩进,可以可选地使用外观类的 new
方法。
Search::new() ->add(Post::class, 'title') ->add(Video::class, 'title') ->search('howto');
还有一个 when
方法,可以根据其他条件应用某些子句。
Search::new() ->when($user->isVerified(), fn($search) => $search->add(Post::class, 'title')) ->when($user->isAdmin(), fn($search) => $search->add(Video::class, 'title')) ->search('howto');
通配符
默认情况下,我们会将搜索词拆分,每个关键词都会得到一个通配符以进行部分匹配。实际上,这意味着搜索词 apple ios
将导致 apple%
和 ios%
。如果您还想让通配符从开头开始,可以调用 beginWithWildcard
方法。这将导致 %apple%
和 %ios%
。
Search::add(Post::class, 'title') ->add(Video::class, 'title') ->beginWithWildcard() ->search('os');
注意:在此包的先前版本中,此方法称为 startWithWildcard()
。
如果您想禁用向术语追加通配符的行为,应调用 endWithWildcard
方法并传入 false
。
Search::add(Post::class, 'title') ->add(Video::class, 'title') ->beginWithWildcard() ->endWithWildcard(false) ->search('os');
多词搜索
默认支持多词搜索。只需将您的短语用双引号括起来即可。
Search::add(Post::class, 'title') ->add(Video::class, 'title') ->search('"macos big sur"');
您可以通过调用 dontParseTerm
方法来禁用搜索词的解析,这将产生与使用双引号相同的结果。
Search::add(Post::class, 'title') ->add(Video::class, 'title') ->dontParseTerm() ->search('macos big sur');
排序
如果您想按其他列排序结果,可以将该列作为第三个参数传递给 add
方法。调用 orderByDesc
方法按降序排序结果。
Search::add(Post::class, 'title', 'published_at') ->add(Video::class, 'title', 'released_at') ->orderByDesc() ->search('learn');
您可以通过调用 orderByRelevance
方法按搜索词出现的次数排序结果。
- 苹果推出 iPhone 13 和 iPhone 13 mini
- 苹果发布具有突破性性能的全新 iPad mini,设计令人惊叹
如果您搜索 苹果 iPad,则第二句话将首先出现,因为有更多匹配的搜索词。
Search::add(Post::class, 'title') ->beginWithWildcard() ->orderByRelevance() ->search('Apple iPad');
当您通过(嵌套)关系进行搜索时,不支持按相关性排序。
要按模型类型排序结果,可以使用 orderByModel
方法,并传入您首选的模型排序顺序。
Search::new() ->add(Comment::class, ['body']) ->add(Post::class, ['title']) ->add(Video::class, ['title', 'description']) ->orderByModel([ Post::class, Video::class, Comment::class, ]) ->search('Artisan School');
分页
我们强烈建议对结果进行分页。在调用 search
方法之前调用 paginate
方法,并将获得一个 \Illuminate\Contracts\Pagination\LengthAwarePaginator
实例作为结果。paginate
方法接受三个(可选)参数来自定义分页器。这些参数与 Laravel 的数据库分页器相同。
Search::add(Post::class, 'title') ->add(Video::class, 'title') ->paginate() // or ->paginate($perPage = 15, $pageName = 'page', $page = 1) ->search('build');
您还可以使用 简单分页。这将返回一个 \Illuminate\Contracts\Pagination\Paginator
实例,它不是长度感知的。
Search::add(Post::class, 'title') ->add(Video::class, 'title') ->simplePaginate() // or ->simplePaginate($perPage = 15, $pageName = 'page', $page = 1) ->search('build');
约束和范围查询
您也可以将 Eloquent 查询构建器 的实例传递给 add
方法,而不是类名。这允许您为每个模型添加约束。
Search::add(Post::published(), 'title') ->add(Video::where('views', '>', 2500), 'title') ->search('compile');
每个模型多列
您可以通过传递一个列数组作为第二个参数,通过多个列进行搜索。
Search::add(Post::class, ['title', 'body']) ->add(Video::class, ['title', 'subtitle']) ->search('eloquent');
搜索(嵌套)关系
您可以使用点表示法来搜索(嵌套)关系
Search::add(Post::class, ['comments.body']) ->add(Video::class, ['posts.user.biography']) ->search('solution');
全文搜索
您可以使用addFullText
方法使用MySQL的全文搜索。您可以通过(全文索引)搜索单个或多个列,并可以指定一组选项,例如指定模式。您甚至可以在一个查询中混合常规和全文搜索
Search::new() ->add(Post::class, 'title') ->addFullText(Video::class, 'title', ['mode' => 'boolean']) ->addFullText(Blog::class, ['title', 'subtitle', 'body'], ['mode' => 'boolean']) ->search('framework -css');
如果您想通过关系进行搜索,您需要传递一个数组,其中数组键包含关系,而值是列数组
Search::new() ->addFullText(Page::class, [ 'posts' => ['title', 'body'], 'sections' => ['title', 'subtitle', 'body'], ]) ->search('framework -css');
听起来像
MySQL内置了一个soundex算法,因此您可以搜索听起来几乎相同的术语。您可以通过调用soundsLike
方法使用此功能
Search::new() ->add(Post::class, 'framework') ->add(Video::class, 'framework') ->soundsLike() ->search('larafel');
预加载关系
这里没有太多要解释的,但这也得到了支持 :)
Search::add(Post::with('comments'), 'title') ->add(Video::with('likes'), 'title') ->search('guitar');
不搜索就获取结果
您调用search
方法而没有术语或带有空术语。在这种情况下,您可以使用orderBy
方法设置排序的列(之前是第三个参数),可以忽略add
方法的第二个参数
Search::add(Post::class) ->orderBy('published_at') ->add(Video::class) ->orderBy('released_at') ->search();
计数记录
您可以使用count
方法计算结果数量
Search::add(Post::published(), 'title') ->add(Video::where('views', '>', 2500), 'title') ->count('compile');
模型标识符
您可以使用includeModelType
将模型类型添加到搜索结果中。
Search::add(Post::class, 'title') ->add(Video::class, 'title') ->includeModelType() ->paginate() ->search('foo'); // Example result with model identifier. { "current_page": 1, "data": [ { "id": 1, "video_id": null, "title": "foo", "published_at": null, "created_at": "2021-12-03T09:39:10.000000Z", "updated_at": "2021-12-03T09:39:10.000000Z", "type": "Post", }, { "id": 1, "title": "foo", "subtitle": null, "published_at": null, "created_at": "2021-12-03T09:39:10.000000Z", "updated_at": "2021-12-03T09:39:10.000000Z", "type": "Video", }, ], ... }
默认情况下,它使用type
键,但您可以通过传递键到方法来自定义它。
您还可以通过在模型中添加一个公共方法searchType()
来自定义type
值,以覆盖默认的类基名称。
class Video extends Model { public function searchType() { return 'awesome_video'; } } // Example result with searchType() method. { "current_page": 1, "data": [ { "id": 1, "video_id": null, "title": "foo", "published_at": null, "created_at": "2021-12-03T09:39:10.000000Z", "updated_at": "2021-12-03T09:39:10.000000Z", "type": "awesome_video", } ], ...
独立解析器
您可以使用parseTerms
方法使用解析器
$terms = Search::parseTerms('drums guitar');
您还可以将回调和第二个参数一起传递,以遍历每个术语
Search::parseTerms('drums guitar', function($term, $key) { // });
测试
composer test
变更日志
有关最近更改的更多信息,请参阅变更日志
贡献
有关详细信息,请参阅贡献指南
其他Laravel包
Inertia Table
:内置查询构建器的Inertia.js终极表格。Laravel Blade On Demand
:编译内存中的Blade模板的Laravel包。Laravel Eloquent Scope as Select
:停止在PHP中重复Eloquent查询作用域和约束。此包允许您通过将它们作为子查询添加来重用查询作用域和约束。Laravel FFMpeg
:此包为Laravel提供FFmpeg集成。文件存储由Laravel的Filesystem处理。Laravel MinIO Testing Tools
:针对MinIO S3服务器运行您的测试。Laravel Mixins
:一组Laravel实用工具。Laravel Paddle
:支持webhooks/events的Paddle.com API集成,用于Laravel。Laravel Task Runner
:像Blade组件一样编写Shell脚本,并在本地或远程服务器上运行它们。Laravel Verify New Email
:此包增加了验证新电子邮件地址的支持:当用户更新电子邮件地址时,只有在新的电子邮件地址经过验证后,它才会替换旧的地址。Laravel XSS Protection
:Laravel 中间件,用于保护您的应用程序免受跨站脚本(XSS)攻击。它清洗请求输入,并且可以清洗 Blade 输出语句。
安全
如果您发现任何安全相关的问题,请通过电子邮件发送到 pascal@protone.media 而不是使用问题跟踪器。
致谢
许可证
MIT 许可证(MIT)。有关更多信息,请参阅 许可证文件。
Treeware
此包是 Treeware。如果您在生产中使用它,我们请求您 为世界买一棵树 以感谢我们的工作。通过为 Treeware 森林做出贡献,您将为当地家庭创造就业机会并恢复野生动物栖息地。