salehhashemi / laravel-repository
为 Laravel 项目实现仓库模式。
Requires
- php: ^8.1
- laravel/framework: 9.*|10.*|11.*
Requires (Dev)
- laravel/pint: ^1.8
- nunomaduro/larastan: ^2.7
- orchestra/testbench: ^8.0
- phpunit/phpunit: ^9.0
README
Laravel 仓库模式
这个 Laravel 扩展包通过实现仓库模式简化并优化了数据访问。它提供了一个强大的抽象层来处理数据库交互,并增加了灵活的筛选、搜索和基于条件的查询。
特性
- 仓库抽象:将数据访问逻辑与应用代码解耦。
- 动态筛选:应用筛选器以细化数据库查询。
- 基于条件的筛选:定义可重用的条件以应用于常见的查询约束。
- 搜索功能:根据用户输入实现自定义搜索逻辑。
- 模块化仓库接口:确保一致性和可维护性。
- 易于集成:无缝集成到 Laravel 应用程序中。
- 开发工具:使用
make:repository
命令自动创建仓库、接口和筛选器。
安装
要安装此包,您可以运行以下命令
composer require salehhashemi/laravel-repository
开发工具
该包包含一个有用的命令,可以加速您的开发工作流程
-
make:repository
此命令将自动为指定的模型创建以下组件- 仓库类
- 仓库接口
- 筛选器类
使用示例
php artisan make:repository User
或
php artisan make:repository App\Models\User
示例用法
使用此包管理和管理 Post 模型的实际示例。
它包括自定义仓库、筛选器、条件和控制器使用的示例。
Post 仓库
PostRepository
类扩展了 BaseEloquentRepository,并展示了如何为 Post 模型使用此包的功能。
<?php namespace App\Repositories; use App\Filters\PostFilter; use App\Models\Post; use App\Repositories\Criteria\FeaturedPostCriteria; use Illuminate\Contracts\Pagination\Paginator; use Illuminate\Database\Eloquent\Collection as EloquentCollection; use Salehhashemi\Repository\BaseEloquentRepository; use Salehhashemi\Repository\Traits\Searchable; /** * @method \App\Models\Post getModel() * @method \App\Models\Post|null findOne(int|string $primaryKey = null) * @method \App\Models\Post findOneOrFail(int|string $primaryKey = null) */ class PostRepository extends BaseEloquentRepository implements PostRepositoryInterface { use Searchable; protected function getFilterManager(): PostFilter { $filterManager = new PostFilter(); $filterManager->setQuery($this->getQuery()); return $filterManager; } public function findAllFeatured(): EloquentCollection { $this->addCriteria(new FeaturedPostCriteria()); return $this->findAll(['limit' => 20]); } public function searchVisible(array $queryParams, int $perPage): Paginator { $this->orderBy('sort'); $this->withCategories(); return $this->search($queryParams, $perPage); } public function findOnePublishedOrFail(int $postId): Post { $this->applyConditions([ 'is_published' => 1, ]); return $this->findOneOrFail($postId); } public function withComments(): static { return $this->with(['comments']); } public function withCategories(): static { return $this->with(['categories']); } /** * {@inheritdoc} */ protected function getModelClass(): string { return Post::class; } }
Post 仓库接口
PostRepositoryInterface
定义了我们的仓库合约,确保方法签名的一致性和清晰性。
<?php declare(strict_types=1); namespace App\Repositories; use App\Models\Post; use Illuminate\Contracts\Pagination\Paginator; use Illuminate\Database\Eloquent\Collection as EloquentCollection; use Salehhashemi\Repository\Contracts\RepositoryInterface; use Salehhashemi\Repository\Contracts\SearchableRepositoryInterface; /** * @method \App\Models\Post|null findOne(int|string $primaryKey = null) * @method \App\Models\Post findOneOrFail(int|string $primaryKey = null) */ interface PostRepositoryInterface extends RepositoryInterface, SearchableRepositoryInterface { public function findAllFeatured(): EloquentCollection; public function searchVisible(array $queryParams, int $perPage): Paginator; public function findOnePublishedOrFail(int $postId): Post; /** * @return $this */ public function withComments(): static; /** * @return $this */ public function withCategories(): static; }
Post 筛选器
PostFilter
展示了如何将自定义筛选器应用于 Post 模型,增强查询的灵活性。
<?php declare(strict_types=1); namespace App\Filters; use App\Models\Post; use Illuminate\Database\Eloquent\Builder as QueryBuilder; use Salehhashemi\Repository\BaseFilter; class PostFilter extends BaseFilter { public function applyFilter(array $queryParams): QueryBuilder { $this ->whereLike('title', $queryParams['title'] ?? '', self::WILD_BOTH) ->whereValue('status', $queryParams['status'] ?? '') ->compare('amount', '<=' $queryParams['max_amount'] ?? '') ->dateFrom('created_at', $queryParams['created_from'] ?? '') ->dateTo('created_at', $queryParams['created_to'] ?? ''); if (! empty($queryParams['category_id'])) { $this->getQuery()->whereHas('categories', function ($query) use ($queryParams) { $query->where('categories.id', $queryParams['category_id']); }); } return $this->getQuery(); } protected function getModelClass(): string { return Post::class; } }
特色 Post 条件
FeaturedPostCriteria
是定义筛选条件的示例,这里专注于特色帖子。
<?php namespace App\Repositories\Criteria; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Model; use Salehhashemi\Repository\Contracts\CriteriaInterface; class FeaturedPostCriteria implements CriteriaInterface { /** * {@inheritDoc} */ public function apply(Model $model, Builder $query): Builder { $query->where([ 'posts.is_featured' => 1, ]); return $query; } }
将接口绑定到实现
将仓库接口与其具体实现绑定至关重要。这允许 Laravel 服务容器在需要的地方自动解析和注入适当的仓库实例。
-
创建服务提供者
php artisan make:provider RepositoryServiceProvider
-
在服务提供者中绑定
<?php namespace App\Providers; use Illuminate\Support\ServiceProvider; use App\Repositories\PostRepositoryInterface; use App\Repositories\PostRepository; class RepositoryServiceProvider extends ServiceProvider { public function register() { $this->app->bind( PostRepositoryInterface::class, PostRepository::class ); } }
-
注册服务提供者:将您的
RepositoryServiceProvider
添加到config/app.php
中的 providers 数组。'providers' => [ // Other Service Providers App\Providers\RepositoryServiceProvider::class, ],
控制器中的仓库使用
此示例展示了如何在控制器中使用 PostRepository
,并将其无缝集成到 Laravel 应用程序的工作流程中。
public function index(Request $request, PostRepositoryInterface $postRepository): AnonymousResourceCollection { return PostCollectionResource::collection( $postRepository ->search( $request->query(), $request->integer('limit'), ) ); }
可用方法
此包提供了一些方法
findOne
通过主键获取单个模型实例,或获取符合应用条件和关系的第一个模型。
$model = $repository->findOne($primaryKey);
findOneOrFail
类似于 findOne,但如果找不到结果,则抛出 ModelNotFoundException
。
$model = $repository->findOneOrFail($primaryKey);
findAll
检索符合应用条件、关系和指定选项的所有模型集合。
$models = $repository->findAll(['limit' => 10, 'offset' => 5]);
findList
获取按指定字段键控的模型值集合,对于下拉列表或类似显示很有用。
$list = $repository->findList('id', 'name');
paginate
基于应用条件、关系和指定页面大小返回模型的分页集合。
$paginatedModels = $repository->paginate(15);
addCriteria
将新的条件实例添加到仓库中进行查询筛选。
$repository->addCriteria(new YourCustomCriteria());
orderBy
根据字段和方向指定查询结果排序。
$repository->orderBy('created_at', 'DESC');
lockForUpdate
将对查询应用“锁定更新”子句以处理并发数据库访问。
$repository->lockForUpdate();
sharedLock
将对查询应用共享锁,防止修改所选行。
$repository->sharedLock();
配置
要发布配置文件,请运行以下命令
php artisan vendor:publish --provider="Salehhashemi\Repository\RepositoryServiceProvider" --tag="config"
发布后,请确保清除配置缓存以应用您的更改
php artisan config:clear
然后,您可以在 config/repository.php
中调整分页限制
异常
InvalidArgumentException
如果页面大小无效则抛出。ModelNotFoundException
如果找不到模型则抛出。
Docker 设置
此项目使用 Docker 进行本地开发和测试。在继续之前,请确保您的系统已安装 Docker 和 Docker Compose。
构建 Docker 镜像
docker-compose build
启动服务
docker-compose up -d
要访问 PHP 容器,您可以使用
docker-compose exec php bash
测试
composer test
变更日志
有关最近更改的更多信息,请参阅CHANGELOG。
贡献
有关详细信息,请参阅CONTRIBUTING。
致谢
许可证
MIT 许可证 (MIT)。有关更多信息,请参阅许可证文件。