Laravel container returning multiple Singleton instances - php

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));

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'));
});

Automatically Change Model Value If Another Value Updates

With Laravel & Eloquent, if a column called status changes its value to "complete," for example, is it possible to automatically change the value of another column (issue_id) to NULL?
I was wondering about the set attribute or intercepting the save() method, but not sure which is best.
You could make use of Observers.
For example, to observe the Issue model, you could generate an Observer as such:
php artisan make:observer IssueObserver --model=Issue
This will produce an observer where you could listen to many model events.
<?php
namespace App\Observers;
use App\Issue;
class IssueObserver
{
/**
* Handle the Issue "updating" event.
*
* #param \App\Issue $Issue
* #return void
*/
public function updating(Issue $issue)
{
if($issue->status == 'complete') {
$issue->issue_id = null;
}
}
}
To register the Observer, you would need to add this to AppServiceProvider#boot()
<?php
namespace App\Providers;
use App\Issue;
use App\Observers\IssueObserver;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot()
{
Issue::observe(IssueObserver::class);
}
/**
* Register the service provider.
*
* #return void
*/
public function register()
{
//
}
}
You could also just do this in your App/Issue model.
public static function boot()
{
parent::boot();
static::updating(function ($issue) {
if($issue->status == 'complete') {
$issue->issue_id = null;
}
})
}
Obviously, you would need to listen on the events that suit your needs. This is just an example. You could take a look at all the available model events here.

Laravel 5.6 Inject variable with Service Provider in a group of routes

I have a part of site that starts with specific prefix /manage.
Can I somehow like with AppServiceProvider view-composers inject a variable in all routes from that prefix?
I tried to do it by passing this variable to layout of all that routes. But then I met a problem. I use this variable in blade view of specific page, and it returns me variable not defined.
Then, I inspect laravel debugger and saw the order of loading of blade files. And it was :
1. Current page view
2. Layout view
3. Sidebars and other stuff
So, the fact that current page is loaded before layout, cause error of undefined variable.
So, how can I solve that ? Thanks.
Code from my Service provider :
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use App\CT;
class AppServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot()
{
view()->composer(['website.implicare.ct.show', 'website.implicare.ct.petition.index', 'layouts.ct'], function($view) {
$ct = request()->ct;
$permissions = [];
foreach($ct->userPermissions(auth()->id()) as $userPermission) {
if($userPermission->pivot->ct_id == $ct->id) {
array_push($permissions, $userPermission->name);
}
}
$view->with('permissions', $permissions);
});
}
/**
* Register any application services.
*
* #return void
*/
public function register()
{
//
}
}
create ComposerServiceProvider
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class ComposerServiceProvider extends ServiceProvider
{
/**
* Bootstrap the application services.
*
* #return void
*/
public $theme = 'mytheme';
public function boot()
{
view()->composer($this->theme.'.includes.navbar', 'App\Http\ViewComposers\MenuComposer');
view()->composer($this->theme.'.includes.header', 'App\Http\ViewComposers\MenuComposer');
}
/**
* Register the application services.
*
* #return void
*/
public function register()
{
//
}
}

Laravel service provider not binding to contract

i have below contract/interface which is binded by a service provider ,however the i get below error :
ReflectionException in RouteDependencyResolverTrait.php line 81:
Class App\Http\Controllers\RocketShipContract does not exist
What am i doing wrong ?
Contract
namespace App\Contracts\Helpers;
Interface RocketShipContract
{
public function blastOff();
}
The concrete class
namespace app\Contracts;
use App\Contracts\Helpers\RocketShipContract;
class RocketShip implements RocketShipContract
{
public function blastOff()
{
return 'Houston, we have ignition';
}
}
The service provider
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use App\Contracts\RocketShip;
class RocketShipServiceProvider extends ServiceProvider
{
protected $defer = true;
/**
* Bootstrap the application services.
*
* #return void
*/
public function boot()
{
//
}
/**
* Register the application services.
*
* #return void
*/
public function register()
{
$this->app->bind('App\Contracts\Helpers\RocketShipContract', function($app){
return new App\Contracts\RocketShip($app['HttpClient']);
});
}
/**
* Get the services provided by the provider.
*
* #return array
*/
public function provides()
{
return ['App\Contracts\Helpers\RocketShipContract'];
}
}
The controller
public function test(RocketShipContract $rocketship)
{
$boom = $rocketship->blastOff();
return view('test.index', compact('boom'));
}
The error you're getting hints at the problem: the class is being resolved in the App\Http\Controllers namespace. That's because you need to specify the full namespace of your interface in the controller.
So either include it with a use statement:
use App\Contracts\Helpers\RocketShipContract;
Or type hint the full namespace:
public function test(App\Contracts\Helpers\RocketShipContract $rocketship)
{
// ...
}

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