safiullahsarhandi/laravel-repository

此包用于在 Laravel 中以非常少的代码实现仓储模式

1.0.5 2023-08-29 21:41 UTC

This package is auto-updated.

Last update: 2024-09-29 23:56:33 UTC


README

此包用于在 Laravel 中以非常少的代码实现仓储模式。这种实现的背后的思想是允许模块化方法,并使你的项目中的每个实体可重用,同时通过模型绑定、仓储生成器、仓储事件等功能增强你的编码体验。

安装

使用以下命令,你可以将此包添加到你的 Laravel 项目中

composer require safiullahsarhandi/laravel-repository

安装此包后,您需要在项目的 config/app.php 中注册提供者 LaravelRepository\Providers\RepositoryServiceProvider::class,

发布资产

  1. php artisan vendor:publish --tag=repository-config 此命令将在 config 目录中创建 repository.php 配置文件,该文件将存储此类信息。
<?php 
//config/repository.php
return [
      /* 
      * repositories will contain all the repositories namespaces from app/Repositories directory  
      * and bind Contract and model associated with it  
      *
      */
      'repositories' => [],
  ];
?> 

用法

此包提供了一些命令,可以帮助执行不同的任务,或者可以说使用此包是必需的。

  1. 如何创建仓储

    命令: php artisan make:repository <path/to/repository> <model>

    使用此包创建仓储将变得简单。它会在配置文件中注册您的仓储,并在 app\Repositories 目录中创建一系列文件,例如 php artisan make:repository User/UserRepository User 将更新您的 app\Repositories 文件夹如下

    repository-dir

    并且更新您的配置文件如下

    <?php 
    //config/repository.php
    return [
          /* 
          * repositories will contain all the repositories namespaces from app/Repositories directory  
          * and bind Contract and model associated with it  
          *
          */
          'repositories' => [
                App\Repositories\User\UserRepository::class => [
                   'model' => App\Models\User::class,
                   'contract' => App\Repositories\User\UserRepositoryContract::class,
                ]
          ],
      ];
    ?> 
    
  2. 创建查询过滤器

    过滤器的思想是扩展数据库查询。在调用任何特定仓储时,您将看到以下仓储函数的结构在某种程度上相似,并且包含最小数量的代码。我将在下一节中解释过滤器的实现,以便您熟悉它,但现在是时候检查如何使用给定命令生成查询过滤器了。

    命令: php artisan make:filter <path/to/filter>

    例如: php artisan make:filter Api/UserFilter 这将在 app/Filters/Api/UserFilters.php 中生成过滤器

    filter-dir

    这是 make:filter 命令的最终输出。

    <?php
    
    namespace App\Filters\Api;
    use LaravelRepository\Abstracts\Filters;
    
    class UserFilter extends Filters {
    
        protected $filters = ['search'];
    
        public function search($value)
        {
            $this->builder->where("status", $value);
        }
    }
    

    使模型可过滤

    在说明如何使用 UserFilter::class 与任何仓储之前,我们应该知道在将过滤器绑定到仓储之前需要遵循的基本步骤。我们必须在模型中使用 LaravelRepository\Traits\Filterable 以便按需过滤任何模型。

    <?php
    
    namespace App\Models;
    
    use Illuminate\Database\Eloquent\Factories\HasFactory;
    use Illuminate\Database\Eloquent\Model;
    use LaravelRepository\Traits\Filterable;
    
    class User extends Model
    {
        use HasFactory, Filterable;
    
        protected $fillable = ['name','email','password'];
    }
    
    

    如何使用查询过滤器

    过滤类应具有与您在 protected $filters 属性中注册的相同名称的方法。每次将查询过滤器绑定到仓储时,它都会读取 Laravel 的 Illuminate\Support\Request 实例并验证 HTTP 请求中参数的可用性。您可以这样做

    use App\Filters\Api\UserFilter;
    use App\Repositories\User\UserRepositoryContract;
    use Illuminate\Support\Facades\Route;
    
    
    //URL looks like "https://:8000/users?search=active" will give you better understanding for filters   
    
    Route::get('/users', function (UserRepositoryContract $user,UserFilter $filter) {
        $data = $user->findAll($filter);
        // under the hood it work like this
       // User::where(status,'active')->get();
    });
    
    

    扩展查询过滤器

    有时您想在不暴露任何特定 route 中的每个参数的情况下扩展底层过滤器。您可以在过滤器传递到仓储之前以编程方式扩展过滤器。

    Route::get('/account', function (UserRepositoryContract $user,UserFilter $filter) {
        // extends request after it has been initialized
        $filter->extendRequest([
            'user_id' => auth()->id(),
        ]);
        $data = $user->findOne($filter);
        // under the hood it work like this
        // User::where('user_id',1)->first();
    });
    
    

    并且您的 UserFilter::class 应该是这样的

    <?php
    
    namespace App\Filters\Api;
    use LaravelRepository\Abstracts\Filters;
    
    class UserFilter extends Filters {
    
        protected $filters = ['search','user_id'];
    
        public function search($value)
        {
            $this->builder->where("status", $value);
        }
        public function user_id($value)
        {
            $this->builder->where("id", $value);
        }
    }
    
    
  3. 创建仓储事件

    您不能覆盖仓库提供的预定义函数,但有时,或者更确切地说,大多数时候,您需要在执行过程中对特定时间进行筛选或执行任何特定操作。使用直接仓库函数无法实现这一点,因为它们只是与数据交互,并不实现您的业务逻辑。为了实现这一点,您可以将其与 仓库事件 绑定。您可以将事件视为类似于 Laravel 监听器。而监听器仅在模型上触发,但在这里,仓库事件仅对仓库可用。

    命令:php artisan make:repository-event <path/to/repository-event>

    例如:使用以下命令 php artisan make:repository-event User/UserRepositoryEvent 将在 app/Events/User/UserRepositoryEvent.php 中创建事件类,并默认包含以下代码片段。

    <?php
    namespace App\Events\User;
    
    use Illuminate\Database\Eloquent\Model;
    use LaravelRepository\Contracts\EventContract;
    
    class UserRepositoryEvent implements EventContract {
    
        public function beforeCreate($repository,array $params = []){}
    
        public function created(Model $model){}
    
        public function beforeUpdate($repository,array $params = []){}
    
        public function updated(Model $model){}
    
        public function beforeDelete($repository,mixed $param){}
    
        public function deleted(mixed $param){}
    
        public function beforeFetch($repository,mixed $params = null){}
    
        public function fetched(null|Model $value = null){}
    }
    
    

    如何使用事件

    当您将 事件类 与任何 仓库 绑定时,会调用仓库事件。您可以看到以下所有仓库方法。假设我们想要创建 `订单` 并将用户选择的产品存储在数据库中。这是如何实现的?您可以创建自己的方法并调用它,但我们推荐使用事件;

    use App\Repositories\Order\OrderRepositoryContract;
    use App\Events\Order\OrderRepositoryEvent;
    
    Route::post('/orders', function (OrderRepositoryContract $order) {
        // params will be passed using \Illuminate\Support\Request;
        // for now just take it as an example
        $params = [
            'customer_email' => 'customer@example.com',
            'customer_name' => 'Mark Endrew',
            'products' => [
                1 => ['qty' => 1, 'price' => 200 ],
                2 => ['qty' => 1, 'price' => 300 ],
            ] 
        ];  
        $data = $order->event(OrderRepositoryEvent::class)->create($params);
    
    });
    
    
    

    现在,我们想要将关联到 订单产品 存储在我们的数据库中。因为我们已经调用了 create 方法,所以我们可以将一些逻辑放在 beforeCreatecreated 中,在 App\Events\Order\OrderRepositoryEvent::class

    <?php
    namespace App\Events\Order;
    
    use Illuminate\Database\Eloquent\Model;
    use LaravelRepository\Contracts\EventContract;
    
    class OrderRepositoryEvent implements EventContract {
    
        private $params;
        
        public function beforeCreate($repository,array $params = [])
        {
             //you don't need to do this every time 
            // and we don't have another way to access params in created
            $this->params = $params;
        }
    
    
        public function created(Model $model)
        {
            // store products after order created 
            $products = $this->params['products'];
            // storing laravel belongsToMany order_products
            $model->products()->attach($products);      
            
            // process merchant payment  
            $model->pay();
              
        }
    } 
    
    

    仓库方法