Laravel 4 service provider instance - php

I am trying do to facade with laravel 4. I am using service provider. In the service provider register I make singleton instance but I want to access it through interface. It is working I just do not know how to access the interface with the reference to that object. My code is bellow:
class AuthenticationServiceProvider extends ServiceProvider
{
public function register()
{
\App::singleton('Auth\iAuthenticate', function()
{
return new DbAuthentication();
});
}
}
And then if I write this in another php class:
Auth\iAuthenticate::someMethod()
It returns that I cannot call abstract methods which doesn't supprise me. How can I access instance that was created within service provider?

You can use $instance = App::make('Auth\iAuthenticate');
It's also suggested to use the this->app property. It might save you from some headaches in the future.
public function register()
{
$this->app->singleton('Auth\iAuthenticate', function()
{
return new DbAuthentication();
});
}

Related

How to implement Depedency Injection correctly when injected service has required constructor argument

I am using Laravel Lumen (v8.2.4) with PHP (v7.4)
I have the following controller class:
<?php
namespace App\Http\Controllers;
use App\Services\MyService;
class MyController extends Controller
{
protected $myService;
public function __construct(MyService $myService)
{
$this->myService = $myService;
}
}
And the following service class:
<?php
namespace App\Services;
class MyService
{
private $credentials;
function __construct($credentials)
{
$this->credentials = $credentials;
}
}
The myService class requires the credentials property to be set in order to function correctly. When myService is being injected into my controller class, I don't have the credentials at that time so therefore cannot initialise the service class to inject it.
How can I handle this? Should I remove the service class constructor and set the credentials property in a public setter method and invoke this when I need to? I am not sure if this is a good approach.
Appreciate any advice.
You need to register your service in service provider. You can do it in AppServiceProvider or in custom provider.
//retrieve credentials from wherever you need to get them, ex: config file
$credentials = config('app.credentialts');
$this->app->bind(MyService::class, function ($app) use ($credentials) {
return new MyService($credentials);
});
Check out Laravel Service Providers and Laravel Service Containers for more detailed information.

Laravel Own ServiceProvider Client Call Type error: Argument 1 passed to ... must be an instance of

I want to swap out my client call or better i try to make a wrapper around this package, so i dont have to write this everytime, so i made a new ServiceProvider which should call
// Create a new client,
// so i dont have to type this in every Method
$client = new ShopwareClient('url', 'user', 'api_key');
on every request i make.
// Later after the Client is called i can make a Request
return $client->getArticleQuery()->findAll();
SwapiServiceProvider
<?php
namespace Chris\Swapi;
use Illuminate\Support\ServiceProvider;
use LeadCommerce\Shopware\SDK\ShopwareClient;
class SwapiServiceProvider extends ServiceProvider
{
/**
* Perform post-registration booting of services.
*
* #return void
*/
public function boot()
{
}
/**
* Register any package services.
*
* #return void
*/
public function register()
{
$this->app->singleton(ShopwareClient::class, function () {
return new ShopwareClient(
env('SHOPWARE_URL'),
env('SHOPWARE_USER'),
env('SHOPWARE_KEY')
);
});
}
}
My Class
...
use LeadCommerce\Shopware\SDK\ShopwareClient as Shopware;
class Swapi
{
public function fetchAllArticles(Shopware $shopware)
{
return $shopware->getArticleQuery()->findAll();
}
}
Testing
I just call it in my routes.php for testing
use Chris\Swapi\Swapi;
Route::get('swapi', function () {
// Since this is a package i also made the Facade
return Swapi::fetchAllArticles();
});
But i get everytime the error
FatalThrowableError in Swapi.php line 18: Type error: Argument 1
passed to Chris\Swapi\Swapi::fetchAllArticles() must be an instance of
LeadCommerce\Shopware\SDK\ShopwareClient, none given, called in
/Users/chris/Desktop/code/swapi/app/Http/routes.php on line 7
So i am asking why this
return new ShopwareClient(
env('SHOPWARE_URL'),
env('SHOPWARE_USER'),
env('SHOPWARE_KEY')
);
is not called everytime i call a method e.g $shopware->getArticleQuery()->findAll();
Does anyone know why?
I think there might be some confusion here about Laravel's IoC. When you use return Swapi::fetchAllArticles();, Laravel doesn't know what you are doing because you haven't used the container to build out the Swapi class (even though you have registered one with the container) nor do you have a facade built to access it in that manner. Otherwise PHP is going to complain because your function isn't static.
I just wrote this code and verified that it works as far as Laravel putting it all together.
In my service provider, my register function was this...
public function register()
{
$this->app->singleton('swapi', function($app) {
return new SwapiRepository(
new ShopwareClient(
env('SHOPWARE_URL'),
env('SHOPWARE_USER'),
env('SHOPWARE_KEY')
)
);
});
}
Keep in mind, swapi is really just a key the container will use to find the actual class. There's no need to pass in the entire qualified class name when you can keep it simple and easy.
My SwapiRepository which is really the wrapper for the Shopware SDK.
use LeadCommerce\Shopware\SDK\ShopwareClient;
class SwapiRepository
{
protected $client;
public function __construct(ShopwareClient $client)
{
$this->client = $client;
}
public function fetchAllArticles()
{
return $this->client->getArticleQuery()->findAll();
}
}
At this point, you are basically done. Just add App\Providers\SwapiServiceProvider::class, in the providers array (which you probably have done already) in app/config.php and use your wrapper like so...
$swapi = app('swapi');
$swapi->fetchAllArticles();
Or you can have Laravel inject it into other classes as long as Laravel is building said class.
If you want to build out a facade for this to save yourself a line of code each time you want to use this or for snytactical sugar...
use Illuminate\Support\Facades\Facade;
class Swapi extends Facade
{
protected static function getFacadeAccessor() { return 'swapi'; }
}
Make sure to update your aliases array in app/config.php so that it contains 'Swapi' => App\Repositories\Swapi::class,
And finally you should be able to use it like so...
Swapi::fetchAllArticles();
Please note your namespaces are different than mine so you may need to replace mine with yours. You should also now be able to easily inject Swapi into other classes and even method injected into your controllers where needed.
Just remember if you do that though, make sure you are grabbing instances of those classes from Laravel's service container using the app() function. If you try to build them out yourself using new SomeClass, then you have the responsibility of injecting any dependencies yourself.

