在Laravel中通过依赖注入解决抽象类的依赖关系
我使用存储库模式遇到了此问题。目前我使用一个接口和一个自定义类来实现它,然后键入提示到控制器的结构中,并且由于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
父类的构造被称为像正常的功能,无需触摸依赖解析器,所以你应该做的两种可能性之一:
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));
}
}
感谢您的时间,但这正是我想避免的,因为我必须编写parent :: __构造(App :: make(SomeModelClass :: class));在每个存储库中(目前我有6个扩展该公共父级),所以如果我不得不在该ComonRepo中添加/删除/修改依赖项,它会变得讨厌。 – user2430929
有趣的问题。我做了一些修补,但我不知道这是你想要的。但是您可以动态创建存储库类所需的Eloquent模型实例。
比方说,你必须存储在app\Models\User.php
您User
模型类:
<?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
模型类。
希望得到这个帮助!
嘿,谢谢你的回应。尽管这不是我想要的,但我可以在将来明确地找到它的用处,因为我经常发现自己注入了模型,有时它与回购的名称相匹配,所以很好。 不应该缓存getModel()方法吗?像在构造函数中调用它? – user2430929
这可能有帮助。您可以在对象解析和设置属性时监听。
$this->app->resolving(CommonRepo::class, function ($object, $app) {
// Called when container resolves object of any type...
$object->commonObject = app(CommonObject::class);
});
您可以从中得到启发这个http://meanderingsoul.com/dev/2015/04/dependency-injection-with-inherited-controllers-in-laravel-5 –
或者也许只是从ExampleRepository类中移除构造函数,除非调用父构造函数,否则没有其他要做的事情。 –
@MateuszDrost我没有输入,但还有更多的事情要做。每个存储库都有自己的依赖关系(通常只是雄辩模型,因为我不喜欢滥用外观)。 – user2430929