I am looking into observers and I found out that instead of calling an observer during the boot() method of the App\Providers\EventServiceProvider laravel can call it using the property protected $observers.
It works perfectly fine when calling it in the boot method, but it does not work when I put it in the property.
What am I doing wrong? I could not find any other explanation in the documentation.
My eventServiceProvider:
class EventServiceProvider extends ServiceProvider
{
/**
* Summary of Observers
* #var mixed
*/
protected $observers = [
User::class => [UserObserver::class],
];
/**
* Register any events for your application.
*
* #return void
*/
public function boot()
{
//User::observe(UserObserver::class);
//Above line is commented because property $observers is used, but uncommented when property observers is commented.
}
My observer:
class UserObserver
{
/**
* Handle the User "updated" event.
*
* #param \App\Models\User $user
* #return void
*/
public function updated(User $user)
{
$dirty = $user->getChanges();
dump($user);
dd($dirty);
}
}
Related
I have an issue while trying to use an observer that it doesn't fire the observer only in the updated case. it works fine in other cases !.
I had some research about it and I found some solutions, such as calling the update method directly from the model, not in a repository, but unfortunately, it didn't work for me.
the solution I found: https://github.com/laravel/framework/issues/11777#issuecomment-170388067
UserObserver
class UserObserver
{
/**
* Handle the user "created" event.
*
* #param \App\Models\User $user
* #return void
*/
public function created(User $user)
{
dd($user);
}
/**
* Handle the user "updated" event.
*
* #param \App\Models\User $user
* #return void
*/
public function updated(User $user)
{
dd($user);
}
/**
* Handle the user "deleted" event.
*
* #param \App\Models\User $user
* #return void
*/
public function deleted(User $user)
{
dd($user);
}
}
and here's my AppServiceProvider:
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*
* #return void
*/
public function register()
{
}
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot()
{
User::observe(UserObserver::class);
}
}
I called the update method in my controller like this:
// First try
$user = User::findOrFail($id);
$user->update($data);
// Second try
User::findOrFail($id)->update($data);
this an example of my $data array:
array [
"nationality_id" => "1"
"birth_date" => "2013-05-26"
"gender" => "1"
"job_title" => "Pariatur Sit provideeee"
"salary" => "5100"
]
Laravel checks if the model has actually been changed before firing updates, so make sure you change the model before saving or updating it.
Additionally, updating events are only fired when you update your model directly.
That means this will fire an event:
$user = User::findOrFail($id);
$user->update($data);
While something like this will not
User::where('id', $id)->update($data);
This is done by design, since using an update query could update millions of rows at once, making it unrealistic to fire events for all of them.
I am just starting to get the hang of Service Providers and the IoC container, however one thing is confusing me. I have a SpamServiceProvider that requires two other classes to function. However one of those classes, InvalidKeywords, has a array $blacklist parameter which needs to be passed to its constructor.
If I register that class in the AppServiceProvider and pass in the $blacklist array, everything works fine. However, if I try to bind the class in the SpamServiceProvider instead it will not inject the $blacklist into InvalidKeywords constructor.
So I guess my question is why is this? And is there a way to keep bindings like this together in a single container or do I simply have to bind InvalidKeywords inside the AppServiceProvider?
This works
class SpamServiceProvider extends ServiceProvider
{
/**
* Indicates if loading of the provider is deferred.
*
* #var bool
*/
protected $defer = true;
/**
* Bootstrap services.
*
* #return void
*/
public function boot()
{
//
}
/**
* Register services.
*
* #return void
*/
public function register()
{
$this->app->bind(SpamManager::class, function ($app) {
return new SpamManager(new InvalidKeywords, new RepeatedCharacters);
});
}
}
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*
* #return void
*/
public function register()
{
$this->app->bind(InvalidKeywords::class, function ($app) {
return new InvalidKeywords(config('spam.blacklist'));
});
}
}
This does not work
class SpamServiceProvider extends ServiceProvider
{
/**
* Indicates if loading of the provider is deferred.
*
* #var bool
*/
protected $defer = true;
/**
* Bootstrap services.
*
* #return void
*/
public function boot()
{
//
}
/**
* Register services.
*
* #return void
*/
public function register()
{
$this->app->bind(InvalidKeywords::class, function ($app) {
return new InvalidKeywords(config('spam.blacklist'));
});
$this->app->bind(SpamManager::class, function ($app) {
return new SpamManager(new InvalidKeywords, new RepeatedCharacters);
});
}
}
In the second case you're not resolving the InvalidKeywords class from the container, simply creating a new instance. Instead, try using app or resolve helpers when creating the SpamManager:
$this->app->bind(SpamManager::class, function ($app) {
return new SpamManager(resolve(InvalidKeywords::class), resolve(RepeatedCharacters::class));
});
// or
$this->app->bind(SpamManager::class, function ($app) {
return new SpamManager(app(InvalidKeywords::class), app(RepeatedCharacters::class));
});
I would create a singleton with InvalidKeywords as well:
$this->app->singleton(InvalidKeywords::class, function ($app) {
return new InvalidKeywords(config('spam.blacklist'));
});
I am using Laravel 5.2 and wrote my own Service Provider. I want to inject a Request object into the register method.
The base problem is that I want to call different service container depending on a special request param - all the service container implementing the same interface/contract of course.
The error message I am getting is:
ReflectionException in Container.php line 559:
Function registerService() does not exist
My service provider looks like that:
<?php
namespace App\Providers;
use Illuminate\Http\Request;
use Illuminate\Support\ServiceProvider;
use App\Contracts\Extractor;
class ExtractorServiceProvider extends ServiceProvider
{
/**
* Indicates if loading of the provider is deferred.
*
* #var bool
*/
protected $defer = true;
/**
* Available services for channels
*
* #var array
*/
protected $availableServices = ['AExtractor', 'ZExtractor'];
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot()
{
//
}
/**
* Register any application services.
*
* #return void
*/
public function register()
{
$this->app->call('registerService');
}
/**
* #param Request $request
* #return void
*/
protected function registerService(Request $request)
{
$tag = DB::table('channels')->where('id', $request->channel)->value('tag')->first()->tag;
$selectedExtractor = $tag . 'Extractor';
$extractor = 'AExtractor';
if(in_array($selectedExtractor, $this->availableServices)) {
$extractor = $selectedExtractor;
}
$this->app->bind('App\Contracts\Extractor', "App\\Helpers\\{$extractor}");
}
/**
* Get the services provided by the provider.
*
* #return array
*/
public function provides()
{
return [Extractor::class];
}
}
How can I use $this->app->call('registerService'); to call my registerService function and inject the Request object?
The problem is you're calling App:call in a wrong way: you have to specify the object on which you want to call the method and the method, like this :
$this->app->call( [ $this, 'registerService' ] );
Maybe someone can tell me how to use something like embedded controllers in symfony2, to call\render controller action in Laravel4,5?
Found the best way for me, for L5:
CartServerProvider
use Illuminate\Support\ServiceProvider;
class CartServiceProvider extends ServiceProvider {
/**
* Register the service provider.
*
* #return void
*/
public function register()
{
$this->app->make('view')->composer('layouts.master', 'Vendor\Cart\Http\ViewComposers\CartComposer');
}
}
The CartComposer class looks like this:
use Illuminate\Contracts\View\View;
class CartComposer {
/**
* Cart manager instance.
*
* #var \Vendor\Cart\StoreInterface
*/
protected $cart;
/**
* Create a new CartComposer instance.
*/
public function __construct()
{
$this->cart = app()->make('cart.store');
}
/**
* Compose the view.
*
* #return void
*/
public function compose(View $view)
{
$view->with('cart', $this->cart);
}
}
cart.store is a custom cart implementation I injected into the container, but the above should be enough to show you how to register a simple view composer.
So I am working on a page in Laravel that generates invite codes upon email submission. I have run into this issue, every time when I enter my email into the form, it is supposed to generate an invite code an input it into my DB then redirect me. Instead I get this error code:
Argument 1 passed to myapp\Repositories\Invite\EloquentInviteRepository::__construct()
must be an instance of Illuminate\Database\Eloquent\Model, instance of
Illuminate\Foundation\Application given, called in /var/www/laravel/bootstrap/compiled.php
on line 4259 and defined
This is my EloquentInviteRepository.php file, apparently line 21 is the line in error:
<?php namespace myapp\Repositories\Invite;
use myapp\Repositories\Crudable;
use Illuminate\Support\MessageBag;
use myapp\Repositories\Repository;
use Illuminate\Database\Eloquent\Model;
use myapp\Repositories\AbstractRepository;
class EloquentInviteRepository extends AbstractRepository implements Repository, Crudable, InviteRepository {
/**
* #var Illuminate\Database\Eloquent\Model
*/
protected $model;
/**
* Construct
*
* #param Illuminate\Database\Eloquent\Model $user
*/
public function __construct(Model $model)
{
parent::__construct(new MessageBag);
$this->model = $model;
}
/**
* Find a valid invite by a code
*
* #param string $code
* #return Illuminate\Database\Eloquent\Model
*/
public function getValidInviteByCode($code)
{
return $this->model->where('code', '=', $code)
->where('claimed_at', '=', null)
->first();
}
/**
* Create
*
* #param array $data
* #return Illuminate\Database\Eloquent\Model
*/
public function create(array $data)
{
$data['code'] = bin2hex(openssl_random_pseudo_bytes(16));
return $this->model->create($data);
}
/**
* Update
*
* #param array $data
* #return Illuminate\Database\Eloquent\Model
*/
public function update(array $data){}
/**
* Delete
*
* #param int $id
* #return boolean
*/
public function delete($id){}
}
In case anyone was curious; the __construct() interface from Illuminate\Database\Eloquent\Model.php:
/**
* Create a new Eloquent model instance.
*
* #param array $attributes
* #return void
*/
public function __construct(array $attributes = array())
{
$this->bootIfNotBooted();
$this->syncOriginal();
$this->fill($attributes);
}
and Illuminate\Foundation\Application.php:
/**
* Create a new Illuminate application instance.
*
* #param \Illuminate\Http\Request $request
* #return void
*/
public function __construct(Request $request = null)
{
$this->registerBaseBindings($request ?: $this->createNewRequest());
$this->registerBaseServiceProviders();
$this->registerBaseMiddlewares();
}
In case these help in debugging the issue!
As per request I have included my controller element used during the post function, this is the part that seems to activate the repository and prompt the error:
<?php
use myapp\Repositories\Invite\InviteRepository;
class InviteController extends BaseController {
/**
* InviteRepository
*
* #var myapp\Repositories\Invite\InviteRepository
*/
protected $repository;
/**
* Create a new instance of the InviteController
*
* #param myapp\Repositories\Invite\InviteRepository
*/
public function __construct(InviteRepository $repository)
{
$this->repository = $repository;
}
/**
* Create a new invite
*
* #return Response
*/
public function store()
{
$invite = $this->repository->create(Input::all());
}
}
RepositoryServiceProvider.php
<?php namespace myapp\Repositories;
use Illuminate\Support\ServiceProvider;
class RepositoryServiceProvider extends ServiceProvider {
/**
* Register
*/
public function register()
{
$this->registerInviteRepository();
}
/**
* Register the Invite Repository
*
* #return void
*/
public function registerInviteRepository()
{
$this->app->bind('myapp\Repositories\Invite\InviteRepository', function($app)
{
return new EloquentInviteRepository( new Invite );
});
}
}
Any idea's as to what I am missing?
Thanks for the help guys,
You've been a great resource so far!
In the file RepositoryServiceProvider.php, replace this
$this->app->bind('myapp\Repositories\Invite\InviteRepository', function($app)
{
return new EloquentInviteRepository( new Invite );
});
With this:
$this->app->bind('myapp\Repositories\Invite\InviteRepository',
'myapp\Repositories\Invite\EloquentInviteRepository');