How to use custom Service Providers in Laravel 5.2

I am creating a Laravel app that needs to communicate with a remote (in-house) service via API.
This API needs to be authenticated at least once per session, and after that other calls can work fine.
I think the best way is to use Laravel's service providers to do this, but I'm open to other solutions.
What I would like:
What I would like is a way to have this Service available for use whenever. I don't want to have to put the service in the parameters of a controller's method if I can avoid it. Something like this:
use MyServiceProvider;
class SomeController extends Controller
{
public function someMethod ()
{
MyServiceProvider::method();
}
}
I can post what I've started doing thus far, if needed - but I'd rather focus on doing what I want rather than fixing what I did wrong.
inb4: I did read the docs.
What you're trying to do is create a Facade. Facades are very similar to using dependency injection, except that they can be used globally without specific injection. Docs: https://laravel.com/docs/5.0/facades#creating-facades
In your service provider:
App::bind('foo', function()
{
return new \MyServices\Foo; //returns a concrete class
});
Foo.php
use Illuminate\Support\Facades\Facade;
class Foo extends Facade {
protected static function getFacadeAccessor() { return 'foo'; } //matches binding in SP
}
Now your service provider is available as Foo anywhere, even without explicitly injecting it:
use Foo;
class SomeController extends Controller
{
public function someMethod ()
{
Foo::method(); //creates a Foo object according to App::bind, then calls method();
}
}

Laravel not finding IoC binding in controller

I have a custom class App/Http/Responder, which had a few methods to build a specific JSON response back in my application. I want to test my controller in isolation, so I'm trying to inject my dependencies via the constructor.
My plan was to simply create a service provider, attach bind it to the $app and then, as per the docs, let it be automatically resolved:
public function register()
{
$this->app->bind('responder', function()
{
return new App\Http\Responder($this->app['cache'], $this->app['app'], new JsonResponse, $this->app['config']);
});
}
I then add this to my config/app.php.
Okay, so now my Responder and it's dependancies are bound to the app, as responder.
Now I thought I'd be able to inject Responder into my controller constructor, and Laravel would be able to automatically resolve this from the IoC container:
class AreasController extends BaseController {
protected $responder;
public function __construct(Responder $responder)
{
$this->responder = $responder;
}
However I get Class Responser does not exist.
The only way I can get it working, without using the App::make() Facade, is to inject the app into my controller:
use Illuminate\Foundation\Application as App;
class AreasController extends BaseController {
protected $app;
public function __construct(App $app)
{
$this->app = $app;
}
I can then do $this->app['responder']->method().
Obviously I'm missing something, but I want to keep away from using Facades in my app so I can test.
If you want to type hint classes to be resolved in the IOC container, you should bind the actual class name with namespace:
$this->app->bind('App\Http\Responder', function()
{
return new App\Http\Responder($this->app['cache'], $this->app['app'], new JsonResponse, $this->app['config']);
});
Technically the container would still resolve this class, because it's a concrete class that can be found, but the way you're doing allows to inject other IOC-bound resources, which is a good practice.
Then, when you wish to have this class injected for you, type hint the full path to the class as you normally would:
use App\Http\Responder;
class AreasController extends BaseController {
protected $responder;
public function __construct(Responder $responder)
{
$this->responder = $responder;
}
}
Also, for what it's worth, your error indicates that you misspelled "Responder" as "Responser".

Laravel Use Eloquent model from custom UserServiceProvider

I'm new to Laravel, just toying with it and getting my head back into MVC.
I'm trying to make my own User auth provider (custom password hashing) as a service that implements the UserProviderInterface within Laravel.
Inside app/controllers/Account.php:
public function postCreate() {
Auth::attempt(Input::all());
}
I have my app routing Auth::attempt through my custom provider class, and passing me the Input::all from the form into a retrieveByCredentials method.
Inside app/services/PasswordHash/PasswordHashUserProvider.php:
public function retrieveByCredentials(array $credentials) {
// Why can't I do this?
//Error: PasswordHash/User not found
User::find($credentials['username']);
dd($credentials);
}
I am lost at this point on how to access my User eloquent models from within this service class. I tried namespaces but had no luck.
The boot method on service providers use the service container to inject dependencies. To that end, you should be able to do the following (not using Facades, but I don't use facades that often).
class PasswordHashUserProvider extends ServiceProvider
{
protected $user;
public function boot(User $user)
{
$this->user = $user;
}
}
You can then access user via $this->user
Source: https://laravel.com/docs/master/providers#the-boot-method

Categories