How do I do the type-hint 'automatic injection' custom class laravel - laravel

Below is the EmailNotifier Class
class EmailNotifier
{
public function notify()
{
echo 'Sending payment notification via email' ;
}
}
Below is my AppServiceProvider
class AppServiceProvider extends ServiceProvider
{
public function boot()
{
}
public function register()
{
$this->app->make(App\EmailNotifier::class); // resolve the EmailNotifier Class
}
}
Below is billing class
class Billing
{
protected $notifier;
public function __construct(EmailNotifier $notifier)
{
$this->notifier = $notifier;
}
public function pay()
{
// Process the bill payment
$this->notifier->notify();
}
}
and in my controller I did
$data = new Billing(1);
As you can see I already resolve the EmailNotifier Class at the AppServiceProvider Class but when I call that like the code above, it throws an error said 'must be an instance of EmailNotifier'
and based on the laravel documentation, it's stated that :
you may "type-hint" the dependency in the constructor of a class that
is resolved by the container (for the automatic injection)
how do I achieve automatic injection for the type-hint in laravel ?

Use $data = resolve(Billing::class); instead of $data = new Billing(1); and you can remove $this->app->make(App\EmailNotifier::class); // resolve the EmailNotifier Class from service provider's register method.

Related

Call to a member function reply() on null laravel botman

This is the code of model. I am unable to change access the function of conversation using the model method as i am passing data from view to botman conversation constructor through request.
<?php
This is the conversation class
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use App\Conversations\TestConversation;
class CheckSaved extends Model
{
public function hasDate($scheduled_date):bool
{
if($scheduled_date)
{
$testconv = new TestConversation($scheduled_date);
$testconv->showOther();
}
return false;
}
}][1]
<?php
namespace App\Conversations;
use BotMan\BotMan\Messages\Incoming\Answer;
use BotMan\BotMan\Messages\Conversations\Conversation;
use App\Http\Traits\PropertyDetails;
use App\Models\CheckSaved;
class TestConversation extends Conversation
{
public $is_saved;
public function __construct($request)
{
if(isset($request->scheduled_date))
{
$checkDate = new CheckSaved();
$this->is_saved = $checkDate->hasDate($request->scheduled_date);
}
}
public function sayHi()
{
// dd($request);
$this->say("<input type='datetime-local' id='birthdaytime' name='birthdaytime'>");
$this->say("<button class='btn-date' onclick='test()'>Save</button>");
}
public function showOther()
{
$this->say('Hi');
}
public function run()
{
$this->sayHi();
}
}
This is the image of Model
I am getting reply() on null if try to call a function called "showOther()" inside TestConversation. I am stuck on it please someone help or contact me.

Laravel contextual binding to be more specific to methods rather then class only

I am trying to understand laravel bind.
let's say, I have UploadFileController.php
Route::post('/upload/images', 'UploadFilesController#uploadImage');
Route::post('/upload/pdf', 'UploadFilesController#uploadPdf');
then in the controller,
class UploadFilesController extends Controller
{
private $uploadServiceInterface;
public function __construct(UploadServiceInterface $uploadServiceInterface)
{
$this->uploadServiceInterface = $uploadServiceInterface;
}
public function uploadImage(Request $request)
{
$this->uploadServiceInterface->store();
}
public function uploadPdf()
{
$this->uploadServiceInterface->store();
}
}
Now, the uploadServiceProvider,
class UploadServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->when(UploadFilesController::class)
->needs(UploadServiceInterface::class)
->give(ImagesUploadService::class);
}
}
Now, I know "when" says that UploadFileController class with uploadService interface will give the imageUploadService but is it possible I make it more specific to function in uploadFileController class, like
$this->app->when(uploadFilesController::uploadImage())
->needs(UploadServiceInterface::class)
->give(ImagesUploadService::class);
then it takes to the imagesUploadService class same for pdf upload class.

bind abstract class service in provider laravel

