在Laravel

时间:2016-11-18 23:27:35

标签: php dependency-injection laravel-5.2 abstract-class

我使用存储库模式遇到了这个问题。目前我使用一个接口和一个自定义类来实现它,然后在控制器的构造中键入提示,并且由于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方式)而不必执行与 new 运算符相关的任何操作

那么,我怎样才能解决该类的依赖关系? PD:使用Laravel 5.2

3 个答案:

答案 0 :(得分: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));
    }
}

答案 1 :(得分:2)

好的问题。我做了一些修补,虽然我不知道这是否是你正在寻找的。但您可以动态创建存储库类所需的Eloquent模型实例。

我们假设您已将$i=0; $linkname = $_POST["recname"][0]; while($linkname != ""){ $linkname = $_POST["recname"][$i]; $linkurl = $_POST["reclink"][$i]; $linktype = $_POST["rectype"][$i]; $linkname = $res->real_escape_string($linkname); $linkurl = $res->real_escape_string($linkurl); $linktype = $res->real_escape_string($linktype); $result299 = mysqli_query($res, "INSERT INTO user_links (linkname,linkurl,linktype,sort) VALUES ('$linkname','$linkurl','$linktype','0')"); $i++; } 模型类存储在User中:

app\Models\User.php

然后,为所有存储库类创建基本抽象类:<?php namespace App\Models; use Illuminate\Database\Eloquent\Model; class User extends Model { // } 。您可以在此处放置存储库类的所有常用功能。但是,您可以添加一个名为app\Repositories\BaseRepository.php的方法,为您的存储库动态创建一个Eloquent模型实例,而不是通过构造函数注入Eloquent实例。

getModel()

现在让我们假设您要为<?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('john@example.com'); 专用于InvoiceRepository.php模型类。

希望这有帮助!

答案 2 :(得分: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