Grouping event registrations on a service provider - laravel

I want to define a service provider that registers events. So have done the following (taken from a book)
<?php
namespace MyApp\Providers;
use Illuminate\Support\ServiceProvider;
class EventsProvider extends ServiceProvider
{
public function boot()
{
Event::listen('some.event', function($parameter)
{
// Handle the event..
});
}
}
Then I added it to the provider array.
But when I execute the code I get the following error
implement the remaining methods
(Illuminate\Support\ServiceProvider::register)
It compels me to declare a register() method.
When I add to the EventsProvider class a method named register() (without implementation, and just make it return null) I get the following error
Class 'MyApp/Providers/EventProvider' not found
Why is that, and how can I solve it?

You just need to declare it, because it's declared in the Interface:
<?php namespace MyApp\Providers;
use Illuminate\Support\ServiceProvider;
class EventsProvider extends ServiceProvider {
public function boot()
{
Event::listen('some.event', function($parameter)
{
// Handle the event..
});
}
public function register()
{
}
}
Then execute
composer dump-autoload --optimize
But you might also have a typo somewhere because it says Class 'MyApp/Providers/EventProviders' not found, but it should be MyApp/Providers/EventProvider.

Related

PHPUnit tests failing after adding a ViewServiceProvider for sharing data to views

I am relatively new to testing so please forgive me if this a stupid question.
All my tests are failing after I added a ViewServiceProvider to share data with the views.
The error is:
Illuminate\Database\QueryException : SQLSTATE[HY000]: General error: 1 no such table: policies (SQL: select "name", "slug" from "policies")
My tests are making use the the refresh database trait:
namespace Tests\Feature;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class ExampleTest extends TestCase
{
use RefreshDatabase;
...
}
Here is an example of the ViewServiceProvider:
namespace App\Providers;
use App\Models\Policy;
use Illuminate\Support\ServiceProvider;
class ViewServiceProvider extends ServiceProvider
{
public function register(): void{...}
public function boot(): void
{
view()->share('policies', Policy::all(['name', 'slug']));
}
}
Every works when browsing the site on front end. Am i missing something? Why are the tests failing?
I will appreciate suggestions on how to make the tests pass.
Edit
It makes total sense what #Donkarnash said but it's also confusing because according to the docs:
So, what if we need to register a view composer within our service provider? This should be done within the boot method. This method is called after all other service providers have been registered, meaning you have access to all other services that have been registered by the framework
See https://laravel.com/docs/8.x/providers#the-boot-method
I found the solution. Creating a view composer solved the problem.
namespace App\Http\View\Composers;
use App\Models\Policy;
use Illuminate\View\View;
class PolicyComposer
{
public function compose(View $view): void
{
$view->with('policies', Policy::all(['name', 'slug']));
}
}
Then I referenced the composer in the ViewServiceProvider
namespace App\Providers;
use App\Models\Policy;
use Illuminate\Support\ServiceProvider;
class ViewServiceProvider extends ServiceProvider
{
public function register(): void{...}
public function boot(): void
{
view()->composer('*', PolicyComposer::class);
}
}

How do I do the type-hint 'automatic injection' custom class 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.

Dependency resolving with App::make not working when bind is done by a provider in Laravel

I'm using Laravel 5.2. I tried to resolve a dependency in Laravel out of the IOCContainer as follows.(with App::make method)
App/FooController.php:-
<?php
namespace App\Http\Controllers;
use App\Bind\FooInterface;
use Illuminate\Support\Facades\App;
class FooController extends Controller
{
public function outOfContainer(){
dd(App::make('\App\bind\FooInterface')); // Focus: program dies here!!
}
}
Bindings for the FooInterface done in the AppServiceProvider as follows
App/Providers/AppServiceProvider.php:-
<?php
namespace App\Providers;
use App\Bind\Foo;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->bind('\App\Bind\FooInterface', function() {
return new Foo();
});
}
}
Structure of the Foo class as follows.
App/Bind/Foo.php:-
<?php
namespace App\Bind;
class Foo implements FooInterface {
}
Structure of the FooInterface interface as follows:-
<?php
namespace App\Bind;
interface FooInterface {
}
Then I created a route as follows.
Route::get('/outofcontainer', 'FooController#outOfContainer');
But when I navigate to this route it throws an exception with the error text:
BindingResolutionException in Container.php line 748:
Target [App\bind\FooInterface] is not instantiable.
What is going wrong with this?
How to use App:make() with the AppServiceProvider?
In your service provider, you're binding the string '\App\Bind\FooInterface'. In your controller, you're attempting to make the string '\App\bind\FooInterface'. These strings are not the same, as they have differing cases (Bind vs bind). Since the strings are not the same, Laravel cannot find the binding in the container.
Correct the casing in your make statement and it should work:
dd(App::make('\App\Bind\FooInterface'));

