Laravel Event Listening - laravel

I have an issue similar to this post :
Laravel - last login date and time timestamp
In short, my purpose and question is :
I have a "logrecords" table in my database.
My event listeners in global.php are just working on default "users" table.
I want my event listeners are able to insert data on my "logrecords" table.
How can i do that :
Should i configure my database tables using which are using eloquent ?
Or should i change something in global.php ?
Thanks for your support.
--------------------Update--------------------
I realized that in my auth.php file, default authentication model has been set as :
'model' => 'User'
But i want to listen and work with both User and Logrecord model.So that when i try to listen events in my global.php file, laravel is automatically trying to work with User model. So that i had to configure my event listeners like that :
Part of my global.php file :
//First Example
Event::listen('auth.login', function($user)
{
$userLogRecord = Logrecord::firstOrCreate(array('user_id' => $user->id));
$userLogRecord->user_id = $user->id;
$userLogRecord->login_last_at = date('Y-m-d H:i:s');
$userLogRecord->save();
});
//Second Example
Event::listen('auth.logout', function($user)
{
$userLogRecord = Logrecord::firstOrCreate(array('user_id' => $user->id));
$userLogRecord->user_id = $user->id;
$userLogRecord->logout_last_at = date('Y-m-d H:i:s');
$userLogRecord->save();
});
It is working for now, but I am thinking that it's not a good idea to edit my listeners like that. My purpose is to listen and do some process with both User and Logrecord models. It serves my purpose right now but i feel like i have to improve.
Any ideas ?

#DemonDrake,
If I understand correctly you simply want to add data to a "log" table?
In the most simple form, the answer is "Yes you would use the eloquent ORM for that
class Log extends Eloquent {
protected $table = 'log';
}
or perhaps query builder even.
There are a number of ways this is possible. I personally suggest you check out https://laracasts.com/lessons

Related

Laravel Automatic resource CRUD

What patterns can I use for 'automatic' resource CRUD operations for given Models in Laravel?
Say I have two models SomeModel and SomeRelatedModel where some_related_model.some_model_id is an FK to SomeModel.
The standard method on the SomeModelController for handling the create POST /api/someModel might look like this:
public function store(Request $request)
{
$user = Auth::guard('api')->user();
$data = $request->get('data');
$data['user_id'] = $user->id;
$someModel = SomeModel::create($data);
// has this request been made with the data for the
// related model? If so create this too.
if($data['relatedModel']){
SomeRelatedModel::create(array_merge(
['some_model_id' => $someModel->id]
$data['relatedModel']
));
}
// has this request been made expecting to get related
// models back in the response? If so load these
if($request->has('with')){
$someModel->load($request->get('with'));
}
return (new PostResource($post))
->toResponse($request)
->setStatusCode(201);
}
This works but is very verbose and for models with a sub-sub relation would need changing further. Similar work will need to be done for the other endpoints for all resources.
Is there a more versatile (or tidy) pattern using out-of-the box classes to get a similar effect?
Have a look at Laravel Orion. Fits your use case.

Laravel Configuration update

I am working on Laravel. I have questions about update / add configuration dynamically. Let me tell you my question.
I am updating / add the global configuration of my project using the file_put_content in config file. I have another way, save configuration into the database and pull that configuration at the time of login to the system.
Which way is better to use and why?
one way is maintain seprate table for config data if your data is static means nothing have to change in that data. and then create provider to get your data and bind that data at run time
public function boot()
{
if (Schema::hasTable('roles')) {
$roles = Role::pluck('name', 'id')->all();
$data = collect($roles)->mapWithKeys(function ($item, $index) {
return [str_slug($item, '_') => $index];
})->all();
config(['configfilename.configkey' => $data]);
}
}
Like this you can get your config data at run time

How can I get Joomla component parameter values?

