Send a notification whenever any update happens in LARAVEL - laravel

Actually I am facing a problem. I need to send a notification to the admin whenever any update happens in any modal, in any user, and in any table.
To clarify more :
I have a client, a company, and an employee.
Under each part, I have many tables ( e.g: under client I have client's profile table, under company I have many tables corresponding to company's lawyer, company's files, etc.., similarly to the employee)
So correspondingly , I have many controllers thus many update methods.
So In order to send a notification to the admin whenever any update happens in any situation under any user. It's too annoying that I must include the notify statement $admin->notify(new UpdateIsMade()); under ALL update METHODS!
It's kind of redundancy.
What I want to actually approach is to find a solution that let me automatically send a notification to the admin whenever any update happens by any user under any table.
I tried to make a middleware function and tried to send a notification whenever any update happens under the client user (kind of sampling) :
public function handle(Request $request, Closure $next)
{
$clients = \App\Client::all();
foreach ($clients as $client) {
if($client->user->wasChanged()){
$arr_of_changes = $client->user->getChanges();
$admin=User::where('profile_type' , 'App\Admin')->first();
$admin->notify(new UpdateIsMade($arr_of_changes,$original_arr));
}
}
return $next($request);
}
Unfortunately this middleware didn't work.
I guess the problem is that $client->user->wasChanged() is not giving a true value whenever an update happens. It looks like wasChanged only works after the save process in the update method.
Any suggestion for my problem? Thank you for your time and sorry for the long text!

It might be less of a headache if you consider using database triggers so monitoring changes is completely separate.
You could create a new table called "change_log" with fields "action" and "created_at" then set up the trigger to insert a new record upon update of any tables you want to monitor.
Then you just set up a CRON to run at intervals that would call a Laravel controller to query the change_log and see if there are any records in it. If there are, the code would take the appropriate action to send an alert then empty the table. The change_log would remain empty until the DB trigger fires due to changes made.

Related

Laravel eloquent doesn't insert data when bug occur during multiple insert

I'm trying to insert users using csv.
My model has an observer on "created" event.
However I can have a bug after some $users->save() because of code in my function created event (which I fixed).
The code in created event send an email to the user. The problem is if code crash after 5iterations, I got my 5emails send but no user in my db.
I'm wondering if Eloquent use transaction when you call multiple times save() ?
If yes how to force Eloquent to really save my object after each end of event created ?
May be I'm misunderstanding something with event, because I don't see the point of using this event if your not sure to have your model insert in your DB.
Finally found what was wrong...
To insert csv my project use :
https://github.com/Maatwebsite/Laravel-Excel
And after some research, this is "why" eloquent use transaction in my case :
https://docs.laravel-excel.com/3.1/imports/validation.html#database-transactions

Laravel Client Switching Functionality

I am new to laravel and do not have much experience with using ORM. I am building a system in which I need build functionality to allow user to switch clients with another user. I am not sure what is the best method to achieve this.
Currently client belongs to user, do I need another association for client and user model using different foreign key ?
public function clients()
{
return $this->hasMany('App\Client');
}
public function user()
{
return $this->belongsTo('App\User');
}
Even though a client can only have one user switch request I would like to track all the requests so for example if user A makes request to switch client Test with user B and then make another request to switch the same client with user C I would like to soft delete the first record and create new record for new request. Once the other user accepts the request we change the primary key for client Test in the clients table. Will this be a One To Many / Many To Many relationship ?
What table naming conventions do I need to follow ? Any help will be much appreciated.
If I understand you correctly, you would like to temporarily switch clients for one user to another. What you should do is have another table say switched-clients that holds records for the switches with columns user1 and user2. When you want to retrieve clients, your controller checks this table first and if the record exists where('user1', 'user A') (according to your example), then you retrieve the clients for user2.

Don't show the message to all users? ( laravel )

I need to create to send a message to all new users registered on my website. I created a table called messages that admins can store (insert) the messages from the admin panel to this table and these messages are simply shown to all users with a foreach.
I don't know if this the best way to do something like that!
Anyway, the problem is that when any new user register and open his dashboard he just found the old messages
This is the table :
image
And this is the simple code for foreach
$msgForAll = Message::latest()->get();
I'm not sure how to display new messages to the users.
Again the way I made this idea is wrong, I know that ):
You can use eloquent's where spefically the whereDate queries in your case to get certain rows past or before date.
As an example relating to what you want to do, it can be along the lines of this:
// Given that you are using Auth to get the user's data...
// Get messages that were created after the user's creation date
$messages = Message::whereDate('created_at','>',Auth::User()->created_at)->get();

