Lumen Dependency Injection - php

As the last comment of this post it states the following:
You can easily do it in any service provider (boot would be a nice place since we can use method based DI).
public function boot(\Illuminate\Contracts\Http\Kernel $kernel) {
$kernel->appendMiddleware('Sheepy85\L5Localization\Middleware\Localization'); // prependMiddleware works too.
}
This is Laravel Code for injecting a middleware from a Service Provider.
I am trying to achieve the same thing from Lumen Framework, here's the code:
<?php namespace Acme\Slz\Providers;
use Illuminate\Contracts\Http\Kernel;
use Illuminate\Support\ServiceProvider;
class SlzServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
* #param Kernel $kernel
* #return void
*/
public function boot(Kernel $kernel)
{
// push the serializer middleware to the stack
$kernel->pushMiddleware(Acme\Slz\Middleware\Serializer::class);
}
/**
* Register any application services.
* This service provider is a great spot to register your various container
* bindings with the application. As you can see, we are registering our
* #return void
*/
public function register()
{
}
}
But this raise the following error:
lumen.ERROR: exception 'ErrorException' with message 'Argument 1 passed to Acme\Slz\Providers\SlzServiceProvider::boot() must be an instance of Illuminate\Contracts\Http\Kernel, none given
Are there some more stuffs to do to enable the Dependency Container with Lumen ?

How about this:
<?php namespace Acme\Slz\Providers;
use Illuminate\Support\ServiceProvider;
class SlzServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot()
{
// push the serializer middleware to the stack
$this->app->middleware([
'serializer' => 'Acme\Slz\Middleware\Serializer',
]);
}
}

Related

Implementation of Yasumi in Laravel 9

There is a posting from 2016 that describes how to implement Yasumi:
https://www.yasumi.dev/
into Laravel. But this looks like it completely outdated now. What is the correct way to implement it into Laravel 9?
Post I am referencing from 2016:
https://stackoverflow.com/a/41266340/8207054
I am using this code (AppServiceProvider):
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Carbon\Carbon;
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*
* #return void
*/
public function register()
{
$this->app->singleton('yasumi', \Yasumi\Yasumi::create('USA', Carbon::now()->format('Y')));
}
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot()
{
//
}
}
but it causes this error: Illuminate\Container\Container::bind(): Argument #2 ($concrete) must be of type Closure|string|null
You can send function as the second parameter to singleton method like this:
$this->app->singleton('yasumi', function () {
return \Yasumi\Yasumi::create('USA', Carbon::now()->format('Y'));
});

Laravel container returning multiple Singleton instances