===
UPDATE:
I think now I am literally just trying to get a database value into my component php files, but again, there seems to be very little documentation that can give an example of a function that will return this info like there is in Wordpress.
So I have a table called membersarea_countries that will have records of differnt countries I want to store values for.
I've read about JTable and other things, but how can I simply just bring back the records from this table?
$row = JTable::getInstance('membersarea_countries', 'Table', array());
But this returns a boolean of 0.
I'd really appreciate some help if anyone can.
===
I've been following what several online guides explain, which are all pretty much the same thing, but I never seem to return the values that I'm expecting.
In Components > Members Area (my component), I have a table set up to allow me to enter a record for each country, and then store a uniqueRef, signature, and URL within that record. (for GeoIP purposes).
I've created the first record, however when I try to use the following code, which the tutorials suggest, I don't see any of my fields within this:
$app = JFactory::getApplication();
$params = $app->getParams();
$uniqueRef = $params->get('uniquereference');
$signature = $params->get('signature');
This is all I see in NetBeans:
There's nothing about $app, and no sign of the fields I've got in the Joomla backend.
I don't understand what's happening, or exactly what I should be doing here. Wordpress uses a simple get_option function. Can anyone try and help me?
Below is the link to the detailed document about JTable -
https://docs.joomla.org/Using_the_JTable_class
Firstly you need to create JTable instance using below code and also change table file name to membersareacountries.php
JTable::addIncludePath(JPATH_ADMINISTRATOR . '/components/com_membersarea/tables');
$row = JTable::getInstance('Membersareacountries', 'Table', array());
JTable Class in this file /administrator/components/com_membersarea/tables/membersareacountries.php-
<?php
defined('_JEXEC') or die();
class TableMembersareacountries extends JTable
{
public function __construct($db)
{
parent::__construct( '#__membersarea_countrie', 'id', $db );
}
}
Then you can use load method to get any records. This accepts primary key value of that table -
$id = 1;//change id as per your record
$row->load($id);
//read data
echo $row->id;
echo $row->title;

symfony 3 time when log in and log out

I'm pretty much new in symfony 3, so how I could get time when user log in and log out.. I know i should create entity for time.. that entity would have id,userID startTime, endTime.. and user should have a connection(many to many, that lot of user could have lot of log in.. ) with this entity.... I'd like to store in database this information. I tried to search on google but I found nothing in common.
I'd like to activate time startTime when this button is pressed
Sign
in
and code in controller
#Route("/login", name="authentication_login")
public function loginActionAction(Request $request)
{
$authenticationUtils = $this->get('security.authentication_utils');
// get the login error if there is one
$error = $authenticationUtils->getLastAuthenticationError();
// last username entered by the user
$lastUsername = $authenticationUtils->getLastUsername();
return $this->render('AppBundle:uzduotis:login.html.twig', array(
'last_username' => $lastUsername,
'error' => $error,
));
}
then for endTime
/**
* #Route("/logout", name="logout")
* #Method({"GET"})
*/
public function logoutAction(Request $request)
{
$session = $this->$request->getSession();
$session = $this->get('session')->clear();
return $this->render('AppBundle:uzduotis:login.html.twig');
}
For this answer I assume you store the users in the database. If not, please show how you do it.
First of all please have a look at the doctrine documentation on how to connect entities to each other. In your case this should help:
http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/association-mapping.html#one-to-many-bidirectional
There's also a pretty good tutorial on this subject in the Symfony documentation: http://symfony.com/doc/current/doctrine/associations.html
In the controller you can fetch the currently logged in user by executing $user = $this->get('security.token_storage')->getToken()->getUser();. That will return the database entity of the user that you can modify immediately. E.g. by adding a new record to the time table (example code):
$time = new TimeLog();
$time->setUser($user);
$time->setType('login');
$time->setTimestamp(time());
In case saving does not work, try with the persist and flush methods of $this->get('doctrine')->getManager(). There's lots of documentation about this, too.

Is it possible to temporarily disable event in Laravel?