Gives an error:
Target [MyVendor\ProductList\ProductServiceInterface] is not instantiable.
ProductServiceInterface
namespace MyVendor\ProductList;
interface ProductServiceInterface
{
public function productList();
public function getProductSpeed();
}
ProductColorService
namespace MyVendor\ProductList\Service;
abstract class ProductColorService implements \MyVendor\ProductList\ProductServiceInterface
{
public function productList()
{
$color = "black";
return $color;
}
}
** ProductSpeedService **
namespace MyVendor\ProductList\Service;
abstract class ProductSpeedService implements \MyVendor\ProductList\ProductServiceInterface {
public function getProductSpeed() {
$speed = 200;
return $speed;
}
}
Provider :
namespace MyVendor\ProductList;
use Illuminate\Support\ServiceProvider;
use MyVendor\ProductList\ProductServiceInterface;
use MyVendor\ProductList\Service\ProductColorService;
class ProductColorServiceProvider extends ServiceProvider
{
public function boot()
{
$this->loadRoutesFrom(__DIR__ . '/routes/color.php');
}
public function register()
{
$this->app->bind('MyVendor\ProductList\ProductServiceInterface','MyVendor\ProductList\Service\ProductColorService');
$this->app->bind('MyVendor\ProductList\ProductServiceInterface','MyVendor\ProductList\Service\ProductSpeedService');
}
}
Whats wrong in this code? Actually I need to override some functions in interface using service. ie each service should override one method.
namespace MyVendor\ProductList\Http\Controllers;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use MyVendor\ProductList\Models\Product;
use MyVendor\ProductList\ProductServiceInterface;
class ProductListController extends Controller
{
public function index(ProductServiceInterface $product_service)
{
$color = $product_service->productList();
$speed = $product_service->getProductSpeed();
dd($color," = ",$speed);
$product = Product::get();
return view('ProductList::product',compact('product'));
}
}
here productList() in one service and productSpeed() from another service
You can't instantiate abstract classes. The whole point of them is there can never be an instance of them, so if you bind your interface to your abstract class with a method, it simply can never be abstract. Abstract is for classes in inheritance structures you do not want to have the users to create new ones.
So there is no reason for the abstract, abstract is for something like this.
abstract class Vehicle {
protected $wheels;
public function getWheels() {
return $this->wheels;
}
}
class Car extends Vehicle {
protected $wheels = 4;
}
class Bike extends Vehicle {
protected $wheels = 2;
}
You can not make a vehicle as it is not a concrete implementation, as it is a parent class to help with methods shared across two classes. So short version, just remove the abstract keyword. If you don't know why you add it, it is not needed.

Should I create separate provider for service in Laravel?

I have custom service in Laravel:
<?php
namespace App\Library\Services;
class RegisterCustomerService
{
public function do()
{
return 'Output from DemoOne';
}
}
In which cases I should create provider for this service, when not?
Could I use RegisterCustomerService as composition in specific class like:
$c = new RegisterCustomerService();
Or am i obligated to create Provider?
Service providers are only necessary if the service needs custom configuration. You can typehint any class in the constructor and Laravel will try to resolve it to an instance.
An example service provider that configures a service with a config value is shown below:
class MyServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->singleton(MyCustomService::class, function ($app) {
return new MyCustomService(config('api_token'));
});
}
}
usage:
class ProjectController {
// Receives the service configured by the service provider above.
public function __construct(MyCustomService $service){
$this->service = $service;
}
}
More details about service providers: https://laravel.com/docs/5.8/providers

Laravel abstract class auto injection

Laravel auto injects abstract class , but when there is another parameter with abstract class, Laravel ignore it and hence, getting error.
public interface PostRepository {
public function getPostById($id)
}
class EloquentPost implements PostRepository{
public function getPostById($id){
return Post::find($id);
} }
Its working fine when I use it like:
class Controller PostController {
private $post;
public function __construct(PostRepository $post)
$this->post = $post;
}
But when I use it like
class Controller PostController {
private $post;
public function __construct($someOtherParam, PostRepository $post)
$this->post = $post;
}
then Laravel show error.
Laravel is unable to determine what should be injected as the first parameter to the controller's constructor as you have no type hint for that parameter.
If that $someOtherParam is something that should come in the URL, you will be able to have that injected in controller's action method to which given route points, but not in the constructor.

Resources