Dependency Injection into a service in Laravel - laravel

I have the following code which I try to create an instance of Guzzle in my service class. I am not sure what is the proper way to Inject this dependency in Laravel, this is my first time using Laravel, I have used Symfony like 8 years ago.
I get a Runtime Exception
RuntimeException : A facade root has not been set.
My code
namespace App\Services;
use Illuminate\Support\Facades\Http;
class DataForSeoService
{
/**
* #var \Illuminate\Http\Client\PendingRequest
*/
private ?\Illuminate\Http\Client\PendingRequest $V3http = null;
public function __construct() {
$this->V3http = Http::withBasicAuth('xxx', 'xxx');
}

Related

Adding a new method to a Laravel vendor class

I'm fairly new to Laravel and I want to add a method to a vendor class. I'm sure it's just my unfamiliarity with how Laravel works, so I'm hoping there's a pretty easy solution.
I've installed a package (https://github.com/kawax/laravel-amazon-product-api) and want to add a new method that I can call like:
use App\Repositories\AmazonSearch\AmazonSearch;
$response = AmazonSearch::alter('All');
So I created a new folder app/Repositories/AmazonSearch and extended the AmazonClient class:
<?php
namespace App\Repositories\AmazonSearch;
use Revolution\Amazon\ProductAdvertising\AmazonClient;
class AmazonSearch extends AmazonClient {
/**
* {#inheritdoc}
*/
public function alter(...)
...
}
I guess I'm not sure on exactly what I need to do to be able to have this class instantiated like the original and use this new method.
Should I be creating a new service provider that would instantiate the new class? Can the existing one (https://github.com/kawax/laravel-amazon-product-api/blob/master/src/Providers/AmazonProductServiceProvider.php) just be extended?
There's some other answers here but many of them are for older Laravel versions. I'm not sure how to approach it the Laravel 8 way.
And I'm still fuzzy on how Laravel does all this, so thanks for your patience and any assistance you can provide.
EDIT: Well, I just renamed the class to ExtendedAmazonClient and added a facade and it seems to work now.
namespace App\AmazonSearch;
use Illuminate\Support\Facades\Facade;
use Revolution\Amazon\ProductAdvertising\AmazonClient;
class AmazonSearch extends Facade
{
/**
* Get the registered name of the component.
*
* #return string
*/
protected static function getFacadeAccessor()
{
return ExtendedAmazonClient::class;
}
}
trait Alter {
/**
* {#inheritdoc}
*/
public function alter(string $str) {
dd($str);
}
}
class ExtendedAmazonClient extends AmazonClient {
use Alter;
}
Can someone explain to me why the facade was the key?
To answer my own question for anyone else in the future: Facades is another way to use classes without manually creating an object. They are just a shortcut to classes registered by Laravel container.
https://stackoverflow.com/a/48843414/8749507

Why Repository interface bind to service container

We need to use Repository in laravel application. We want create Two important things one is Repository Interface and another one Repository class
My doubt is Why Repository interface and Repository class register to service provider
I removed repository interface and class from service provider
show below error
"Target [App\Repository\UserInterface] is not instantiable while building "
<?php
namespace App\Repository\user;
use Illuminate\Support\ServiceProvider;
class UserRepoServiceProvide extends ServiceProvider
{
/**
* Bootstrap the application services.
*
* #return void
*/
public function boot()
{
}
/**
* Register the application services.
*
* #return void
*/
public function register()
{
// $this->app->bind('App\Repository\UserInterface', 'App\Repository\user\UserRepository');
}
}
An Interface class is just a definition of methods (without their body), hence is not instantiable. That means you can't do a new App\Repository\UserInterface().
Somewhere in your code you have a method (or maybe a constructor?) that takes a UserInterface dependency, something like
public function myMethod(UserInterface $repository) {
...
}
// or
public function __construct(UserInterface $repository) {
...
}
If you remove the binding, Laravel will try to instantiate an UserInterface and that will result in the error you get.
When working with interfaces you have always to bind() them with concrete classes.
I have a question, why did you remove the binding from ServiceProvider?

Get loop globally in laravel

I have setting options which has controller and I need to get some of it's data on header and footer which need to be load globally.
How do I do that?
I've read some questions in this website but none of them helped me as I expected, or I didn't get those! either way I need your help to solve this issue of mine.
Thanks.
there are many ways to do that
but one of them that refer in laravel document is using boot
Sharing Data With All Views
Occasionally, you may need to share a piece of data with all views
that are rendered by your application. You may do so using the view
facade's share method. Typically, you should place calls to share
within a service provider's boot method. You are free to add them to
the AppServiceProvider or generate a separate service provider to
house them:
<?php
namespace App\Providers;
use Illuminate\Support\Facades\View;
class AppServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot()
{
View::share('key', 'value');
}
/**
* Register the service provider.
*
* #return void
*/
public function register()
{
//
}
}
you can share a variable inside boot method of AppServiceProvider.php
for example you have categories table and Category Model and you want to share it to all views
<?php
namespace App\Providers;
use Illuminate\Support\Facades\View;
class AppServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot()
{
$categories = Category::All();
View::share('categories', 'categories');
}
/**
* Register the service provider.
*
* #return void
*/
public function register()
{
//
}
}
but if you want to have header and footer for your site simply you can use master file and extend it to other views
document

