在我的 laravel 项目中,我有以下接口、存储库和控制器。
这是界面
interface TrainingClassTypeInterfaces
{
public function updateTrainingClassType($id, $request);
}
Run Code Online (Sandbox Code Playgroud)
这是存储库
use App\Models\Trainings\AppTrainingClassType;
class TrainingClassTypeEloquent implements TrainingClassTypeInterfaces
{
protected $model;
public function __construct(AppTrainingClassType $appTrainingClassType)
{
$this->model = $appTrainingClassType;
}
public function updateTrainingClassType($id, $request)
{
$response = false;
$isUpdated = $this->model::where('training_class_id',$id)->update([
'app_id' => $request->app_id
]);
....
}
}
Run Code Online (Sandbox Code Playgroud)
这是控制器
class TrainingClassTypesController extends \TCG\Voyager\Http\Controllers\VoyagerBaseController
{
protected $trainingService;
public function __construct(TrainingClassTypeEloquent $trainingClassTypeInterfaces) {
$this->trainingService = $trainingClassTypeInterfaces;
}
public function insertOrUpdate()
{
...
$this->trainingService->updateTrainingClassType($id, $request);
..
}
}
Run Code Online (Sandbox Code Playgroud)
到这里一切正常
正如你所看到的,我在内部使用 TrainingClassTypeEloquent 的方法TrainingClassTypesController。但它返回了类似的错误
Argument 1 passed to ...::__construct() must be an instance of
基本上它要求我将模型的实例放入TrainingClassTypeEloquent类中。然后我做了如下
$TCTypes = new AppTrainingClassType();
$TCT = new TrainingClassTypeEloquent($TCTypes);
$TCT->updateTrainingClassType($id, $request);
Run Code Online (Sandbox Code Playgroud)
工作正常,但我很困惑这种方法不正确,应该有一些正确的方法。
谷歌搜索后,我找到了另一个解决方案,即单例绑定,然后我尝试在 AppServiceProvider 中执行以下操作
$this->app->singleton(
\App\Services\Voyager\Eloquent\TrainingClassType\TrainingClassTypeInterfaces::class,
\App\Services\Voyager\Eloquent\TrainingClassType\TrainingClassTypeEloquent::class
);
Run Code Online (Sandbox Code Playgroud)
添加此单例绑定后,我注意到脚本可以正常工作,而无需向TrainingClassTypeEloquent类中提供模型实例。
我想知道它$this->app->singleton()是如何工作的,这样我的概念就会很清楚。如果有人知道,请指导我。
太感谢了
这都是关于将服务绑定到服务容器。
方法有什么作用$this->app->singleton();?
单例方法将类或接口绑定到服务容器中,以便 Laravel 可以保持依赖关系(当使用接口作为构造函数参数时)。
(实际上Singleton是一种设计模式。Singleton实现在后续调用中总是返回相同的对象,而不是一个新的实例)。所以$this->app->singleton();方法一次又一次返回同一个对象。
需要注意的是 Laravel 文档说:
如果类不依赖于任何接口,则无需将类绑定到容器中。容器不需要被告知如何构建这些对象,因为它可以使用反射自动解析这些对象。
但是您的控制器类依赖于接口,因此需要通知容器并且要执行此操作,您需要使用此$this->app->singleton();方法,但还有其他方法。
同时,这又TrainingClassTypeEloquent::class具有AppTrainingClassType::class. 但在这种情况下,我们不需要担心这一点,因为 Laravel 使用Reflection API来维护其依赖关系,因为该类不像TrainingClassTypesController::class类那样使用接口。
完成将服务绑定到容器后,Laravel 会自动将服务作为使用接口的参数放入构造函数方法中。
我希望这对你有帮助。您可能会从这个答案中找到更多帮助。
您需要注册 TrainingClassTypeEloquent
$this->app->singleton(TrainingClassTypeInterfaces::class, static function ($app) {
return new TrainingClassTypeEloquent(new AppTrainingClassType());
});
Run Code Online (Sandbox Code Playgroud)
然后你可以将它注入到你的控制器中
public function insertOrUpdate(TrainingClassTypeInterfaces $trainingService, $id)
{
$trainingService->updateTrainingClassType($id, request());
}
Run Code Online (Sandbox Code Playgroud)