mtferreira / repository
Rinvex Repository 是 Laravel 的一种简单、直观且智能的 Active Repository 实现,具有极其灵活且粒度化的缓存系统,用于抽象数据层,使应用程序更易于维护。
此包的官方仓库似乎已不存在,因此该包已被冻结。
Requires
- php: >=5.5.9
- illuminate/container: ~5.1.0|~5.2.0|~5.3.0|~5.4.0
- illuminate/contracts: ~5.1.0|~5.2.0|~5.3.0|~5.4.0
- illuminate/database: ~5.1.0|~5.2.0|~5.3.0|~5.4.0
- illuminate/events: ~5.1.0|~5.2.0|~5.3.0|~5.4.0
- illuminate/support: ~5.1.0|~5.2.0|~5.3.0|~5.4.0
Suggests
- illuminate/pagination: Required to paginate the result set.
This package is not auto-updated.
Last update: 2023-08-10 00:43:12 UTC
README
Rinvex Repository 是 Laravel 的一种简单、直观且智能的 Active Repository 实现,具有极其灵活且粒度化的缓存系统,用于抽象数据层,使应用程序更易于维护。
目录
- 特性
- 安装
- 集成
- 配置
- 用法
- 快速示例
- 详细文档
setContainer()
,getContainer()
setModel()
,getModel()
setRepositoryId()
,getRepositoryId()
setCacheLifetime()
,getCacheLifetime()
setCacheDriver()
,getCacheDriver()
enableCacheClear()
,isCacheClearEnabled()
createModel()
forgetCache()
with()
where()
whereIn()
whereNotIn()
offset()
limit()
orderBy()
find()
findBy()
findAll()
paginate()
simplePaginate()
findWhere()
findWhereIn()
findWhereNotIn()
create()
update()
delete()
- 将代码转换为接口
- 添加自定义实现
- EloquentRepository 触发的事件
- 强制仓库约定
- 自动猜测
- 灵活且粒度化的缓存
- 总结
- 变更日志
- 支持
- 贡献与协议
- 安全漏洞
- 关于 Rinvex
- 许可证
特性
- 缓存,缓存,缓存!
- 防止代码重复。
- 减少潜在的编程错误。
- 以灵活的方式细粒度缓存查询。
- 应用集中管理的一致访问规则和逻辑。
- 实现并集中管理领域模型的缓存策略。
- 通过将客户端对象与领域模型分离来提高代码的可维护性和可读性。
- 通过自动化和隔离客户端对象以及领域模型来最大化可测试的代码量,以支持单元测试。
- 将行为与相关数据关联。例如,计算字段或强制实体内部数据元素之间的复杂关系或业务规则。
安装
安装此包的最佳和最简单方法是通过 Composer。
兼容性
此包完全兼容 Laravel 5.1.*
、5.2.*
和 5.3.*
。
虽然这个包倾向于框架无关,但它在一定程度上采用了Laravel文化和最佳实践。它主要与Laravel进行测试,但你仍然可以使用它与其他框架或甚至在没有框架的情况下使用。
先决条件
"php": ">=5.5.9", "illuminate/events": "5.1.*|5.2.*|5.3.*", "illuminate/support": "5.1.*|5.2.*|5.3.*", "illuminate/database": "5.1.*|5.2.*|5.3.*", "illuminate/container": "5.1.*|5.2.*|5.3.*", "illuminate/contracts": "5.1.*|5.2.*|5.3.*"
需要包
打开您的应用程序的composer.json
文件,并将以下行添加到require
数组中
"rinvex/repository": "2.0.*"
注意:确保运行
composer validate
后,您的composer.json
文件有效。
安装依赖项
在您的终端中运行composer install
或composer update
命令,根据您的应用程序状态安装新要求。
注意:有关更多详细信息,请查阅Composer的基本用法文档。
集成
Rinvex Repository包是框架无关的,因此可以轻松地本地或使用您喜欢的框架进行集成。
本地集成
在框架之外集成此包非常简单,只需要求vendor/autoload.php
文件来自动加载包。
注意:有关更多详细信息,请查阅Composer的自动加载文档。
Laravel集成
Rinvex Repository包默认支持Laravel,并附带一个服务提供程序,可轻松与框架集成。
安装包后,打开位于config/app.php
的Laravel配置文件,并将以下服务提供程序添加到$providers
数组中
Rinvex\Repository\Providers\RepositoryServiceProvider::class,
在您的终端中运行以下命令以发布配置文件
php artisan vendor:publish --provider="Rinvex\Repository\Providers\RepositoryServiceProvider" --tag="config"
注意:有关更多详细信息,请查阅Laravel的配置文档。
您已经准备就绪。集成已完成,您现在可以使用所有可用的方法,请转到用法部分以获取示例。
配置
如果您遵循了之前的集成步骤,那么您发布的配置文件位于config/rinvex.repository.php
。
配置选项非常表达性和自解释,如下所示
return [ /* |-------------------------------------------------------------------------- | Models Directory |-------------------------------------------------------------------------- | | Here you may specify the default models directory, just write | directory name, like 'Models' not the full path. | | Default: 'Models' | */ 'models' => 'Models', /* |-------------------------------------------------------------------------- | Caching Strategy |-------------------------------------------------------------------------- */ 'cache' => [ /* |-------------------------------------------------------------------------- | Cache Keys File |-------------------------------------------------------------------------- | | Here you may specify the cache keys file that is used only with cache | drivers that does not support cache tags. It is mandatory to keep | track of cache keys for later usage on cache flush process. | | Default: storage_path('framework/cache/rinvex.repository.json') | */ 'keys_file' => storage_path('framework/cache/rinvex.repository.json'), /* |-------------------------------------------------------------------------- | Cache Lifetime |-------------------------------------------------------------------------- | | Here you may specify the number of minutes that you wish the cache | to be remembered before it expires. If you want the cache to be | remembered forever, set this option to -1. 0 means disabled. | | Default: -1 | */ 'lifetime' => -1, /* |-------------------------------------------------------------------------- | Cache Clear |-------------------------------------------------------------------------- | | Specify which actions would you like to clear cache upon success. | All repository cached data will be cleared accordingly. | | Default: ['create', 'update', 'delete'] | */ 'clear_on' => [ 'create', 'update', 'delete', ], /* |-------------------------------------------------------------------------- | Cache Skipping URI |-------------------------------------------------------------------------- | | For testing purposes, or maybe some certain situations, you may wish | to skip caching layer and get fresh data result set just for the | current request. This option allows you to specify custom | URL parameter for skipping caching layer easily. | | Default: 'skipCache' | */ 'skip_uri' => 'skipCache', ], ];
用法
快速示例
Rinvex\Repository\Repositories\BaseRepository
是一个抽象类,具有混凝土实现必须扩展的最低要求。
Rinvex\Repository\Repositories\EloquentRepository
目前是唯一的可用仓库实现(未来还将有更多,您可以开发自己的实现),它使得创建新的 eloquent 模型实例并轻松操作它们变得简单。要使用 EloquentRepository
,您的仓库必须首先扩展它
namespace App\Repositories; use Rinvex\Repository\Repositories\EloquentRepository; class FooRepository extends EloquentRepository { protected $repositoryId = 'rinvex.repository.uniqueid'; protected $model = 'App\User'; }
就这样,您完成了!是的,就这么简单。
但是,如果您想对容器实例有更多的控制,或者想要动态传递模型名称,您可以按照以下方式操作
namespace App\Repositories; use Illuminate\Contracts\Container\Container; use Rinvex\Repository\Repositories\EloquentRepository; class FooRepository extends EloquentRepository { // Instantiate repository object with required data public function __construct(Container $container) { $this->setContainer($container) ->setModel(\App\User::class) ->setRepositoryId('rinvex.repository.uniqueid'); } }
现在在您的控制器中,您可以通过 $repository = new \App\Repositories\FooRepository();
传统的创建仓库实例,或者使用 Laravel 的出色依赖注入,让 IoC 做出魔法
namespace App\Http\Controllers; use App\Repositories\FooRepository; class BarController { // Inject `FooRepository` from the IoC public function baz(FooRepository $repository) { // Find entity by primary key $repository->find(1); // Find all entities $repository->findAll(); // Create a new entity $repository->create(['name' => 'Example']); } }
您可以开始了!关于使用这个包的知识已经足够了。
一个好的程序员在穿过单行道之前总是两边看。 -Doug Linder
所以,您决定继续前进,哈哈?!太棒了!! :D
详细文档
setContainer
,getContainer
setContainer
方法设置 IoC 容器实例,而 getContainer
返回它
// Set the IoC container instance $repository->setContainer(new \Illuminate\Container\Container()); // Get the IoC container instance: $container = $repository->getContainer();
setModel
,getModel
setModel
方法设置仓库模型,而 getModel
返回它
// Set the repository model $repository->setModel(\App\User::class); // Get the repository model $repositoryModel = $repository->getModel();
setRepositoryId
,getRepositoryId
setRepositoryId
方法设置仓库标识符,而 getRepositoryId
返回它(它可以是你想要的任何东西,但必须是每个仓库的 唯一标识符)
// Set the repository identifier $repository->setRepositoryId('rinvex.repository.uniqueid'); // Get the repository identifier $repositoryId = $repository->getRepositoryId();
setCacheLifetime
,getCacheLifetime
setCacheLifetime
方法设置仓库缓存生命周期,而 getCacheLifetime
返回它
// Set the repository cache lifetime $repository->setCacheLifetime(123); // Get the repository cache lifetime $cacheLifetime = $repository->getCacheLifetime();
setCacheDriver
,getCacheDriver
setCacheDriver
方法设置仓库缓存驱动,而 getCacheDriver
返回它
// Set the repository cache driver $repository->setCacheDriver('redis'); // Get the repository cache driver $cacheDriver = $repository->getCacheDriver();
enableCacheClear
,isCacheClearEnabled
enableCacheClear
方法启用仓库缓存清除,而 isCacheClearEnabled
确定其状态
// Enable repository cache clear $repository->enableCacheClear(true); // Disable repository cache clear $repository->enableCacheClear(false); // Determine if repository cache clear is enabled $cacheClearStatus = $repository->isCacheClearEnabled();
createModel
createModel
方法创建一个新的仓库模型实例
$repositoryModelInstance = $repository->createModel();
forgetCache
forgetCache()
方法将忘记存储库缓存
$repository->forgetCache();
with()
with
方法设置应该预先加载的关系
$repository->with(['relationship']);
where()
with
方法将基本的 where 子句添加到查询中
$repository->where('slug', '=', 'example');
whereIn()
whereIn
方法将 "where in" 子句添加到查询中
$repository->whereIn('id', [1, 2, 5, 8);
whereNotIn()
whereNotIn
方法将 "where not in" 子句添加到查询中
$repository->whereNotIn('id', [1, 2, 5, 8);
注意: 所有的
where
、whereIn
和whereNotIn
方法都是链式的,可以在单个请求中多次调用。它会在内部保留所有 where 子句的数组,并在执行查询之前应用它们。
offset()
offset
方法设置查询的 "偏移量" 值
$repository->offset(5);
limit()
limit
方法设置查询的 "限制" 值
$repository->limit(9);
orderBy()
orderBy
方法将 "order by" 子句添加到查询中
$repository->orderBy('id', 'asc');
find()
find
方法通过其主键查找实体
$entity = $repository->find(1);
findBy()
findBy
方法通过其实体的一个属性查找实体
$entity = $repository->findBy('id', 1);
findAll()
findAll
方法查找所有实体
$allEntities = $repository->findAll();
paginate()
paginate
方法对所有实体进行分页
$entitiesPagination = $repository->paginate(15, ['*'], 'page', 2);
正如你所猜想的,这个查询是第一页的前15条记录。
simplePaginate()
simplePaginate
方法将所有实体分页到一个简单的分页器中
$entitiesSimplePagination = $repository->simplePaginate(15);
findWhere()
findWhere
方法查找符合 where 条件的全部实体
// Matching values with equal '=' operator $repository->findWhere(['slug', '=', 'example']);
findWhereIn()
findWhereIn
方法查找符合 whereIn 条件的全部实体
$includedEntities = $repository->findwhereIn('id', [1, 2, 5, 8);
findWhereNotIn()
findWhereNotIn
方法查找符合 whereNotIn 条件的全部实体
$excludedEntities = $repository->findWhereNotIn('id', [1, 2, 5, 8);
说明
- 从 v2.0.0 开始,所有
findWhere
、findWhereIn
和findWhereNotIn
方法的签名已更改。- 所有的
findWhere
、findWhereIn
和findWhereNotIn
方法分别使用where
、whereIn
和whereNotIn
方法,因此第一个参数是后续方法所需参数数组的数组。
create()
create
方法使用给定的属性创建一个新实体
$createdEntity = $repository->create(['name' => 'Example']); // Assign created entity status and instance variables list($status, $instance) = $createdEntity;
update()
update
方法用于使用给定的属性更新实体
$updatedEntity = $repository->update(1, ['name' => 'Example2']); // Assign updated entity status and instance variables list($status, $instance) = $updatedEntity;
delete()
delete
方法用于根据给定的 id 删除实体
$deletedEntity = $repository->delete(1); // Assign deleted entity status and instance variables list($status, $instance) = $deletedEntity;
说明
- 所有
find*
方法接受一个可选参数,用于选择属性。- 所有
set*
方法返回当前存储库的实例,因此可以串联使用。create
、update
和delete
方法始终返回包含两个值的数组,第一个是操作状态(成功或失败)作为一个布尔值,第二个是刚刚操作的模型实例。- 建议像上面的例子一样,通过您的存储库构造函数显式设置 IoC 容器实例、存储库模型和存储库标识符。但这个包足够智能,可以猜测任何缺失的要求。查看自动猜测部分
面向接口编程
作为一个最佳实践,建议为接口进行编程,特别是对于可扩展的项目。以下示例解释了如何这样做。
首先,为每个您拥有的实体创建一个接口(抽象)
use Rinvex\Repository\Contracts\CacheableContract; use Rinvex\Repository\Contracts\RepositoryContract; interface UserRepositoryContract extends RepositoryContract, CacheableContract { // }
其次,为每个您拥有的实体创建一个存储库(具体实现)
use Rinvex\Repository\Repositories\EloquentRepository; class UserEloquentRepository extends EloquentRepository implements UserRepositoryContract { // }
现在在 Laravel 服务提供者中将它们绑定到 IoC(在 register
方法内)
$this->app->bind(UserRepositoryContract::class, UserEloquentRepository::class)
这样我们就不必手动实例化存储库,并且可以轻松地在多个实现之间切换。IoC 容器将负责所需的依赖关系。
添加自定义实现
由于我们专注于抽象数据层,并且我们将抽象接口与具体实现分开,因此很容易添加自己的实现。
例如,如果你的领域模型使用 Web 服务或文件系统数据存储作为数据源,你所需要做的只是扩展 BaseRepository
类,就是这样。见
class FilesystemRepository extends BaseRepository { // Implement here all `RepositoryContract` methods that query/persist data to & from filesystem or whatever datastore }
EloquentRepository 触发的事件
存储库在每次操作时都会触发事件,如 create
、update
、delete
。所有触发的事件都以存储库的标识符(你之前在存储库的构造函数中设置的)为前缀,例如以下示例
- rinvex.repository.uniqueid.entity.created
- rinvex.repository.uniqueid.entity.updated
- rinvex.repository.uniqueid.entity.deleted
为了方便起见,后缀为 .entity.created
、.entity.updated
或 .entity.deleted
的事件具有相应的监听器。通常,我们需要在每个成功操作时刷新缓存(如果启用且存在)。
还有一个事件 rinvex.repository.uniqueid.entity.cache.flushed
在刷新缓存时触发。默认情况下,它没有监听器,但你可能需要监听它,如果你有模型关系需要进一步操作。
必需的存储库约定
以下是一些在使用本包时需要了解的重要约定。本包遵循最佳实践,试图让网络工匠的开发更容易,因此它有一些约定用于标准化和互操作性。
-
所有触发的事件都有一个唯一的后缀,如
.entity.created
之类的。注意.entity.
,这是自动事件监听器订阅的必需项。 -
任何使用 Rinvex Repository 的包的默认目录结构如下
├── config --> config files
|
├── database
| ├── factories --> database factory files
| ├── migrations --> database migration files
| └── seeds --> database seed files
|
├── resources
| └── lang
| └── en --> English language files
|
├── src --> self explanatory directories
| ├── Console
| | └── Commands
| |
| ├── Http
| | ├── Controllers
| | ├── Middleware
| | ├── Requests
| | └── routes.php
| |
| ├── Events
| ├── Exceptions
| ├── Facades
| ├── Jobs
| ├── Listeners
| ├── Models
| ├── Overrides
| ├── Policies
| ├── Providers
| ├── Repositories
| ├── Scopes
| ├── Support
| └── Traits
|
└── composer.json --> composer dependencies file
注意: Rinvex 仓库 遵循 PSR-4: 自动加载器,并期望使用它的其他包也遵循相同的标准。这是自动猜测功能所必需的,例如当缺少仓库模型时,它将自动猜测并相应地解决,尽管完整的目录结构可能不是必需的,但这仍然是所有 Rinvex 包的标准。
自动猜测
虽然强烈建议显式设置 IoC 容器、仓库标识符和仓库模型;但此包足够智能,能够在缺少这些所需数据时猜测它们。
- IoC 容器
app()
助手在未明确提供 IoC 容器实例时用作后备。 - 仓库标识符 建议将仓库标识符设置为类似
rinvex.repository.uniqueid
的点命名,但如果缺少,将使用完全限定的仓库类名称(实际上是get_called_class()
函数的结果)。 - 仓库模型 通常,仓库按照以下方式命名空间:
Rinvex\Demos\Repositories\ItemRepository
,因此相应的模型应该按照以下方式命名空间:Rinvex\Demos\Models\Item
。这就是此包如果缺少模型时如何根据 默认目录结构 进行猜测的方式。
灵活且细粒度缓存
Rinvex 仓库 拥有一个强大、简单且细粒度的缓存系统,可以处理几乎所有的边缘情况。虽然你可以全局启用/禁用应用程序的缓存,但你也有权限对每个单独的查询进行细粒度的启用/禁用缓存!这让你有能力排除某些查询的缓存,即使方法默认或以其他方式被缓存。
让我们看看我们可以控制哪些缓存级别
整个应用程序缓存
有关更多详细信息,请参阅 Laravel 的 缓存 文档。
单个查询缓存
按查询更改缓存或禁用它
// Set cache lifetime for this individual query to 123 minutes $repository->setCacheLifetime(123); // Set cache lifetime for this individual query to forever $repository->setCacheLifetime(-1); // Disable cache for this individual query $repository->setCacheLifetime(0);
按查询更改缓存驱动程序
// Set cache driver for this individual query to redis $repository->setCacheDriver('redis');
setCacheLifetime
和 setCacheDriver
方法都是可链式的
// Change cache lifetime & driver on runtime $repository->setCacheLifetime(123)->setCacheDriver('redis')->findAll(); // Use default cache lifetime & driver $repository->findAll();
除非明确禁用,否则默认为对所有仓库启用缓存,并保留到您的 rinvex.repository.cache.lifetime
配置值,使用默认应用程序的缓存驱动程序 cache.default
(也可以按查询进行更改)。
是否缓存结果完全取决于您,尽管所有检索 find*
方法默认启用缓存,但您可以为单个查询启用/禁用缓存或控制其缓存方式、持续时间以及使用哪个驱动程序。
临时跳过单个 HTTP 请求缓存
最后,您可以通过在 URL 中传递以下查询字符串来跳过单个请求的缓存:skipCache=true
。您可以通过 rinvex.repository.cache.skip_uri
配置选项修改此参数为所需的任何名称。
总结思考
- 由于这是一个不断发展的实现,它可能会根据实际用例相应地改变。
- 存储库智能地将缺失的调用方法传递给底层模型,因此您实际上可以实现任何类型的逻辑,甚至通过利用存储库模型进行复杂的查询。
- 关于Active Repository实现的更多见解,我已经发布了一篇题为《Active Repository is good & Awesomely Usable》的文章,您可以在此处阅读:[Active Repository is good & Awesomely Usable](https://blog.omranic.com/active-repository-is-good-awesomely-usable-6991cfd58774)。
- 存储库非常聪明地使用缓存标签,即使您选择的缓存驱动程序不支持它。存储库将自行管理以实现精确的缓存管理。在幕后,它使用json文件来存储缓存键。请检查
rinvex.repository.cache.keys_file
配置选项以更改文件路径。 - Rinvex Repository遵循符合PSR-1: 基本编码标准、PSR-2: 编码风格指南和PSR-4: 自动加载的FIG PHP标准建议,以确保共享PHP代码之间具有高度互操作性。
- 目前,我认为通过实现
Criteria Pattern
来添加更复杂的层以进行过滤并没有看到其好处,相反,我更喜欢保持它现在这样简单,使用传统的where子句,因为我们可以达到相同的结果。(你有不同的想法吗?请解释。)
变更日志
有关项目的完整历史,请参阅变更日志。
支持
以下支持渠道随时可供您使用:
贡献 & 协议
感谢您考虑为这个项目做出贡献!贡献指南可以在CONTRIBUTING.md中找到。
我们非常欢迎错误报告、功能请求和拉取请求。
安全漏洞
如果您在此项目中发现安全漏洞,请通过电子邮件发送到help@rinvex.com。所有安全漏洞都将得到及时解决。
关于Rinvex
Rinvex是一家成立于2016年6月的开罗,埃及的软件解决方案初创公司,专注于为中小企业提供集成企业解决方案。我们相信,我们的动力是“价值、范围和影响”,这是我们与众不同的地方,并通过软件的力量释放我们哲学的无限可能性。我们喜欢称它为“与生活同步的创新”。这就是我们为推进人类事业贡献我们的一份力量。
许可协议
本软件在MIT许可协议(MIT)下发布。
(c) 2016 Rinvex LLC,部分权利保留。