Hooking laravel observer in the controller - php

I have created an observer called OfficeUserObserver and it's registered in my provider as well. I want a situation whereby when a user is attached to an office. A mail is automatically sent.
So my observer looks thus:
class OfficeUserObserver
{
public function __construct()
{
dd('hi');
}
public function created(OfficeUser $officeUser)
{
dd('hi');
}
public function saving(OfficeUser $officeUser)
{
dd('hi');
}
}
My Controller looks thus:
public function assignUsers(MyRequest $request, Office $office)
{
...
$office->users()->syncWithoutDetaching($users);
}
When I however try to attach a user to an office. The process is successful but nothing ever gets dumped(dd()) on my view despite using dd() in my construct. What am I doing wrong please?
Here is the code in my AppServiceProvider
public function boot()
{
OfficeUser::observe(OfficeUserObserver::class);
}

If you want to use UserObserver you should use pivot models for relations.
https://laravel.com/docs/7.x/eloquent-relationships#defining-custom-intermediate-table-models
class UserOffice extends Model {...}
And observers will work for the pivot model, but not for User or Office.
Or use package for relation events:
https://github.com/chelout/laravel-relationship-events
P.S.: Sorry for disinformation in the previous edit.

Related

How to pass parameter to a laravel elequent model's event observer

I have a model in laravel and I want to do something after the first time which an object of my model is created. the simplest way is to add a static boot method inside my model's class like the code below:
class modelName extends Model
{
public static function boot()
{
parent::boot();
self::created(function ($model) {
//the model created for the first time and saved
//do something
//code here
});
}
}
so far so good! the problem is: the ONLY parameter that created method accepts is the model object itself(according to the documentation) :
Each of these methods receives the model as their only argument.
https://laravel.com/docs/5.5/eloquent#events
I need more arguments to work with after model creation. how can I do that?
Or is there any other way to do something while it's guaranteed that the model has been created?
laravel version is 5.5.
You're close. What I would probably do would be to dispatch an event right after you actually create the model in your controller. Something like this.
class WhateverController
{
public function create()
{
$model = Whatever::create($request->all());
$anotherModel = Another::findOrFail($request->another_id);
if (!$model) {
// The model was not created.
return response()->json(null, 500);
}
event(new WhateverEvent($model, $anotherModel));
}
}
I solved the issue using static property in eloquent model class:
class modelName extends Model
{
public static $extraArguments;
public function __construct(array $attributes = [],$data = [])
{
parent::__construct($attributes);
self::$extraArguments = $data ;
public static function boot()
{
parent::boot();
self::created(function ($model) {
//the model created for the first time and saved
//do something
//code here
self::$extraArguments; // is available in here
});
}
}
It works! but I don't know if it may cause any other misbehavior in the application.
Using laravel events is also a better and cleaner way to do that in SOME cases.but the problem with event solution is you can't know if the model has been created for sure and it's time to call the event or it's still in creating status ( and not created status).

Laravel service container - registering an object shared to all services

I have tried to register to the container an Uuid and i have tried to retrive it from a route controller more than once, but the uuid value is not the first registered.
Can anyone help me to understand?
class AppServiceProvider extends ServiceProvider
{
public function boot()
{
if(App::bound('conf')==NULL)
App::instance('conf', Uuid::generate()->string);
}
}
class InstanceController extends Controller
{
public function getUuid()
{
return App::make('conf');
}
}
I need to register an unique value or object that will be accessible to all.
I have also tried to put this code:
config(['uuid' => Uuid::generate()->string]);
in Laravel command handle method:
class RegisteredInstances extends Command
{
public function handle()
{
config(['uuid' => Uuid::generate()->string]);
}
}
and execute it, but when i try to retrive the uuid from a service, the response is null.
Now i have registered a laravel command that do this:
class RegisteredInstances extends Command
{
.
.
.
public function handle()
{
if(App::bound('conf')==NULL)
App::instance('conf', Uuid::generate()->string);
if(config('uuid2')==NULL)
config(['uuid2' => Uuid::generate()->string]);
}
}
A task every minute execute this command and i try to retrive the uuid from a service controller like this:
class InstanceController extends Controller
{
public function getUuid()
{
return App::make('conf');
}
public function getUuid()
{
return config('uuid2');
}
}
The problem, in this case, is that the controller return NULL:
You need to use laravel Configuration (accessing-configuration-values) with AppServiceProvider
Example:
class AppServiceProvider extends ServiceProvider
{
public function boot()
{
config([ 'theconfig.uuid' => $class_here->UUID ]);
}
}
Then to use it, call
config('theconfig.uuid');
anywhere in the program
Is this in Laravel 4? I haven't seen the App::instance markup before, but I found it in Laravel 4.2 docs for the IoC Container.
This looks like a case for using a singleton. You can use this to ensure that conf is only resolved once. Looking at 4.2 docs, you could define your singleton as follows.
App::singleton('conf', function()
{
return Uuid::generate()->string;
});

Laravel Observer Create Working but Delete Not Working

I am Trying to Using Observer for Deleting With Relationship But Problem Is When i DD in Created Function Its Working Fine But When i DD In Deleted Function It Shows Nothing (POSTMAN) Means Neither Working Nor Error With Same Everything
Here Is Api:
$api->post('store','App\Http\Controllers\CustomerController#store');
$api->delete('delete/{id}','App\Http\Controllers\CustomerController#destroy');
Here Is Observer file made by artisan
namespace App\Observers;
use App\Customer;
class CustomerObserver
{
public function created(Customer $customer)
{
dd($customer);
}
public function deleted(Customer $customer)
{
dd($customer);
}
}
Here is Customer Controller
class CustomerController extends Controller
{
public function store(Request $request)
{
return Customer::store($request->person);
}
public function destroy($id)
{
$delete = Customer::where('person_id',$id);
$delete->delete();
}
}
Here Is Customer Model File.
class Customer extends Model
{
//Relationship Start From Here
public function person()
{
return $this->belongsTo(Person::class);
}
//End Here
public static function store($request)
{
//Call to Person Model And Save User
$user = Person::store($request);
//Create object of Customer Model
$customer = new Customer();
$customer->fill($request['customers']);
$customer->person()->associate($user)->save();
//return customer
return $customer;
}
}
I know this might be a late reply and not sure if you are still looking for the answer. I think the issue is about how you delete your Customer model.
When you do something like
$delete = Customer::where('person_id',$id);
$delete->delete();
You are executing a mass delete statement. As stated in laravel document, mass deletes will not fire any model events for the models that are deleted This is the reason your deleted observer event didn't fire.
When executing a mass delete statement via Eloquent, the deleting and deleted model events will not be fired for the deleted models. This is because the models are never actually retrieved when executing the delete statement
Now look at how you create a Customer. You create a model one at a time. Therefore your created observer does get run.
//Create object of Customer Model
$customer = new Customer();
$customer->fill($request['customers']);
$customer->person()->associate($user)->save();
To solve your problem, the easiest way is to retrieve all the models and delete one by one, so that you can trigger the event.
foreach (Customer::where('person_id',$id)->get() as $delete) {
$delete->delete();
}
can you do all things
1 add line in Customer::observe(CustomerObserver::class); in CustomerServiceProvider in boot method
add CustomerServiceProvider in app.php file in provider array
composer dump-autoload
php artisan config:cache
I was also having this problem, however I was calling the delete method from the repository, which prevents the Observer's deleted event from being triggered. When I used the delete from the mode it worked normally.
Only these Methods Works
$customer=Customer::where('id',$id)->first();
if($customer){
$customer->delete();
}
Or
$customer=Customer::find($id)->delete();

When is the `apply` method fired on a Laravel global scope object?

I'm attempting to implement a global scope in Laravel 4.2 by following the documentation. I have created a UserTypeTrait to add a UserTypeScope to the global scope. This is my UserTypeTrait:
trait UserTypeTrait
{
public static function bootUserTypeTrait()
{
Log::info('bootUserTypeTrait fired');
static::addGlobalScope(new UserTypeScope);
}
}
This is my UserTypeScope:
class UserTypeScope implements ScopeInterface
{
public function apply(Builder $builder)
{
Log::info('apply fired');
$model = $builder->getModel();
}
public function remove(Builder $builder)
{
// #todo
}
I'm attempting to apply this trait to my Customer object:
class Customer extends User
{
use UserTypeTrait;
}
Whenever the application boots, I'm getting confirmation that the bootUserTypeTrait() method fired in my log file. I'd like to add a constraint to all queries related to my Customer model in the apply method of my UserTypeScope, but I can't figure out how to trigger the apply method. From the documentation, it seems that it should be triggered any time I query the model. I've tried a few tests, but none of them result in the apply method being fired. For example:
public function testUserTypeScopeApplyFires()
{
FactoryMuffin::create('Users\Customer');
$customers = Customer::all(); // this does note fire `UserTypeScope::apply()`
$customer = Customer::first(); // neither does this
}
In my log file, I see plenty of bootUserTypeTrait fired and no apply fired entries. When is the apply() method invoked? I thought I followed the documentation correctly. Am I missing something?

Laravel 4 setting up model using the IoC container

I recently watched this video and wanted to change my Laravel controllers so that they had their dependencies managed with Laravel's IoC container. The video talks about creating an interface for a Model and then implementing that interface for the specific data source used.
My question is: when implementing the interface with a class that extends Eloquent and binding that class to the controller so that it is accessible from $this->model, should I also create interfaces and implementations for the Eloquent models which may be returned when calling methods such as $this->model->find($id)? Should there be different classes for the Model and the ModelRepository?
Put it another way: how do I do new Model when my model is in $this->model.
Generally, yes, people doing that pattern (the repository pattern) have an interface which have some methods defined that your app will use:
interface SomethingInterface {
public function find($id);
public function all();
public function paged($offset, $limit);
}
Then you create an implementation of this. If you're using Eloquent, then you can make an Eloquent implementation
use Illuminate\Database\Model;
class EloquentSomething {
protected $something;
public function __construct(Model $something)
{
$this->something = $something;
}
public function find($id)
{
return $this->something->find($id);
}
public function all() { ... }
public function paged($offset, $limit) { ... }
}
Then you make a service provider to put it all together, and add it into app/config/app.php.
use Something; // Eloquent Model
use Namespace\Path\To\EloquentSomething;
use Illuminate\Support\ServiceProvider;
class RepoServiceProvider extends ServiceProvider {
public function register()
{
$app = $this->app;
$app->bind('Namespace/Path/To/SomethingInterface', function()
{
return new EloquentSomething( new Something );
});
}
}
Finally, your controller can use that interface as a type hint:
use Namespace/Path/To/SomethingInterface;
class SomethingController extends BaseController {
protected $something;
public function __construct(SomethingInterface $something)
{
$this->something = $something;
}
public function home() { return $this->something->paged(0, 10); }
}
That should be it. Apologies on any errors, this isn't tested, but is something I do a lot.
Downsides:
More code :D
Upsides:
Able to switch out implementations (instead of EloquentSomething, can use ArraySomething, MongoSomething, whatever), without changing your controller code or any code that uses an implementation of your interface.
Testable - you can mock your Eloquent class and test the repository, or mock your constructor dependency and test your controller
Re-usable - you can App::make() to get the concrete EloquentSomething anywhere in your app and re-use the Something repository anywhere in your code
Repository is a good place to add additional logic, like a layer of cacheing, or even validation rules. Stock mucking about in your controllers.
Finally:, since I likely typed all that out and STILL DIDN'T ANSWER YOUR QUESTION (wtf?!), you can get a new instance of the model using $this->model. Here's an example for creating a new Something:
// Interface:
public function create(array $data);
// EloquentSomething:
public function create(array $data)
{
$something = this->something->newInstance();
// Continue on with creation logic
}
Key is this method, newInstance().
I've used $newModel = $this->model and it's worked for me.

Categories