I have an interface that I wish to resolve on controllers. On registration inside a service provider, I am binding a class to the Service on condition.
Here is my service interface and two classes.
PaymentService::class
namespace App\Services\Payment\Contracts;
use App\Models\ParkingBill;
interface PaymentService
{
public function request(ParkingBill $parkingBill, string $client): bool;
public function confirm(ParkingBill $parkingBill, string $client): bool;
}
MpesaPaymentService::class
namespace App\Services\Payment;
use App\Models\ParkingBill;
use App\Models\PaymentMethod;
use App\Services\Payment\Contracts\PaymentService;
class MPesaPaymentService implements PaymentService
{
private PaymentMethod $paymentMethod;
public function __construct(PaymentMethod $paymentMethod)
{
$this->paymentMethod = $paymentMethod;
}
public function request(ParkingBill $parkingBill, string $client): bool
{
return true;
}
public function confirm(ParkingBill $parkingBill, string $client): bool
{
return false;
}
}
AirtelPaymentService::class
namespace App\Services\Payment;
use App\Models\ParkingBill;
use App\Models\PaymentMethod;
use App\Services\Payment\Contracts\PaymentService;
class AirtelMoneyPaymentService implements PaymentService
{
private PaymentMethod $paymentMethod;
public function __construct(PaymentMethod $paymentMethod)
{
$this->paymentMethod = $paymentMethod;
}
public function request(ParkingBill $parkingBill, string $client): bool
{
return true;
}
public function confirm(ParkingBill $parkingBill, string $client): bool
{
return false;
}
}
Here is the register method of PaymentServiceProvider
where am binding the class
$this->app->bind(PaymentService::class, function ($app) {
PaymentMethod::query()
->where('id', request()->input('payment_method'))
->first();
if ($paymentMethod->type == 'mpesa') {
return new MPesaPaymentService($paymentMethod);
} elseif ($paymentMethod->type == 'airtel') {
return new AirtelMoneyPaymentService($paymentMethod);
} else {
return null;
}
});
I have also added the provider to the list of providers
inside the app.php
config file.
'providers' => [
//...
\App\Providers\PaymentServiceProvider::class,
//...
]
Then this is where am trying to type hint it inside the controller method and access it inside the controller.
public function store(PaymentService $paymentService, Request $request, ParkingBill $parkingBill){
//...
return $paymentService->request($parkingBill, $request->payment_client);
}
I expect to get true or false based on the payment method I submit but am actually getting an exception.
Here is the exception
{
"message": "Target [App\\Services\\Payment\\Contracts\\PaymentService] is not instantiable.",
"exception": "Illuminate\\Contracts\\Container\\BindingResolutionException",
"file": "C:\\wamp64\\www\\my-valet\\vendor\\laravel\\framework\\src\\Illuminate\\Container\\Container.php",
"line": 1087,
"trace": [...]
I have tried to remove the conditional binding but it is still not behaving, what could I be doing wrong?
I am using php V8.1.0
and Laravel V9
CodePudding user response:
PaymentMethod query
$paymentMethod = PaymentMethod::find(request()->input('payment_method'));
Or,
$paymentMethod = PaymentMethod::query()
->where('id', request()->input('payment_method'))
->first();