monospice/spicy-repositories

一个轻量级仓库框架,使用功能标准来提高代码的流畅性。

1.3.2 2015-10-31 07:25 UTC

This package is auto-updated.

Last update: 2024-09-21 20:08:27 UTC


README

Build Status

一个轻量级仓库框架,使用功能标准来提高代码的流畅性。

仓库位于应用程序的业务逻辑和数据库操作层之间。这种抽象加快了开发速度并提高了应用程序的可维护性,因为它使数据访问更加一致和灵活。

此仓库实现为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

要创建自定义标准,在存储库(及其接口)中定义以CriterionCriteria结尾的方法

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)。有关更多信息,请参阅许可文件