2016-11-18 122 views
1

我使用存储库模式遇到了此问题。目前我使用一个接口和一个自定义类来实现它,然后键入提示到控制器的结构中,并且由于Laravel,它将自动并递归地解决存储库的依赖关系。在Laravel中通过依赖注入解决抽象类的依赖关系

我也为此在服务提供商:

$this->app->bind(path/to/repoInterface,path/to/implementationClass) 

但是,由于我的方式编码这些存储库,以避免重复代码,我创建了一个有一个共同的方法把所有的抽象类这些知识库。这个类如下:

abstract class CommonRepo{ 

    public function __construct(SomeModelClass model){} 

    public function commonMethod(){//Code here} 

我的资料库具有以下结构:

public class ExampleRepository extends CommonRepo implements ExampleRepositoryI{ 

    public function __construct(){ 
    parent::__construct(); 
    } 
} 

Laravel不喜欢这一点,所以它给这个错误:

Argument 1 passed to path/to/repo/CommonRepo::__construct() must be an instance of path/to/model/SomeModelClass, none given, called in... 

所以,显然不解决类CommonRepo的依赖性,但它确实解决了对正常存储库的依赖关系。

我想,如果有可能,而不必做相关操作

什么我怎么能,那么,解决这一类的依赖使用类型提示(在Laravel方式)? PD:使用Laravel 5.2

+1

您可以从中得到启发这个http://meanderingsoul.com/dev/2015/04/dependency-injection-with-inherited-controllers-in-laravel-5 –

+0

或者也许只是从ExampleRepository类中移除构造函数,除非调用父构造函数,否则没有其他要做的事情。 –

+0

@MateuszDrost我没有输入,但还有更多的事情要做。每个存储库都有自己的依赖关系(通常只是雄辩模型,因为我不喜欢滥用外观)。 – user2430929

回答

2

父类的构造被称为像正常的功能,无需触摸依赖解析器,所以你应该做的两种可能性之一:

public class ExampleRepository extends CommonRepo implements ExampleRepositoryI 
{  
    public function __construct(SomeModelClass $model){ 
     parent::__construct($model); 
    } 
} 

public class ExampleRepository extends CommonRepo implements ExampleRepositoryI 
{  
    public function __construct(){ 
     parent::__construct(App::make(SomeModelClass::class)); 
    } 
} 
+0

感谢您的时间,但这正是我想避免的,因为我必须编写parent :: __构造(App :: make(SomeModelClass :: class));在每个存储库中(目前我有6个扩展该公共父级),所以如果我不得不在该ComonRepo中添加/删除/修改依赖项,它会变得讨厌。 – user2430929

2

有趣的问题。我做了一些修补,但我不知道这是你想要的。但是您可以动态创建存储库类所需的Eloquent模型实例。

比方说,你必须存储在app\Models\User.phpUser模型类:

<?php 

namespace App\Models; 

use Illuminate\Database\Eloquent\Model; 

class User extends Model 
{ 
    // 
} 

然后,您创建一个抽象基类所有的仓库类:app\Repositories\BaseRepository.php。这是您放置存储库类的所有常用功能的地方。但不是通过构造函数注入Eloquent实例,而是添加一个名为getModel()的方法来动态创建存储库的Eloquent模型实例。

<?php 

namespace App\Repositories; 

use ReflectionClass; 
use RuntimeException; 
use Illuminate\Support\Str; 

abstract class BaseRepository 
{ 
    protected $modelNamespace = 'App\\Models\\'; 

    public function getById($id) 
    { 
     return $this->getModel()->find($id); 
    } 

    public function getModel() 
    { 
     $repositoryClassName = (new ReflectionClass($this))->getShortName(); 

     $modelRepositoryClassName = $this->modelNamespace . Str::replaceLast('Repository', '', $repositoryClassName); 

     if (! class_exists($modelRepositoryClassName)) { 
      throw new RuntimeException("Class {$modelRepositoryClassName} does not exists."); 
     } 

     return new $modelRepositoryClassName; 
    } 
} 

现在让我们假设你想创建一个信息库用于User模型,并且这个用户的库必须实现以下接口:app\Repositories\UserRepositoryInterface.php

<?php 

namespace App\Repositories; 

interface UserRepositoryInterface 
{ 
    public function getByEmail($email); 
} 

创建app\Repositories\UserRepository.php类,并简单地从BaseRepository扩展它类。另外不要忘记实施在UserRepositoryInterface上定义的所有特定实现。

<?php 

namespace App\Repositories; 

use App\Repositories\BaseRepository; 
use App\Repositories\UserRepositoryInterface; 

class UserRepository extends BaseRepository implements UserRepositoryInterface 
{ 
    public function getByEmail($email) 
    { 
     return $this->getModel()->where('email', $email)->firstOrFail(); 
    } 
} 

这样你就可以绑定UserRepositoryInterface它是像这样实现:

$this->app->bind(\App\Repositories\UserRepositoryInterface::class, \App\Repositories\UserRepository::class); 

最后,你可以自由地注入UserRepositoryInterface到控制器的构造函数或方法。您还可以通过服务容器解决这样的:

$userRepository = App::make(App\Repositories\UserRepositoryInterface::class); 

$userRepository->getByEmail('[email protected]'); 

当然,这里有一个问题,以这种方式。存储库类应以相关模型启动,因此InvoiceRepository.php专用于Invoice.php模型类。

希望得到这个帮助!

+0

嘿,谢谢你的回应。尽管这不是我想要的,但我可以在将来明确地找到它的用处,因为我经常发现自己注入了模型,有时它与回购的名称相匹配,所以很好。 不应该缓存getModel()方法吗?像在构造函数中调用它? – user2430929

0

这可能有帮助。您可以在对象解析和设置属性时监听。

$this->app->resolving(CommonRepo::class, function ($object, $app) { 
    // Called when container resolves object of any type... 
    $object->commonObject = app(CommonObject::class); 
}); 

文档:https://laravel.com/docs/5.4/container#container-events