Laravel 4.1.* issue registering events in service provider

I am trying to register events with the service provider but I keep getting reflection class error. I have searched and could not find a solution, perhaps this is an issue with the core.
// AppServiceProvider.php
<?php namespace App;
use Illuminate\Support\ServiceProvider;
use App\Events\UserEventHandler;
class AppServiceProvider extends ServiceProvider {
public function register() {
// Events
$this->app->events->subscribe(new UserEventHandler);
}
}
// UserEventHandler.php
<?php namespace App\Events;
class UserEventHandler {
/**
* Handle user login events.
*/
public function onUserLogin($event)
{
echo 'subscriber logged in'; exit;
}
/**
* Register the listeners for the subscriber.
*
* #param Illuminate\Events\Dispatcher $events
* #return array
*/
public function subscribe($events)
{
$events->listen('auth.login', 'UserEventHandler#onUserLogin');
}
}
$this->app->events->subscribe(new UserEventHandler); is firing fine, because I can reach the subscribe method, however $events->listen('auth.login', 'UserEventHandler#onUserLogin'); is returning an exception Class UserEventHandler does not exist
I have tried the same code on global.php and works fine, so the problem lies on the ServiceProvider, I have tried both methods register() and boot() and get the same error.
[UPDATED]
I have found that you need to specifically specify the full namespace when listening for the event.
public function subscribe($events)
{
$events->listen('auth.login', 'App\Events\UserEventHandler#onUserLogin');
}
You need to declare the full path to the class if it is in a different directory to the service provider.

Laravel 4 facade class not calling functions on facade root class

I've set up a package in laravel 4 via the artisan workbench command. I created a facade class and followed this tutorial to come up with the following service provider, facade and root classes:
src/Spoolphiz/Infusionsoft/InfusionsoftServiceProvider.php:
namespace Spoolphiz\Infusionsoft;
use Illuminate\Support\ServiceProvider;
class InfusionsoftServiceProvider extends ServiceProvider {
protected $defer = false;
/**
* Bootstrap the application events.
*
* #return void
*/
public function boot()
{
$this->package('spoolphiz/infusionsoft');
}
/**
* Register the service provider.
*
* #return void
*/
public function register()
{
// Register 'infusionsoft' instance container to our Infusionsoft object
$this->app['infusionsoft'] = $this->app->share(function($app)
{
return new Spoolphiz\Infusionsoft\Infusionsoft;
});
}
/**
* Get the services provided by the provider.
*
* #return array
*/
public function provides()
{
return array();
}
}
src/Spoolphiz/Infusionsoft/Facades/Facade.php:
namespace Spoolphiz\Infusionsoft\Facades;
use Illuminate\Support\Facades\Facade;
class Infusionsoft extends Facade {
/**
* Get the registered name of the component.
*
* #return string
*/
protected static function getFacadeAccessor() { return 'infusionsoft'; }
}
Finally I've set up the underlying class thats to be connected to the facade at src/Spoolphiz/Infusionsoft/Infusionsoft.php:
namespace Spoolphiz\Infusionsoft;
//use Spoolphiz\Infusionsoft\iSDK;
/*
This is hackish and a un-laravel way to handle the requirement of \iSDK but unfortunately the xmlrpc3.0 lib doesn't want to correctly encode values when run with a namespace. Will try to resolve this later.
*/
require_once(__DIR__.'/isdk.php');
class Infusionsoft extends \iSDK {
protected $_app;
/**
* Init the sdk
*
*/
public function __construct( $connectionName )
{
$this->_app = parent::cfgCon($connectionName);
}
public function test()
{
dd('works');
}
}
I set up the service provider and the facade alias of Infusionsoft in app/config/config.php.
When I try running methods belonging to the extended iSDK class against an instance of Spoolphiz\Infusionsoft\Facade\Infusionsoft I get undefined method errors, such as the following:
Call to undefined method Spoolphiz\Infusionsoft\Facades\Infusionsoft::loadCon()
Why is this? The whole point of facades is to be able to call methods against its root class...
Looks like I was being stupid. I was developing this package in the laravel workbench. Once it was done I submitted it to packagist and set up a requirement for it in the same laravel app. Having the package installed in vendors directory and in the workbench caused some sort of conflict.
Lesson learned: make sure you dont have the same package in your workbench and in your application's vendors directory.

Resources