Dependency Injection with Laravel Service Container

Classes may depend on other classes, Laravel addresses this issue with Reflection Classes, and the service container’s goal is to manage class dependencies through dependency injection.

Let’s put it to the test with some code.

Create a folder called “Billing” and place a class called “PaymentGateWay” inside it.

Afterward, make a controller with the name PaymentController that is dependent on the PaymentGateWay class.

namespace App\Http\Controllers;
use App\Billing\PaymentGateWay;
use Illuminate\Http\Request;

class PaymentController extends Controller
{
       public function store(PaymentGateWay $paymentGateWay)
    {//$paymentGatway=new PaymentGateWay();
       dd($paymentGateWay->charnge(2500));    
}}

We can see from this that we can feed the dependence right into the method without having to use “new PaymentGateway().” But we cannot bind it in this way if the parent class of the class contains a constructor with a parameter. We must employ the register method of the AppService Provider. We must obtain the data from the register function of the parent class constructor. That implies that the Class must be bound to the AppServiceProvider.(Learn about Service Provider)

<?php namespace App\Billing;
use Illuminate\Support\Str;

class PaymentGateWay
{
    public function __construct($currency)
    {
        $this->currency=$currency;
    }
    public function  charge($amount)
    {
        return [
            'amount'=>$amount,
            'confirmation_number'=>Str::random(),
            'currency'=>$this->currency,
        ];
    }
}?> 


<?php namespace App\Http\Controllers;
use App\Billing\PaymentGateWay;
use Illuminate\Http\Request;
class PaymentController extends Controller
{
    public function store(PaymentGateWay $paymentGateWay)
    {// $paymentGatway=new PaymentGateWay();     
     dd($paymentGateWay->charnge(2500));
}}?>   

<?php namespace App\Providers;
use App\Billing\PaymentGateWay;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
        public function register()
    {
                $this->app(PaymentGateWay::class,function ($app){
            return new PaymentGateWay('usd');
        });
    }
    public function boot(){}
}

But the binding technique has a problem. Each object of the class PaymentGateway will be a new object if we use the bind method. We must thus utilize Laravel’s singleton approach for this reason. When employing singletons, an object will only need to be initialized once, making it the identical object each time it is created.

Let’s imagine we want to offer the user a discount.

<?php

namespace App\Billing;
use Illuminate\Support\Str;

class PaymentGateWay
{
    private $discount;
    private $currency;
    public function __construct($currency)
    {
        $this->currency=$currency;
        $this->discount=0;
    }
    public function  charnge($amount)
    {
        return [
            'amount'=>$amount-$this->discount,
            'confirmation_number'=>Str::random(),
            'currency'=>$this->currency,
            'discount'=>$this->discount,
        ];
    }
    public function setDiscount($amount)
    {
        $this->discount=$amount;
    }
}?> 

Therefore, we need to build a class called orderdetails and a new folder in the project named Order.

 
namespace App\Order;
use App\Billing\PaymentGateWay;
class OrderDetails
{
    private $paymentGateWay;
    public function __construct(PaymentGateWay $paymentGateWay)
    {
        $this->paymentGateWay=$paymentGateWay;
    }
    public function all()
    {
        $this->paymentGateWay->setDiscount(500);
        return ['name'=>'Navid',
            'address','Mirpur'            
    ];}

Consequently, we must alter the AppService provider.

<?php
namespace App\Providers;
l.ms/luse App\Billing\PaymentGateWay;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider    
   { public function register(){
                $this->app->singleton(PaymentGateWay::class,function ($app){
            return new PaymentGateWay('usd');
        });
    }    

    public function boot(){
    }

And also have to change in PaymentController

<?php

namespace App\Http\Controllers;

use App\Billing\PaymentGateWay;
use App\Order\OrderDetails;
use Illuminate\Http\Request;

class PaymentController extends Controller
{
public function store(OrderDetails $orderDetails,PaymentGateWay $paymentGateWay)
{
//  $paymentGatway=new PaymentGateWay();$order=$orderDetails->all();
dd($paymentGateWay->charge(2500));
}
}

What if we use a credit card processing business in addition to a bank? We cannot just utilize the static method of the PaymentGateWay class since they are two distinct features. Due to this, let’s rename PaymentGateWay to BankPaymentGateWay, make an interface called PaymentGateWay, and use BankPaymentGateWay to implement it.
Make a payment gateway interface.

 <?php

namespace App\Billing;

interface PaymentGateWay
{
    public function charnge($amount);

    public function setDiscount($amount);
}

?>

Then we can implement it;

If it’s a Credit Payment then.

<?php
namespace App\Billing; use Illuminate\Support\Str;
class CreditPaymentGateWay implements PaymentGateWay
{
    private $discount;
    private $currency;
    public function __construct($currency)
    {
        $this->currency=$currency;
        $this->discount=0;
    }

    public function  charge($amount)
    {
        $fees=$amount*0.03;
        return [
            'amount'=>$amount-$this->discount+$fees,
            'confirmation_number'=>Str::random(),
            'currency'=>$this->currency,
            'discount'=>$this->discount,
            'fees'=>$fees,
        ];
    }

    public function setDiscount($amount)
    {
        $this->discount=$amount;
    }
}
?>

If it is BankPayment

<?php namespace App\Billing;
use Illuminate\Support\Str;
class BankPaymentGateWay implements PaymentGateWay
{
    private $discount;
    private $currency;
    public function __construct($currency)
    {
        $this->currency=$currency;
        $this->discount=0;
    }

    public function  charnge($amount)
    {
        return [
            'amount'=>$amount-$this->discount,
            'confirmation_number'=>Str::random(),
            'currency'=>$this->currency,
            'discount'=>$this->discount,
        ];
    }
    public function setDiscount($amount)
    {
        $this->discount=$amount;
    }
}
?>

Also, have to change in AppServiceprovider
<?php namespace App\Providers;
use App\Billing\BankPaymentGateWay;
use App\Billing\CreditPaymentGateWay;
use App\Billing\PaymentGateWay;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{    public function register()
    {
                $this->app->singleton(PaymentGateWay::class,function ($app){
            if (request()->has('credit')){
                return new CreditPaymentGateWay('usd');
            }
           return new BankPaymentGateWay('usd');
        });
    }
    public function boot(){
        }

Nothing else has to change.

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top