ratno/laravel-repositories

使用原生 Eloquent 函数的 Laravel 仓库

2.0.5 2020-10-15 11:28 UTC

This package is auto-updated.

Last update: 2024-09-15 20:17:54 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 方法时,为它创建一个仓库方法。这适用于所有类型的操作,如关系、查询作用域等。

创建外观

在我们之前的示例中,我们使用依赖注入来检索我们的仓库。
如果您想像使用模型一样使用您的仓库,您需要创建一个外观。

  • 首先,创建您的外观,例如在 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 中,注册您的外观。
<?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)