Event of model not fire when use in Query Scopes - laravel

I am using laravel 9, PHP 8.1.
I noticed the following problem:
// App\Model\Store
class Store extends Model
{
....
public function scopeUpdateStore($query, $id) {
Store::find($id)->update(['name' => 'foo']);
return $query;
}
}
Then if I use :
Store::updateStore($id)->first();
Event updating and updated will not fire.
But when I use in controller:
// StoreController
Store::find($id)->update(['name'])
Event updating and updated will fire.
My problem is that it is not clear why there is this difference, and is there a way to make the event fireable in the Query Scope?
Thank you very much.

Related

Laravel deleting cache working in controller but not in model closure

I'd like to delete a specific model from the cache using its id. This works as expected in the controller, but not using the model closure.
What I have in App\Models\Post:
use Illuminate\Support\Facades\Cache;
protected static function booted()
{
static::updated(function ($post) {
Cache::forget('post:'.$post->id);
});
}
If I do Cache::forget('post:'.$post->id); in the controller it works.
Something I'm missing?
Make sure that you are actually changing a value on your model, because the updated event only fires when the model was dirty, as you can see here.
The saved event however will fire whenever you call the save() method, as you can see here:
protected static function booted()
{
static::saved(function ($post) {
Cache::forget('post:'.$post->id);
});
}
From the docs:
The retrieved event will fire when an existing model is retrieved from
the database. When a new model is saved for the first time, the
creating and created events will fire. If a model already existed in
the database and the save method is called, the updating / updated
events will fire. However, in both cases, the saving / saved events
will fire.

How to Override Update Method in Laravel 5.8

I'm trying to create a ticketing system that's linked to timesheets. Whenever someone updates a ticket, they have the option of submitting how much time has been spent on it, in a time_spent form object. Timesheets are polymorphically linked to many objects.
I want to create a trait, CreatesTimesheets, then apply that to relevant models so that:
Each of those models gets a timesheets() function.
It overrides the update() method of each model that it's a trait of, to check whether any time was submitted in time_spent.
It's the second bit that isn't working. My code is as below, and when I update the model (which works fine), this code doesn't fire at all, even testing it with a simple dd().
How do I fix this?
<?php
namespace App\Traits;
use App\Models\HR\Timesheet;
use Auth;
trait CreatesTimesheets
{
public function update(array $attributes = [], array $options = [])
{
dd('test');
if ($request->time_spent)
{
$timesheet = new Timesheet;
$timesheet->time_logged_in_mins = $request->time_spent;
$timesheet->appointment_id = Auth::user()->appointedJobIDToUse();
$this->timesheets()->save($timesheet);
}
parent::update($attributes, $options);
}
public function timesheets()
{
return $this->morphToMany('App\Models\HR\Timesheet', 'timesheetable');
}
}

Laravel Cancel Creation of Object

