mratiebatie/laravel-repositories

使用原生 Eloquent 函数的 Laravel 仓库。

1.0.9 2020-10-29 15:32 UTC

This package is auto-updated.

Last update: 2024-09-13 18:59:20 UTC


README

注意!这不仅仅是一个基类,其中包含一些尝试作为 Eloquent 替代品的方法。这是一个实现,您可以在自定义类上使用所有 Eloquent 功能!

在 Laravel 中使用仓库可能会有些困惑。如果您创建自定义的作为仓库的类,您将无法再使用 Eloquent,这是 Laravel 最好的功能之一。这就是我寻找另一种在 Laravel 中使用仓库模式的原因。我提出了这个方法,并认为我应该分享它。

安装

只需通过 Composer 安装即可。

composer require mratiebatie/laravel-repositories

安装完成后,您就可以开始使用 Laravel 的仓库模式了。

创建仓库类

此包提供一个新的 Artisan 命令来创建仓库类。所有类都将生成在 App\Repositories 文件夹中,如果此文件夹不存在,则会自动生成。

php artisan make:repository ProductRepository

您可以使用 --model 选项来定义将与此仓库相关联的 Eloquent 模型。

php artisan make:repository ProductRepository --model=App\\Product

不要忘记写出您模型的 完整命名空间,使用 '\\' 作为分隔符。

示例

在这个例子中,我假设您已经有一个名为 Product 的模型。使用以下命令:

php artisan make:repository ProductRepository --model=App\\Models\\Product

<?php

namespace App\Repositories;

use MrAtiebatie\Repository;
use App\Models\Product; 

class ProductRepository
{
    use Repository;

    /**
     * The model being queried.
     *
     * @var Model
     */
    protected $model;

    /**
     * Constructor
     */
    public function __construct()
    {
        // setup the model
        $this->model = app(Product::class);
    }
}

魔法在于 Repository 特性和 protected $model 属性。当您在您的仓库上调用 Eloquent 方法时,此调用将回退到您的模型。
因此,所有 Eloquent 方法如 whereallfind 或您的自定义作用域都可用于您的仓库。

初始化 $model 属性的建议方法是使用 IoC 容器。这样,您可以在进行单元测试时始终用 Mock 对象替换模型。

<?php

namespace App\Repositories;

use MrAtiebatie\Repository;
use App\Models\Product; 

class ProductRepository
{
    use Repository;

    /**
     * The model being queried.
     *
     * @var Model
     */
    protected $model;

    /**
     * Constructor
     */
    public function __construct()
    {
        // setup the model
        $this->model = app(Product::class);
    }

    /**
     * Find published products by SKU
     * 
     * @param  {int} $sku
     * 
     * @return {Product}
     */
    public function findBySku(int $sku): Product 
    {
        // using 'whereIsPublished' and 'whereSku' scopes
        // defined on the Product model
        return $this->whereIsPublished(1)
            ->whereSku($sku)
            ->first();
    }
}
<?php

/**
 * In your routes/web.php
 */

Route::get('/', function (\App\Repositories\ProductRepository $productRepo) {

    // Use any Eloquent feature directly
    $productRepo->all()->dd();

    // Use your custom repository methods
    echo $productRepo->findBySku(12345)->name;

    // You can even query relations
    echo $productRepo->first()->category;

});

我遵循以下规则

  • 当您链式调用超过 2 个 Eloquent 方法时,请为它创建一个仓库方法。这适用于所有类型的方法、关系、查询作用域等。

创建外观

在我们的上一个例子中,我们使用了依赖注入来检索我们的仓库。
如果您想像使用模型一样使用您的仓库,您需要创建一个 Facade。

  • 首先,创建您的 Facade,例如在 app/Facades/ProductRepository
<?php

namespace App\Facades;

use Illuminate\Support\Facades\Facade;

class ProductRepository extends Facade
{
    protected static function getFacadeAccessor()
    {
        return 'ProductRepository';
    }
}
  • 然后,在您的 app/Providers/AppServiceProvider.php 中注册您的 Facade
<?php

namespace App\Providers;

use App\Repositories\ProductRepository;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        $this->app->bind('ProductRepository', function () {
            return new ProductRepository();
        });
    }

    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        //
    }
}
  • 最后一步,将此别名添加到您的 config/app.php 文件
'ProductRepository' => App\Facades\ProductRepository::class,

现在,我们的 routes/web.php 示例将如下所示

<?php

/**
 * In your routes/web.php
 */

use App\Facades\ProductRepository;

Route::get('/', function () {

    // Use any Eloquent feature directly
    ProductRepository::all()->dd();

    // Use your custom repository methods
    echo ProductRepository::findBySku(12345)->name;

    // You can even query relations
    echo ProductRepository::first()->category;

});

鸣谢

Sjors van Dongen (sitesjors@hotmail.com)

Yannick Leone (yannick.leone@gmail.com)