I have the following code in 'saved' model event:
Session::flash('info', 'Data has been saved.')`
so everytime the model is saved I can have a flash message to inform users. The problem is, sometimes I just need to update a field like 'status' or increment a 'counter' and I don't need a flash message for this. So, is it possible to temporarily disable triggering the model event? Or is there any Eloquent method like $model->save() that doesn't trigger 'saved' event?
Solution for Laravel 8.x and 9.x
With Laravel 8 it became even easier, just use saveQuietly method:
$user = User::find(1);
$user->name = 'John';
$user->saveQuietly();
Laravel 8.x docs
Laravel 9.x docs
Solution for Laravel 7.x, 8.x and 9.x
On Laravel 7 (or 8 or 9) wrap your code that throws events as per below:
$user = User::withoutEvents(function () use () {
$user = User::find(1);
$user->name = 'John';
$user->save();
return $user;
});
Laravel 7.x docs
Laravel 8.x docs
Laravel 9.x docs
Solution for Laravel versions from 5.7 to 6.x
The following solution works from the Laravel version 5.7 to 6.x, for older versions check the second part of the answer.
In your model add the following function:
public function saveWithoutEvents(array $options=[])
{
return static::withoutEvents(function() use ($options) {
return $this->save($options);
});
}
Then to save without events proceed as follow:
$user = User::find(1);
$user->name = 'John';
$user->saveWithoutEvents();
For more info check the Laravel 6.x documentation
Solution for Laravel 5.6 and older versions.
In Laravel 5.6 (and previous versions) you can disable and enable again the event observer:
// getting the dispatcher instance (needed to enable again the event observer later on)
$dispatcher = YourModel::getEventDispatcher();
// disabling the events
YourModel::unsetEventDispatcher();
// perform the operation you want
$yourInstance->save();
// enabling the event dispatcher
YourModel::setEventDispatcher($dispatcher);
For more info check the Laravel 5.5 documentation
There is a nice solution, from Taylor's Twitter page:
Add this method to your base model, or if you don't have one, create a trait, or add it to your current model
public function saveQuietly(array $options = [])
{
return static::withoutEvents(function () use ($options) {
return $this->save($options);
});
}
Then in you code, whenever you need to save your model without events get fired, just use this:
$model->foo = 'foo';
$model->bar = 'bar';
$model->saveQuietly();
Very elegant and simple :)
Call the model Object then call unsetEventDispatcher
after that you can do whatever you want without worrying about Event triggering
like this one:
$IncidentModel = new Incident;
$IncidentModel->unsetEventDispatcher();
$incident = $IncidentModel->create($data);
To answer the question for anyone who ends up here looking for the solution, you can disable model listeners on an instance with the unsetEventDispatcher() method:
$flight = App\Flight::create(['name' => 'Flight 10']);
$flight->unsetEventDispatcher();
$flight->save(); // Listeners won't be triggered
In laravel 8.x :
Saving A Single Model Without Events
Sometimes you may wish to "save" a given model without raising any events. You may accomplish this using the saveQuietly method:
$user = User::findOrFail(1);
$user->name = 'Victoria Faith';
$user->saveQuietly();
See Laravel docs
In laravel 7.x you can do that as easy as
use App\User;
$user = User::withoutEvents(function () {
User::findOrFail(1)->delete();
return User::find(2);
});
See more in Laravel 7.x Muting Events documentation
You shouldnt be mixing session flashing with model events - it is not the responsibility of the model to notify the session when something happens.
It would be better for your controller to call the session flash when it saves the model.
This way you have control over when to actually display the message - thus fixing your problem.
Although it's a long time since the question, I've found a way to turn off all events at once. In my case, I'm making a migration script, but I don't want any event to be fired (either from Eloquent or any other).
The thing is to get all the events from the Event class and remove them with the forget method.
Inside my command:
$events = Event::getRawListeners();
foreach ($events as $event_name => $closure) {
Event::forget($event_name);
}
The only thing that worked for me was using the trait WithoutEvents. This will be executed inside the setUp method and does prevent any dispatch you have added to the code.

Resources