代码之家  ›  专栏  ›  技术社区  ›  abbood

如何在laravel中创建一个控制器构造函数,它接受同一接口的两个具体实现?

  •  2
  • abbood  · 技术社区  · 8 年前

    背景

    注意:这是使用拉弗5.3,请不要判断。

    我们正在尝试对我们的laravel控制器使用依赖注入,并将尽可能多的业务逻辑推送到repo中,这些repo在控制器实例化时注入控制器。

    我们已经有了一个有效的例子:

    class AcmeController extends Controller
    {
        protected $repository;
    
        public function __construct(AcmeInterface $repository)
        {
            $this->repository = $repository;
        }
    }     
    

    在app/providers/repositoryserviceprovider.php中,我们进行绑定:

    namespace App\Providers;
    
    use Illuminate\Support\ServiceProvider;
    
    class RepositoryServiceProvider extends ServiceProvider
    {
        /**
         * Bootstrap the application services.
         *
         * @return void
         */
        public function boot()
        {
            //
        }
    
        /**
         * Register the application services.
         *
         * @return void
         */
        public function register()
        {
            $this->app->bind(\App\Repositories\Contracts\AcmeInterface::class, \App\Repositories\OpCity\AcmeRepo::class);
        }
    }
    

    然后acmerepo自然实现了acmeinterface:

    class AcmeRepo implements AcmeInterface
    

    问题

    现在我们有一个案例 相同的 模型保存在内存类型存储(redis)中,其余的保存在关系数据库存储(psql)中。我们希望有两个单独的repo,其中每个repo都是特定于其存储类型的,即RedisAcmeRepo和SqlAcmeRepo

    怎么可能在 AcmeController 构造器?

    public function __construct(AcmeInterface $sqlRepo, AcmeInterface $redisRepo)
    {
        $this->sqlRepo = $sqlRepo;
        $this->redisRepo = $redisRepo;
    }
    
    2 回复  |  直到 8 年前
        1
  •  2
  •   abbood    8 年前

    基于上面的答案,我提出了这个解决方案,这种方式也使用了复合模式(我将repo的名称从acme改为shopperlogs):

    <?php
    
    interface ShopperLogInterface
    {
    
        public function getLogs($from, $to, $shopper);
    }
    
    class ShopperLogsController extends Controller
    {
    
        /**
         * service 
         *
         * @var \App\Repositories\Contracts\ShopperLogInterface
         * @access protected
         */
        protected $manager;
    
        public function __construct(ShopperLogInterface $manager)
        {
            $this->manager = $manager;
        }
    }
    
    
    
    class ShopperLogManager implements ShopperLogInterface
    {
        protected $sqlRepo;
        protected $redisRepo;
    
        public function __construct(ShopperLogInterface $sqlRepo, ShopperLogInterface $redisRepo)
        {
            $this->sqlRepo = $sqlRepo;
            $this->redisRepo = $redisRepo;
        }
    
        public function getLogs($from, $to, $shopper)
        {
            $todayRange = //get the today part of from -- to
    
            /**
             * array of ShopperLogs 
             */
            $todaysLogs;
    
            if ($todayRange) {
                $this->redisRepo->getLogs($todayRange->start, $todayRange->finish, $shopper); 
            }
    
            $legacyRange = //get the part of from -- to that excludes today's range
    
            /**
             * array of ShopperLogs 
             */
            $legacyLogs;
    
            if ($legacyLogs) {
                $this->sqlRepo->getLogs($todayRange->start, $todayRange->finish, $shopper); 
            }
    
            return merge($todayRange, $legacyRange);
    
        }
    }
    
    
    class ShopperLogsSqlRepo implements ShopperLogInterface
    {
        /**
         * @var /Illuminate\Database\Eloquent\Model/ShopperLogs
         */
        protected $model;
    
    
        /**
         * @param /Illuminate\Database\Eloquent\Model/ShopperLogs $model
         */
        public function __construct(ShopperLogs $model)
        {
            $this->model = $model;
        }
    
        public function getLogs($from, $to, $shopper)
        {
            $this->model->whereLogs //do eloquent sql stuff here
        }
    }
    
    
    
    class ShopperLogsRedisRepo implements ShopperLogInterface
    {
        /**
         * @var \Redis\Model\Class 
         */
        protected $model;
    
    
        /**
         * @param \Redis\Model\Class $model
         */
        public function __construct(ShopperLogs $model)
        {
            $this->model = $model;
        }
    
        public function getLogs($from, $to, $shopper)
        {
            $this->model->whereLogs //do redis stuff
        }
    }
    
    
    
    
    namespace App\Providers;
    
    use Illuminate\Support\ServiceProvider;
    
    class RepositoryServiceProvider extends ServiceProvider
    {
        /**
         * Bootstrap the application services.
         *
         * @return void
         */
        public function boot()
        {
            //
        }
    
        /**
         * Register the application services.
         *
         * @return void
         */
        public function register()
        {
    
        $this->app->bind(\App\Repositories\Contracts\ShopperLogInterface::class, \App\Managers\ShopperLogManager::class);
    
        $this->app->bind(ShopperLogsController::class, function ($app) {
            return new ShopperLogsController($app->make(ShopperLogManager::class));
        });
        $this->app->bind(\App\Repositories\Contracts\ShopperLogInterface::class, function() {
            return new \App\Managers\ShopperLogManager(new \App\Repositories\ShopperLogsSqlRepo(new \App\ShopperLog), new \App\Repositories\ShopperLogsRedisRepo(new \App\ShopperLog));
        });
    
        }
    }
    
        2
  •  1
  •   J. Doe    8 年前

    例如,您可以这样做:

    $this->app->bind(AcmeController::class, function ($app) {
       return new AcmeController($app->make(sqlRepo::class), $app->make(redisRepo::class));
    });
    

    或者这个:

    $this->app->when(AcmeController::class)
          ->needs('$sqlRepo')
          ->give($app->make(sqlRepo::class));
    
    $this->app->when(AcmeController::class)
          ->needs('$redisRepo')
          ->give($app->make(redisRepo::class));
    
    推荐文章