I'm displaying the name of the loggedin user in the header with $this->Auth->user('name').
The issue is, when I update the name of the user how can I refresh this value at $this->Auth->user() because after I just updated the old name still?
Unless you are using stateless authentication, the data is stored and retrieved from the session, so you just need to update it there.
For example
$this->Auth->session->write($this->Auth->sessionKey . '.name', $newName);
Or maybe set the complete modified user data in case applicable (note that this will renew the session)
$this->Auth->setUser($updatedUserData);
See also API > Controller > Component > AuthComponent::_setUser()
In Appcontroller
public function initialize()
{
...
$tableUser=TableRegistry::get("Users");
$user=$tableUser->get($this->Auth->user('id'));
$this->set(compact('user','...'));
...
In view just use $user['name'] you will get the name. Any update in user will inflect to $user. You can get any fields after update the user with array $user.
I stucked at your case, but i have found the solution long ago. Hope this work. Let me know if it doesn't work. I write out in my memory so it might wrong functions
Related
Using Laravel 5.1 & 'file' Session Driver,
I'm trying to provide facility to user to track their sessions and invalidate them anytime they wish by keeping a record of their session_id within the database. With Database, I mean, I maintain a table called user_sessions which associates user_id with their session_id (obtained by Session::getId()).
So, to invalidate Session, I tried the following code,
$sessionId = Session::getId();
Session::setId($sessionId);
Session::invalidate();
and it works perfectly fine, for the case where, where user does not uses Remember Me feature.
For the case where user uses Remember Me feature, this above code does not work, So, I additionally, tried setting remember_token field to null as specified here in this answer, but with this, all sessions of the user get destroyed including the current one.
You can simply use
use Illuminate\Support\Facades\Session;
Session::forget('YOUR_SESSION_ID');
If you want to get the current session Id:
Session::driver()->getId();
I hope it helps
Sessions are meant to be short-lived. If you want something a bit more permanent you can use some sort of a long term user settings table.
Create a table user_settings:
id (PK), user_id(FK users table), settings(BLOB?), created_at, updated_at
Add a model:
class UserSetting extends Model {
public function user() {
return $this->belongsTo(User::class);
}
}
You can also associate the user with these via :
class User extends Model {
//...
public function settings() {
$this->hasMany(UserSetting::class);
}
}
You can then get all user sessions via:
User::find($u)->settings();
When a user logs in regularly or automatically via a remember token a Login event is fired.
You can listen to this in your event service provider:
\Event::listen(\Illuminate\Auth\Events\Login::class, function ($event) {
// Here you can load the last settings in the session if you want e.g.
session(['current_settings' => $event->user->settings()->latest()->value('id') ]);
// or you can just make a new entry:
$settings = new UserSettings();
$event->user->settings()->save($settings);
session(['current_settings' => $settings->id ]);
});
Note that you will have to manually persist things that need persisting instead of just putting them in the session.
I am new to PHP. I am using a MVC project as an example, and I noticed that each time a submit button is pressed my controller is called. The issue with this is that it creates a new model every time the button is pressed.
To fix this, I used a hidden field to check if the button has already been pressed. If it has, then I do not instantiate a new Model, otherwise I do. Code from controller is below:
//code listed below is in the controller which is called each time button
//has been pressed...
$myModel;//used to access model and its functions from controller
if(isset($_POST['has_started']))
{
//stores some logic that uses $myModel variable
playingGame();
}
else
{
echo "just starting...";
$myModel=new HangManModel();
startGame($myModel);
}
This seems to work, BUT then when playingGame() is called it tells me I cannot use $myModel and its functions because it was not declared, or it is a non-object. How can I fix this? Thanks for the help!
First, there is no mvc pattern I see here.
Secondly, php executes and generates the output in html and javascript and sent to the browser.
At the next postback, php does not store any state for this.
As per my understanding, for storing states you can use one of the following.
1) Option1-->Using session.
//code listed below is in the controller which is called each time button
//has been pressed...
$myModel;//used to access model and its functions from controller
if(!isset($_SESSION)){session_start();}
if(isset($_POST['someuniqueID']))
{
//stores some logic that uses $myModel variable
$someuniqueID = $_POST['someuniqueID'];
$myModel = $_SESSION[$someuniqueID]; //retrieving the session object.
playingGame($myModel); //passing your model to the main function.
}
else
{
echo "just starting...";
$myModel=new HangManModel();
//start session
$_SESSION['someuniqueID'] = $myModel; // do not store very complex model object to avoid server memory problem.
startGame($myModel);
}
2) Option2--> you can serialise that object and send it in hidden field then it will be posted back but this will have bandwidth consumption problem. Each time, the page is posted, it will send your model back and forth.
3) Option3--> If your model is big, Use database and create a temp table where you can store unique id and serialised $myModel object. You will need to clean the unwanted states from database. because unlike session and hidden field it is permanent storage.
I am currently building a web app which has two models, Donor and Donation Models respectively. It has multiple user roles. When the staff user first registers a donor, I want him to be redirected to another form which allows him to fill in the Donation details(the donor is registered once the first donation is successful).
Firs of all, should I create a donation controller, from which I would redirect the user using:
return $this->redirect(array('controller'=>'donations','action'=>'add'));
For the above to work, it requires me to save the newly registered donor's id in a session like so :
$this->Session->write('id', $this->Donor->id);
So the user is redirected to 'donations/add' in the url, and this works fine.. However I think this has some flaws. I was wandering whether I should create another action inside the Donor controller called 'add_donation', which will have its respective 'View'. The idea is to be able to form a url of the sort : 'donors/add_donation/4' (4 being the donor_id ! )
This URL follows this construct: 'controller/action/id'
If anyone could shed some light on best practices, or describe any caveats to my solution(the former, using session etc.) , please do help a brother out! Ill be deeply indebted to you! Thanks in advance!
After you saved the data you can do this in the DonorsController:
$this->redirect(array(
'controller' => 'donations',
'action' => 'add',
$this->Donor->getLastInsertId()
));
There is no need to return a redirect, it's useless because you get redirected. Notice that we pass the last inserted record id as get param in the redirect. The redirect method of the controller calls by default _stop() which calls exit().
CakePHP3: There is a discussion about changing that default behavior in 3.0. Looks like in CakePHP 3.0 the redirect() won't exit() by default any more.
DonationsController:
public function add($donorId = null) {
// Get the donor to display it if you like to
if ($this->request->is('post')) {
$this->request->data['Donation']['donor_id'] = $donorId;
// Save code here
}
}
I would not use the session here, specially not by saving it to a totally meaningless and generic value named "id". If at all I would use always meaningful names and namespaces, for example Donor.lastInsertId as session key.
It's not always clear where to put things if they're related but the rule of thumb goes that things should go into the domain they belong to, which is pretty clear in this case IMHO.
Edit:
Leaving this edit here just if someone else needs it - it does not comply with the usage scenario of the asker.
If you have the user logged in at this stage, modify the add function to check if the userId passed is the same as the one logged in:
DonationsController:
public function add($donorId = null) {
// Get the donor to display it if you like to
if ($this->request->is('post')) {
if ($this->Auth->user('id') != $donorId) {
throw new InvalidArgumentException();
}
$this->request->data['Donation']['donor_id'] = $donorId;
// Save code here
}
}
You can use also the same controller using more models with uses.
Or you can also to ask to another controller with Ajax and morover to get response with Json.
In my view i am trying to display the current logged in users information and have figured i can do this by using
echo "Welcome back " .$this->Session->read('Auth.User.username'). "
This displays the username and i can use the same approach to display the other fields in that database row, however some of the other fields can update at anytime but does not update on the users page until they logout and login again.
Is this correct way to do it? or can this be done a better way and somehow put some code in the beforeFilter() in AppController to continue to update the variables on each page load?
If the database is updated from outside CakePHP and without calling any controller action it seems the only solution for this is making a query on every loaded page to get the current value.
For this, you should use the beforeFilter method on the AppController:
function beforeFilter(){
$user = $this->User->field('name', array('User.id' => $this->Session->read('Auth.User.id')));
$this->Session->write('Auth.User', $user);
}
Otherwise, you can make use of JavaScript and AJAX to get the data from time to time.
I prefer to get the real time data instead of the session data
var $uses = array('User');
function beforeFilter(){
$id = $this->Auth->user('id'); //Using the session's user id is fine because it doesn't change/update
$user_data = $this->User->findById($id);
$user_fname = $user_data['User']['fname'];
$this->set('fname', $user_fname);
}
//In your view
echo 'Welcome Back '. $fname . '!';
What if you just made an afterSave() on the User model, and in it, set $this->Session->write('Auth.User') = $user;
This is non-tested, but seems like it should work - then your session would always be up to date on any changes.
Edit:
Per your comment, if the data is being pulled from a third-party source that you don't have access to, and you need to make sure it's updated on EVERY page load, then yes, the AppController's beforeFilter() is just fine.
If, however you only need it on certain pages, or certain elements, you can call the update then, or via a requestAction of an element.
When my users are logged in I display their details (name, email) on the UI. When they update their profile, I would like to show the updated details, without requiring the user to log out and back in.
The UI details are retrieved from Zend_Auth via a view helper. Zend_Auth is storing the 'identity' details in a session.
How should I go about updating the details in the session?:
I was considering retrieving the user's login credentials from the database and using them to call Zend_Auth->authenticate() again. The problem is that I don't know the password, only it's md5 hash. I could consider a new method, reauthenticate(), which configured the adapter to bypass the md5 and salt, but this sounds laborious.
I was considering writing directly to the Zend_Auth session namespace, but this sounds like a recipe for trouble?
Have you come across a similar problem? How did you handle it?
Your ideas are much appreciated!
You can update Zend_auth identity for the currently logged user. Very simplified action that updates only username could be as follows:
public function editAction() {
// check if user is logged, etc, and then
// show the edit user form and process the data after submission.
$userForm = new My_Form_EditUser();
if ($this->getRequest()->isPost()) {
if ($userForm->isValid($_POST)) {
// process the submitted data,
// and when you are sure that everything went ok,
// update the zend_auth identity
$authData = Zend_Auth::getInstance()->getIdentity();
// this line would depend on the format of your
// identity data and a structure of your
// actual form.
$authData->property->nickname = $formData['user']['nickname'];
$this->_helper->FlashMessenger('Your data was changed');
return $this->_redirect('/');
}
}
$this->view->form = $userForm;
}
Hope this helps.
What I really want is a method on Zend_Auth::setIdentity($user).
But in the absence of such a method, I have used a hack in which I have create an auth adapter that always returns success and sets the identity to the same user object I would have created in a "real" auth adapter. Then I just call Zend_Auth::authenticate($adapter) with that adapter and it sets the identity internally.
Now, looking mosre closely at the internals of Zend_Auth::authenticate(), I see that what we could do is just:
Zend_Auth::getInstance()->getStorage()->write($user);
Here's how I solved the problem for the time being. Not sure yet if it's the best solution:
create a wrapper for Zend_Auth
include a getAuthAdapter($raw) method
configure the adapter differently, depending on the value of $raw
if (false === $raw) {
$this->_authAdapter->setCredentialTreatment('SHA1(CONCAT(?,salt))');
} else {
$this->_authAdapter->setCredentialTreatment();
}