I've created a CustomProvider, added it to the app.php array of providers and registered a class as singleton:
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use App\ReserveCart;
class CustomProvider extends ServiceProvider
{
/**
* Bootstrap services.
*
* #return void
*/
public function boot()
{
//
}
/**
* Register services.
*
* #return void
*/
public function register()
{
$this->app->singleton('App\ReserveCart', function($app){
return new ReserveCart;
});
}
}
but everytime I request for the object with $rc = resolve('App\ReserveCart'); it keeps giving me different instances of the object instead of a single one (I've done some echo tracking).
Also tried passing the dependency to methods acording to Laravel Documentation. e.g
public function foo(App\ReserveCart $rc){
//
}
but the issue persists.
Is the output below same ?
$rc = resolve('App\ReserveCart');
$rc1 = resolve('App\ReserveCart');
dd(spl_object_hash($rc), spl_object_hash($rc1));

View composer not working properly in testing mode in Laravel 5.2

I've a view composer written like this
view()->composer('masterbox.partials.pipeline', function($view) {
// Some vars and code
});
In one of my view I do as follow
#include('masterbox.partials.pipeline', ['my_var' => 1])
When i'm trying it on my browser everything is fine, but when I run a simple test everything blows up ... After some debugging I found out the closure wasn't executed at all.
$this->visit('/connect/customer/subscribe')
->type($faker->firstName, 'first_name')
->type($faker->firstName, 'first_name')
->type($faker->lastName, 'last_name')
->type($faker->email, 'email')
->type($faker->phoneNumber, 'phone')
->type($password, 'password')
->type($password, 'password_confirmation')
->press("S'inscrire");
Note : It visits a page, fills the form and subscribe, then it redirects on the page with the #include and it returns a big error, part of it is
exception 'ErrorException' with message 'Undefined variable: my_var' in /Users/Loschcode/Google Drive/projects/my_project_lo/website/storage/framework/views/7e11f284c02bc38adc60b5f8a0545df65d7cf5ec.php:7
I'm afraid it an issue, it's a fresh Laravel 5.2 I downloaded a few days ago. Any guess ? Any method to debug this ? Thanks
Working solution
I ended up trying anything. My problem was my service provider organization.
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class ComposerServiceProvider extends ServiceProvider
{
/**
* Bootstrap the application services.
*
* #return void
*/
public function boot()
{
foreach (glob(app_path().'/Http/ViewComposers/*.php') as $filename){
require_once($filename);
}
}
/**
* Register the application services.
*
* #return void
*/
public function register()
{
//
}
}
If you have a similar organization and problem, replace the require_once by a simple require and everything will go fine.
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class ComposerServiceProvider extends ServiceProvider
{
/**
* Bootstrap the application services.
*
* #return void
*/
public function boot()
{
foreach (glob(app_path().'/Http/ViewComposers/*.php') as $filename){
require($filename);
}
}
/**
* Register the application services.
*
* #return void
*/
public function register()
{
//
}
}

Not undestanding how to make a custom auth driver. Ultimately will need SOAP.

I am quite new to Laravel and I really need some help. I need to create a simple app for my job, and I think I will not have problem with this as the tutorials here are really excellent.
The issue I have is that for that project I need to authenticate the users against an external DB using a SOAP webservice and if the user does not exist in the local DB I create it and log the user in. I am able to manage this part as I have already written a Joomla plugin that does that.
I have tried to figure out the documentation on how to create a custom driver. http://laravel.com/docs/5.1/authentication I thought that at first I would replicate the EloquentUserProvider befor modifying it, thus I created:
ErsAuthServiceProvider and ErsUserProvider respectively placed in App\Providers and App\Extensions
But it mysteriously does not work... I get the following error:
ErrorException in ErsUserProvider.php line 33: Argument 1 passed to App\Extensions\ErsUserProvider::__construct() must be an instance of Illuminate\Contracts\Hashing\Hasher, none given, called in /home/vagrant/Code/ERSTools/app/Providers/ErsAuthServiceProvider.php on line 31 and defined
Actually I do not understand much in the documentation what they are doing with the boot() method in the example. I understand that they extend The Auth class in order to add the new driver (ers in my case) but I do not get why they pass the $app['riak.connection']
<?php
namespace App\Providers;
use Auth;
use App\Extensions\ErsUserProvider;
use Illuminate\Contracts\Auth\Access\Gate as GateContract;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
class ErsAuthServiceProvider extends ServiceProvider
{
protected $policies = [
'App\Model' => 'App\Policies\ModelPolicy',
];
/**
* Register any application authentication / authorization services.
*
* #param \Illuminate\Contracts\Auth\Access\Gate $gate
* #return void
*/
public function boot(GateContract $gate)
{
parent::registerPolicies($gate);
Auth::extend('ers', function($app) {
// Return an instance of Illuminate\Contracts\Auth\UserProvider...
return new ErsUserProvider;
});
//
}
/**
* Register the application services.
*
* #return void
*/
public function register()
{
//
}
}
and
<?php
namespace App\Extensions;
use Illuminate\Support\Str;
use Illuminate\Contracts\Auth\UserProvider;
use Illuminate\Contracts\Hashing\Hasher as HasherContract;
use Illuminate\Contracts\Auth\Authenticatable as UserContract;
class ErsUserProvider implements UserProvider
{
/**
* The hasher implementation.
*
* #var \Illuminate\Contracts\Hashing\Hasher
*/
protected $hasher;
/**
* The Eloquent user model.
*
* #var string
*/
protected $model;
/**
* Create a new database user provider.
*
* #param \Illuminate\Contracts\Hashing\Hasher $hasher
* #param string $model
* #return void
*/
public function __construct(HasherContract $hasher, $model)
{
$this->model = $model;
$this->hasher = $hasher;
}
... the rest is similar to the original file (EloquentUserProvider)
Finally, my plan is to keep the ErsUserprovider quite similar to the EloquentUserProvider and to implement my check with the webservice in the validateCredentials() method as in this method I shoul know if a user exists with the requested username in the local DB, I will know if the user passes validation with the SOAP webservice I can then
Login the user
Login the user and create a new user based on the date returned by the webservice
refuse the login.
Is this a good plan?
I sweated but I made the first part work. The issue was within the boot method.My custom provider is a working replica of the original laravel 5.1 I can now customize it.
Here is the Service provider that works:
<?php
namespace App\Providers;
use App\Extensions\ErsUserProvider;
use Illuminate\Support\ServiceProvider;
use Illuminate\Contracts\Auth\UserProvider;
class ErsAuthServiceProvider extends ServiceProvider
{
/**
* Bootstrap the application services.
*
* #return void
*/
public function boot()
{
$this->app['auth']->extend('ers',function($app)
{
$model = $app['config']['auth.model'];
return new ErsUserProvider($app['hash'], $model);
});
}
/**
* Register the application services.
*
* #return void
*/
public function register()
{
//
}
}

PHP - Laravel dependency injection: pass parameters to dependency constructor

I'm building a Laravel project and in one of the controllers I'm injecting two dependencies in a method:
public function pusherAuth(Request $request, ChannelAuth $channelAuth) { ... }
My question is really simple: How do I pass parameters to the $channelAuth dependency?
At the moment I'm using some setters to pass the needed dependencies:
public function pusherAuth(Request $request, ChannelAuth $channelAuth)
{
$channelAuth
->setChannel($request->input('channel'))
->setUser(Auth::user());
What are the alternatives to this approach?
P.S. The code needs to be testable.
Thanks to the help I received on this Laracast discussion I was able to answer this question. Using a service provider it's possible to initialize the dependency by passing the right parameters to the constructor. This is the service provider I created:
<?php namespace App\Providers;
use Security\ChannelAuth;
use Illuminate\Contracts\Auth\Guard;
use Illuminate\Http\Request;
use Illuminate\Support\ServiceProvider;
class ChannelAuthServiceProvider extends ServiceProvider {
/**
* Bootstrap the application services.
*
* #return void
*/
public function boot()
{
//
}
/**
* Register the application services.
*
* #return void
*/
public function register()
{
$this->app->bind('Bloom\Security\ChannelAuthInterface', function()
{
$request = $this->app->make(Request::class);
$guard = $this->app->make(Guard::class);
return new ChannelAuth($request->input('channel_name'), $guard->user());
});
}
}
You can pass parameters (as a string indexed array) when resolving a dependence like this:
<?php namespace App\Providers;
use Security\ChannelAuth;
use Illuminate\Contracts\Auth\Guard;
use Illuminate\Support\ServiceProvider;
class ChannelAuthServiceProvider extends ServiceProvider {
/**
* Bootstrap the application services.
*
* #return void
*/
public function boot()
{
//
}
/**
* Register the application services.
*
* #return void
*/
public function register()
{
$this->app->bind('Bloom\Security\ChannelAuthInterface', function($params)
{
$channelName = $params['channelName'];
$guard = $this->app->make(Guard::class);
return new ChannelAuth($channelName, $guard->user());
});
}
}
Then when resolving eg in a controller:
public function pusherAuth()
{
$channelAuth = app()->makeWith('Bloom\Security\ChannelAuthInterface', [
'channelName' => $request->input('channel_name')
]);
// ... use $channelAuth ...
}
You can create and register your own service provider and create object with constructor's requests parameters.
I don't know how to do this in Laravel, but in Symfony2 you can inject in your own service something like RequestStack. It's the best way, because you have small service providers that are fully testable.

Categories