I have a Laravel app which has an object, Position, which is created via a form.
class Position extends Model
{
protected $dispatchesEvents = [
'creating' => PositionCreating::class,
];
And this calls an event of the PositionCreating class, which I've tested, and is correctly firing. The underlying code also works to give me success or fail criteria.
class PositionCreating
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public function __construct(Position $position)
{
if (some_good_stuff())
{
//keep creating the object
} else {
//stop creating the object
}
}
If it works, that's fine, I just let the __construct() function finish executing and everything, including the pre-execution code I want, works perfectly.
But I don't know how to actually stop the creation of the object. I can, of course use the dd() function or something (which works and stops creation of the object as expected), but I want to present a readable error to the user in a friendly manner. What function or commands should I be using to cancel the creation of the object to return back to my position.create method?
A bit late answer but this is a way to do it. Models fire several events. The one you're looking for is probably the "created" event. Each model event receive an instance of the model so you could just attach an event on your model, just like this:
protected $dispatchesEvents = [
'created' => PositionCreated::class,
];
Inside your "PositionCreated" event, add a public property to get the model instance,like this:
public $position;
public function __construct(Position $position)
{
$this->position=$position;
}
Finally just add the logic on your "handle" method inside your event listener.
public function handle($event)
{
if($something)
{
$event->position->delete();
}
}
This should do the work.You can check for the other events and see wich one suits you the most.

Queueable entity App\Setting not found for ID error in Laravel

I am trying to send emails in laravel 5.1 by using queues. When running queue listen command on terminal,
php artisan queue:listen
Displays below error on terminal,
[Illuminate\Contracts\Queue\EntityNotFoundException]
Queueable entity [App\Setting] not found for ID [].
Values of jobs table is not process. Any idea ?
How can I process my queue ?
I know this question is a few months old, but I'd like to add an observation of mine while encountering this very same error message. It is due to the EventListener (interface of ShouldQueue in this example for asynchronous) not being able to resolve a dependant variable correctly (out of scope or not included in scope of Event object passed through the handle(Event $event) method of EventListener).
For me, this error was fired when I put my code within the __construct block within the EventListener:
public function __construct(Event $event)
{
$localProperty = $event->property
Mail::queue(etc...);
}
public function handle()
{
// Yeah I left this blank... whoops
}
Instead, the handle() method of the EventListener takes an Event interface and when called processes the job in the queue:
In the Event:
public function __construct(Object $ticket, AnotherObject $user)
{
$this->ticket = $ticket;
$this->user = $user;
}
And in Event Listener
class SomeEventListener implements ShouldQueue
{
use InteractsWithQueue;
use SerializesModels;
public function __construct()
{
// Leave me blank!
}
public function handle(Event $event)
{
$someArray = [
'ticket' = $event->ticket,
'user' = $event->user,
];
Mail::queue('some.view', $someArray, function($email) use ($someArray) {
// Do your code here
});
}
}
Although a tad late, I hope this helps someone. Queues are similar to Events (with the exception of Jobs being the main driving force behind Queues), so most of this should be relevant.
Turned out that it was because a model was added to the queue, that has since been deleted.

Laravel 4 how to listen to a model event?

I want to have an event listener binding with a model event updating.
For instance, after a post is updated, there's an alert notifying the updated post title, how to write an event listener to have the notifying (with the post title value passing to the listener?
This post:
http://driesvints.com/blog/using-laravel-4-model-events/
Shows you how to set up event listeners using the "boot()" static function inside the model:
class Post extends eloquent {
public static function boot()
{
parent::boot();
static::creating(function($post)
{
$post->created_by = Auth::user()->id;
$post->updated_by = Auth::user()->id;
});
static::updating(function($post)
{
$post->updated_by = Auth::user()->id;
});
}
}
The list of events that #phill-sparks shared in his answer can be applied to individual modules.
The documentation briefly mentions Model Events. They've all got a helper function on the model so you don't need to know how they're constructed.
Eloquent models fire several events, allowing you to hook into various points in the model's lifecycle using the following methods: creating, created, updating, updated, saving, saved, deleting, deleted. If false is returned from the creating, updating, saving or deleting events, the action will be cancelled.
Project::creating(function($project) { }); // *
Project::created(function($project) { });
Project::updating(function($project) { }); // *
Project::updated(function($project) { });
Project::saving(function($project) { }); // *
Project::saved(function($project) { });
Project::deleting(function($project) { }); // *
Project::deleted(function($project) { });
If you return false from the functions marked * then they will cancel the operation.
For more detail, you can look through Illuminate/Database/Eloquent/Model and you will find all the events in there, look for uses of static::registerModelEvent and $this->fireModelEvent.
Events on Eloquent models are structured as eloquent.{$event}: {$class} and pass the model instance as a parameter.
I got stuck on this because I assumed subscribing to default model events like Event:listen('user.created',function($user) would have worked (as I said in a comment). So far I've seen these options work in the example of the default model user created event:
//This will work in general, but not in the start.php file
User::created(function($user)....
//this will work in the start.php file
Event::listen('eloquent.created: User', function($user)....
Event::listen('eloquent.created: ModelName', function(ModelName $model) {
//...
})

Resources