monospice / spicy-repositories
一个轻量级仓库框架,使用功能标准来提高代码的流畅性。
Requires
- php: >=5.4.0
- illuminate/database: >=4.2
- illuminate/pagination: >=4.2
- illuminate/support: >=4.2
- monospice/spicy-identifiers: 1.0.x-dev
Requires (Dev)
- mockery/mockery: 0.9.*
- phpspec/phpspec: ~2.3
README
一个轻量级仓库框架,使用功能标准来提高代码的流畅性。
仓库位于应用程序的业务逻辑和数据库操作层之间。这种抽象加快了开发速度并提高了应用程序的可维护性,因为它使数据访问更加一致和灵活。
此仓库实现为Laravel版本4和5内置了对Laravel Eloquent ORM的支持。
简单示例
$users = new UserRepository(new UserModel()); $users->getAll(); $users->getBy('age', '21'); $users->only('name', 'age')->get($id); $users->filterByCustomCriteria()->orderBy('name')->getAll();
安装
安装包
$ composer require monospice/spicy-repositories
在Laravel应用程序中
首先,在您的应用程序中创建一个Repository Service Provider来自动加载仓库
use Monospice\SpicyRepositories\Laravel\EloquentRepositoryServiceProvider; class RepositoryServiceProvider extends EloquentRepositoryServiceProvider { // repository binding methods here }
上面的服务提供商将您的仓库绑定到Laravel容器中,这样Laravel将自动将仓库实例注入到任何类型化仓库接口的控制器中。
要指示包绑定一个仓库类,向您刚才创建的服务提供商中添加一个方法,该方法定义了抽象仓库接口并返回匹配的具体仓库类的名称
class RepositoryServiceProvider extends EloquentRepositoryServiceProvider { protected function bindUserRepository() { $this->interface = \App\Repositories\Interfaces\UserRepository::class; return \App\Repositories\UserRepository::class; } }
在某些情况下,开发人员可能需要额外的功能来实例化一个仓库。仓库绑定方法也可以返回一个匿名函数,该函数包含新的仓库实例
class RepositoryServiceProvider extends EloquentRepositoryServiceProvider { protected function bindUserRepository() { $this->interface = \App\Repositories\Interfaces\UserRepository::class; return function () { if ($someCondition) { $model = new \App\User(); } else { $model = new \App\AdminUser(); } return new \App\Repositories\UserRepository($model); }; } }
仓库绑定方法必须以bind
开头,以Repository
结尾。这种命名约定鼓励对仓库类绑定进行可读性的定义。
EloquentRepositoryServiceProvider类为您调用register方法,因此在此处无需重新定义。
请确保将新的服务提供商添加到您的config/app.php
文件中的services数组中
... // Laravel >= 5.1: App\Providers\RepositoryServiceProvider::class, // Laravel < 5.1: 'App\Providers\RepositoryServiceProvider', ...
创建仓库
通过扩展包的类来创建一个新的仓库及其接口。
对于仓库接口
use Monospice\SpicyRepositories\Interfaces\Repository; use Monospice\SpicyRepositories\Interfaces\BasicCriteria; interface UserRepositoryInterface extends Repository, BasicCriteria { // custom repository methods here }
对于具体的仓库类
确保仓库类在其构造函数中接收一个模型的实例。如果您使用上一节中描述的服务提供商,框架将自动注入模型实例。
use Monospice\SpicyRepositories\Laravel\EloquentRepository; use App\Repositories\UserRepositoryInterface; class UserRepository extends EloquentRepository implements UserRepositoryInterface { public function __construct(User $user) { parent::__construct($user); } // custom repository methods here }
或者,您可以选择为您的应用程序创建一个基础仓库类和接口,这样您就只需要扩展一次包类。
现在,这个仓库可以通过在控制器中类型提示仓库的接口来使用。Laravel将自动注入实例。
class UserController extends Controller { public function __construct(UserRepositoryInterface $users) { // use the repository $users->getAll(); } }
仓库方法
当您为特定情况定义自己的自定义可重用方法时,仓库会特别出色。然而,为了方便起见,此包中的仓库包含以下通用方法
获取数据
getAll() - 获取模型的所有记录
$repository->getAll();
paginateAll() - 分页获取模型的所有记录集
$itemsPerPage = 20; $repository->paginateAll($itemsPerPage);
getFirst() - 获取一组中的第一条记录
$repository->getFirst();
get() - 通过ID获取模型的单条记录
$recordId = 1; $repository->get($recordId);
getBy() - 获取属性等于指定值的记录集
$column = 'name'; $value = 'George Washington'; $repository->getBy($column, $value);
paginateBy() - 分页获取属性等于指定值的记录集
$itemsPerPage = 20; $column = 'name'; $value = 'George Washington'; $repository->paginateBy($column, $value, $itemsPerPage);
listAll() - 获取包含一个属性值的所有记录的数组
values of one attribute
$column = 'name'; $repository->listAll($column);
exists() - 判断是否存在记录
$repository->exists();
此方法在应用标准到查询后检查记录是否存在时更有用
$repository->forUserType($userType)->exists();
count() - 获取查询的记录数
$repository->count();
如果没有标准,此方法返回模型的所有记录数。count()
在确定应用标准后的记录数时更有用
$repository->forUserType($userType)->count();
有关存储库标准的信息,请参阅本文档后面的标准部分。
修改数据
create() - 从属性数据数组创建新记录
$input = ['first' => 'George', 'last' => 'Washington']; $repository->create($input);
update() - 使用属性数据数组更新现有记录
$recordId = 1; $changes = ['first' => 'Denzel']; $repository->update($recordId, $changes);
updateOrCreate() - 更新现有记录或如果不存在则创建它
$repository->updateOrCreate() ->where([ 'first' => 'George', 'last' => 'Washington', ]) ->set([ 'occupation' => 'President of the US' ]);
在上面的示例中,如果记录存在,则存储库将设置记录的occupation
字段。否则,它将创建一个新记录并将所有三个字段设置为给定值。
可以指定多个where子句来查找记录,并且操作将更新每个匹配的记录或创建新记录
$repository->updateOrCreate() ->where(['first' => 'George']) ->orWhere(['first' => 'Denzel']) ->set(['occupation' => 'Some guy named Washington']);
delete() - 删除指定的记录
$recordId = 1; $repository->delete($recordId);
getResult() - 获取最后创建、更新或删除操作的返回值
$repository->getResult();
自定义方法
在扩展此包基础类的存储库类中定义自定义方法。
例如
class UserRepository extends EloquentRepository implements UserRepositoryInterface { public function customGetAll() { return $this->orderBy('name')->getAll(); } } $repository->customGetAll(); // the custom method $repository->getAll(); // a built-in method
标准
存储库标准是存储库应用到的查询的可重复约束。为了代码更流畅,此包使用功能标准而不是标准类。
大多数标准应根据特定应用程序的需求创建。此包提供了一些基本标准以供您开始使用
only() - 仅检索结果集中指定的列
$repository->only('name', 'email')->getAll();
exclude() - 检索结果集中除指定的列之外的所有列
$repository->exclude('password')->getAll();
limit() - 检索结果集中不超过指定数量的记录
$repository->limit(5)->getAll();
orderBy() - 根据指定的列对返回的结果集进行排序
$repository->orderBy('name')->getAll(); $repository->orberBy('age', 'desc')->getAll();
with() - 懒加载(在同一查询中)指定的关系(在模型上定义)
$repository->with('comments')->getAll();
withRelated() - 懒加载(在同一查询中)模型和存储库上定义的所有关系(这些关系必须在存储库中手动定义--目前无法从Eloquent模型中收集它们)
$repository->withRelated()->getAll();
在存储库中添加此属性
protected $related = ['likes', 'comments'];
哪里是where()?
为了鼓励创建可重复使用的标准,此存储库框架明确排除了包中的where()
标准。该框架旨在让开发者编写可读性强的标准,这些标准执行与where子句相同的功能,而不是每次需要该功能时都构建复杂的查询。
如果项目真的需要where标准,可以在其子存储库类中定义标准方法,如下所示
public function whereCriterion($query, $column, $boolean, $value) { return $query->where($column, $boolean, $value); }
有关更多信息,请参阅下一小节。
自定义标准
当开发者为存储库创建自定义的、可重复使用的标准时,存储库特别强大。这些标准应抽象复杂或经常使用的逻辑单元。
例如,开发人员可以创建一个honorStudents()
标准,根据用户类型和平均成绩过滤结果,以及一个freshman()
标准,根据用户类型和年级水平过滤。
结合这些标准,这些标准指示存储库返回所有荣誉新生。实现不需要了解数据层的内部工作原理
$repository->freshman()->honorStudents()->getAll(); // freshman honors students $repository->honorStudents()->getAll(); // all honors students
要创建自定义标准,在存储库(及其接口)中定义以Criterion
或Criteria
结尾的方法
public function honorStudentCriterion($query, $gradeThreshold = 90) { return $query ->where('user_type', 'student') ->where('grade_average', '>=', $gradeThreshold); }
在上面的示例中,对honorStudents()
的调用自动调用honorStudentsCriterion()
方法,并将$参数查询以及任何提供给honorStudents()
方法调用的其他参数传递给该方法。
此约定鼓励在存储库类中定义可读的存储库标准。请注意,不应显式声明honorStudents()
方法。存储库框架处理动态方法调用。
可选地,通过在具有相同属性或功能模型的存储库共享的特性中定义它们,来提高您的标准重用性。
方法链
不返回输出值的方法可以被链式调用
$result = $repository ->create($new) ->delete($old) ->update($related) ->orderBy('name') ->exclude('password') ->withRelated() ->someCustomCriteria() ->getAll();
测试
Spicy Repositories 包使用 PHPUnit 通过 Eloquent 使用数据库执行功能测试,并使用 PHPSpec 对象行为。
$ phpunit $ vendor/bin/phpspec run
许可
MIT 许可证 (MIT)。有关更多信息,请参阅许可文件。