简体   繁体   中英

How $this->app->singleton() works in laravel?

In my laravel project I have following interface, repository and controller.

This is Interface

interface TrainingClassTypeInterfaces
{
    public function updateTrainingClassType($id, $request);
} 

This is Repository

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
            ]);
            .... 
        }
    
    }

This is controller

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);
        ..
    }

}

Everything working fine till here

As you can see I am using TrainingClassTypeEloquent's method inside TrainingClassTypesController . But it was returning error something like

Argument 1 passed to...::__construct() must be an instance of

Basically it was asking me to put instance of Model into TrainingClassTypeEloquent class. Then I did as following

$TCTypes = new AppTrainingClassType();
$TCT = new TrainingClassTypeEloquent($TCTypes);
$TCT->updateTrainingClassType($id, $request);

which was working fine but I was confused that this approach is not proper, there should be some proper way.

After googling I found another solution which is singleton binding, and then I tried following in AppServiceProvider

$this->app->singleton(
            \App\Services\Voyager\Eloquent\TrainingClassType\TrainingClassTypeInterfaces::class,
            \App\Services\Voyager\Eloquent\TrainingClassType\TrainingClassTypeEloquent::class
        );

After adding this singleton binding, I notice script was working without providing model instance into TrainingClassTypeEloquent class.

I would like to know how $this->app->singleton() is working, so in this way my concept would be clear about it. If someone knows then kindly guide me about it.

Thank you so much

It is all about BINDING a service to the service container .

What does $this->app->singleton(); method do?

The singleton method binds a class or interface into the service container so that Laravel can maintain dependency (when using an interface as the constructor parameter).

(Actually Singleton is a design pattern. Singleton implementation always returns the same object on subsequent calls instead of a new instance). So $this->app->singleton(); method returns the same object again and again.

Point to be noted that Laravel doc says:

There is no need to bind classes into the container if they do not depend on any interfaces . The container does not need to be instructed on how to build these objects, since it can automatically resolve these objects using reflection.

But your controller class depends on an interface, so the container needs to be informed and to do this, you need to use this $this->app->singleton(); method but there are other ways around.

Again, at the same time, this TrainingClassTypeEloquent::class has a dependency of AppTrainingClassType::class . But in this case, we do not need to worry about that because Laravel uses Reflection API to maintain its dependency as this class does not use interface as like TrainingClassTypesController::class class.

Once you are done with binding the service to the container, Laravel will then automagically put the service onto the constructor method as an argument where the interface is used.

I hope this would help you. You may find more help from this answer .

You need to register TrainingClassTypeEloquent

$this->app->singleton(TrainingClassTypeInterfaces::class, static function ($app) {
    return new TrainingClassTypeEloquent(new AppTrainingClassType());
});

Then you can inject it in your Controller

public function insertOrUpdate(TrainingClassTypeInterfaces $trainingService, $id)
{
    $trainingService->updateTrainingClassType($id, request());
}

Binding A Singleton

The singleton method binds a class or interface into the container that should only be resolved one time. Once a singleton binding is resolved, the same object instance will be returned on subsequent calls into the container:

$this->app->singleton('HelpSpot\API', function ($app) {
    return new \HelpSpot\API($app->make('HttpClient'));
});

For more go to HERE

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM