Dispatching event from Model with custom event key - laravel

I'm currently rebuilding an application and I currently have this in observer
public function updated(Lead $lead) {
if ( $lead->isDirty('status') && $lead->status === 'rejected') {
LeadRejected::dispatch($lead);
}
}
I'm removing the use of observer and want to dispatch the event directly from the model
something like;
protected $dispatchesEvents = [
'updated' => LeadUpdated::class,
];
I'd like to know if its possible to create a custom event key (model's lifecycle) I can hook the LeadRejected event
something like
protected $dispatchesEvents = [
'rejected' => LeadRejected::class,
];

Related

Laravel - Passing a variable from controller to model or accessing a variable in the controller from the model

I want to pass a variable in the controller to the model in laravel.
In Controller,
$withoutUser = True;
$post->update([
'status' => 'inactive'
]);
In model,
protected static function boot(): void
{
parent::boot();
static::updated(fn (Model $model) =>
// Need to access the $withoutUser variable from here?
);
}
Is there a method to pass the $withoutUser variable when calling $post->update() or is it possible to access the $withoutUser variable in the controller when the static::updated method is called in model?
Thanks
You can do this by creating a property on the post model. The exact same instance of the post class is sent to the event dispatcher. So you can write your code something like this:
class Post extends Model
{
public bool $updateWithoutUser = false;
...
}
And then in your controller:
$post->updateWithoutUser = true;
$post->update([
'status' => 'inactive',
]);
And in the boot function:
protected static function boot(): void
{
parent::boot();
static::updated(function (Post $post) {
if ($post->updateWithoutUser) {
...
}
});
}
Though you should be careful if you are queueing the listener, because in that case the property will not be preserved as it fetches the post from the database when the listener is run from the queue.

Nova action with custom message for confirmation - tool required?

In the Nova docs, it is indicated that fields can be used to require input from a user before dispatching an action.
https://nova.laravel.com/docs/3.0/actions/defining-actions.html#action-fields
public function fields()
{
return [
Text::make('Subject'),
];
}
These fields are referenced in handle:
public function handle(ActionFields $fields, Collection $models)
{
foreach ($models as $model) {
(new AccountData($model))->send($fields->subject);
}
}
It is unclear from the docs what AccountData should be. When I instantiate a model, it tells me send is undefined. What is the simplest way to get a modal to popup that includes the defined fields?
What you should do is to create a new action with artisan nova:action and in that actions fields method define the fields user should fill out. They work in the same way as normal fields in a resource.
Then inside the actions method inside the resource where you want the action, you add it to the return array in actions method.
eg:
inside resource:
public function actions(Request $request)
{
return [
QuickImportAction::make($this->resource, $request)->standalone()
];
)
And then inside the Nova/Actions/ after action is generated:
public function handle(ActionFields $fields, Collection $models)
{
if($models->count()>0) return Action::danger("Replace in filters is not ready, unselect and replace in all");
}
/**
* Get the fields available on the action.
*
* #return array
*/
public function fields()
{
$replace = "";
return [
Heading::make("<div class=' text-secondary'> NOTE! only selected filters rows will be replaced</div>")
->textAlign('center')->asHtml(),
];
)
EDIT:
Sorry, let me reply to your actual question. The
(new <class>)->method
Is the same as:
$model = new MyModel();
$model->method()
So its different from application to application.

How to detect update event in model in Laravel 8

Good day to all
The situation is as follows
In the controller, in the update method, I try to update the object
There is an image in the fields of this object
Wrote a trait to process this field and load an image
In the model itself, I called the update method, which just determines the event of updating the object
The problem lies in the following image in the specified directory is loaded and the entry itself in the database does not change
Here is my code
Controller
Model
Trait
There is extra code in the model
public function update(Request $request, MainHeader $mainHeader): RedirectResponse
{
$mainHeader->update([
'language_id' => $request->language_id,
'brandLogoImage' => $request->file('brandLogoImage'),
'homeTitle' => $request->homeTitle,
'ourProjectsTitle' => $request->ourProjectsTitle,
'contactTitle' => $request->contactTitle,
'feedbackTitle' => $request->feedbackTitle,
]);
return redirect()->route('admin.header.index')->with('success', 'Данные успешно обновлены');
}
public function setBrandLogoImageAttribute($value): string
{
return $this->uploadImage('brandLogoImage', $value);
}
public function update(array $attributes = [], array $options = [])
{
$this->uploadImage('brandLogoImage', $attributes['brandLogoImage']);
$this->setBrandLogoImageAttribute($attributes['brandLogoImage']);
return parent::update($attributes, $options); // TODO: Change the autogenerated stub
}
protected function uploadImage(string $attr, $value): string
{
$uploadDir = public_path('uploads/');
$imageDir = public_path('uploads/image/');
if (!file_exists($uploadDir)){
mkdir($uploadDir);
}
if (!file_exists($imageDir)){
mkdir($imageDir);
}
if (!file_exists(public_path("uploads/image/$this->table/"))){
mkdir(public_path("uploads/image/$this->table/"));
}
$imageName = Str::random(12) . '.png';
Image::make($value)->save(public_path("uploads/image/$this->table/$imageName") , 100);
return $this->attributes[$attr] = (string) "uploads/image/$this->table/$imageName";
}
if you call the update methode in your model then you are overriding the default update() of the model class , its not listening to the event it simply runs your code before parent:: , so you need to make sure that the changes you are making does not get overwitten by the parent call .
regarding your question on how to detect update , if you want to perform anything before update than i advise you to use eloquent events or use observers , Observers listen to various events regarding your model like updating or updated .. but i think if its only for updating event than you should use event using closure
for example :
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
/**
* The "booted" method of the model.
*
* #return void
*/
protected static function booted()
{
static::updating(function ($user) {
// do what you want
});
}
}
If your pupose

Call another observer method in current model observer

In laravel I want to call another observers deleting method in my current model observer. Is that possible?
for example lets say I have observers for product and category, So I want to call productobservers deleting method in categoryobservers deleting loop.
public function deleting(Category $Category)
{
DB::transaction(function () use($Category) {
$Category->products->each(function ($products) {
//call product observer deleting function
});
});
}
You can set your event in this array like this
class User extends Authenticatable
{
protected $dispatchesEvents = [
'saved' => UserSaved::class,
'deleted' => UserDeleted::class,
];
}
and create listener for those events

How to create custom model events laravel 5.1?

I want to create a custom model event in laravel 5.1.
For e.x. when an Articles category is updated i want to make an event and listen to it.
$article = Article::find($id);
$article->category_id = $request->input('category_id');
// fire an event here
You should use Eloquent Events (do not confuse with Laravel Events).
public function boot()
{
Article::updated(function ($user) {
// do some stuff here
});
}
You would want to look into Observers to make this more reusable and single-responsible, though a starting point would be something alike:
public function boot()
{
self::updated(function ($model) {
if (array_key_exists('category_id', $model->getDirty())) {
// Log things here
}
});
}
Laravel will populate a 'dirty' array which contains modified fields. You can detect when a certain field has changed using this.
You also have:
$model->getOriginal('field_name') // for this field value (originally)
$model->getOriginal() // for all original field values
You can use Attribute Events to fire an event when the category_id attribute changes:
class Article extends Model
{
protected $dispatchesEvents = [
'category_id:*' => ArticleCategoryChanged::class,
];
}

Resources