How to undo database after update in laravel?

I have two buttons, updates and undo. For example, after I update the new database, I want to undo it back to the original. I can only execute the update button.
function update(Request $req)
{
$id = $req->contact_id;
$contract = Contacts::find($id);
$contract->area_id = $req->areas;
$contract->code = $req->code;
$contract->created_at = $req->sign_in;
$contract->value = $req->total;
$contract->save();
return redirect('contact/'.$id)->with('message', 'Update successful !!');
}
To do that you must keep somewhere your old record before you update.
There is no "undo" so don't think it like that. You basically want to update the table with the old values.
Since as you said you have 2 buttons which one of them is the update which updates the current record what you can do, to make undo possible is that you have another table like records which you are going to fill in every update.
So according to your code the field contact_id seems like the unique identifier for each contract. Before you update then with the new values you can use a select like:
$oldRecord = DB::table('my_main_table')
->where('id', $req->contact_id)->first();
Inside your $oldRecord variable is stored all the info of your record that you want to update but is not yet updated , so it's your old record. Having that you can just hit an insert query to the records table i mentioned before so you can keep your "older version" there in case you want to undo.
So the undo functionality will just be the same logic. Select the record with the specific contract_id but this time from the records table and just update your main table.
I don't know if I fully got your question, but as long as you haven't called the save() method on your model, you can use
$eloquentModel->getChanges()
to list all attributes you did already change.
You can retrieve original attribute values by calling
$eloquentModel->getOriginal();

How to display in blade which rows are soft deleted?

I have created a polling system and in the backend (CMS area) I want the ability for admins to be able to remove polls. When an admin removes a poll, it should soft delete the poll. This is working as intended, however I also want to have the ability for the admin to be able to restore a poll. To do this I am displaying all of the polls (including the soft deleted polls) in the admin area.
PollController index() to get all polls
$polls = Poll::withTrashed()->get();
In the blade I want to have two different buttons for each poll. One of restoring and one for deleting but I only want to display 1 button for each poll depending on whether it can be restored or deleted.
To do this, I have put this inside the foreach in the blade:
#if($poll->trashed())
// Restore button
#else
// Delete button
#endif
However the issue is, trashed() keeps returning true for all the polls when only 1 out of the 3 polls I have are actually soft deleted. I am unsure as to why trashed() returns all of these are true?
How would I get this method working correctly? Thanks.
PART 1
It depends on your query. When using soft deletes, Laravel will query all models that are not soft-deleted by default. When you also want to get the soft-deleted models, you need to call the withTrashed() method on your query. Read more here:
https://laravel.com/docs/5.5/eloquent#querying-soft-deleted-models
To understand what withTrashed() does, you need to understand how soft-deleting works. Soft-deleting models works by adding a new column to your database tables called deleted_at. It's value defaults to null. When you soft-delete a model, Laravel will put the current timestamp into that column. Therefore, this field doesn't contain a null value anymore.
When querying models when using soft-deletes, Laravel appends a deleted_at is null condition to the query. Calling the withTrashed() method, removes that condition from the query.
Have a look on the source of the default query modifier and the withTrashed method.
PART 2
That are events. You can call that to tell Laravel, that it should execute that specific closure when this event happens. In your example, it is listening for the "deleting" event. See more on that here:
https://laravel.com/docs/5.5/eloquent#events
PART 3
You can entirely delete soft-deletable models with the forceDelete() method. See "Permanently Deleting Models" here:
https://laravel.com/docs/5.5/eloquent#querying-soft-deleted-models
FOR EXAMPLE
$items = App\Model::withTrashed()->get();
If you want to restore a single item, just find it by ID:
$item = App\Model::find($id);

Resources