Laravel IoC doesn't automatically resolving the interface

I've just crossed this example, but it fails to resolve binding interface to implementation.
Having the follow code files:
// File: app/App/Services/Talkable.php
<?php
namespace App\Services;
interface Talkable {
public function talk();
}
// File: app/App/Services/Cat.php
<?php
namespace App\Services;
use App\Services\Talkable;
class Cat implements Talkable
{
public function talk()
{
return 'meow meow';
}
}
// File: app/Jobs/MakeSomeNoise.php
<?php
namespace App\Jobs;
use App\Jobs\Job;
use App\Services\Talkable;
class MakeSomeNoise extends Job
{
private $talkable;
public function __construct(Talkable $talkable)
{
$this->talkable = $talkable;
}
public function handle()
{
return ($this->talkable->talk());
}
}
The binding are taken place in app/Providers/AppServiceProvider.php
// File: app/Providers/AppServiceProvider.php
...
$this->app->bind('App\\Services\\Talkable', 'App\\Services\\Cat');
The MakeSomeNoise job is dispatched from a Controller
// File: any controller
public function makeNoises()
{
return $this->dispatch(new MakeSomeNoise); // (*)
}
At the (*), I expect Laravel will automatically resolve the binding, but it doesn't. Here the error,
Argument 1 passed to App\Jobs\MakeSomeNoise::__construct() must be an instance of App\Services\Talkable, none given, called in ...
But if I just inject into controller constructor, it works fine.
Any thought on this?
My mistake in the code. The DI should be taken in handle() method, not constructor.
public function handle(Talkable $talkable) {
// blah lbah
}

Laravel 4 interface file error: "syntax error, unexpected 'interface' (T_INTERFACE)"

When trying to do any actions that invoke my Repo class, I get the following error on the child Repo interface:
"syntax error, unexpected 'interface' (T_INTERFACE)"
Here is the code for the Repo class, and the child repo interface file that is the source of the error:
<?php namespace MyProj\Repository\Parent;
use MyProj\Parent;
use MyProj\Parent\ChildRsrc as ChildRsrc;
class EloquentParentRepo implements ParentRepoIfc
{
public $childRepo;
public function __construct(ChildRsrcRepoIfc $childRepo)
{
$this->childRepo = $childRepo;
}
// ...
}
and the child repo interface file:
<?php namespace MyProj\Repository\Parent;
interface ChildRscrRepoIfc // the error info points to this line
{
public function all();
public function create($input);
public function delete($id);
public function find($id);
}
It all is structured just like other code in the project that works fine. The ChildRsrcRepoIfc and its concrete implementation (EloquentChildRscrRepo) are in the same Parent namespace as everything else referenced here. I've triple-checked all spelling for typos. Any help is appreciated, as always.
Update: I tried removing the DI in the parent class and using direct instantiation but still got the same error:
class EloquentParentRepo implements ParentRepoIfc
{
public function __construct()
{
$this->childRepo = new ChildRsrcRepoIfc;
//...
And I double checked that I am doing the binding in the Repo Svc Provider as follows:
class RepositoryServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->singleton(
'MyProj\Repository\Parent\ChildRsrcRepoIfc',
'MyProj\Repository\Parent\EloquentChildRsrcRepo'
);
Shouldn't this be?:
class RepositoryServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->singleton(
'MyProj\Repository\Parent\ChildRsrcRepoIfc',
'MyProj\Repository\Parent\EloquentParentRepo '
);
Something that happened to me once while using Laravel IoC automatic resolution was writing
<?
Instead of
<?php
Laravel cannot find the file if you do this. Check your files.

Resources