CakePHP Auth User Information - php

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.

Related

The Auth component still fetching older value of Session?

I am manually modifying some key of Auth session in beforeFilter of AppController.php by this code
public function beforeFilter(Event $event){
//$companyId = $this->Companies->find(.........
$this->request->session()->write('Auth.User.company_id', $companyId);
}
And in various actions of different controller i'm trying to get that stored companyid in session by following way
public function add(){
$companyId = $this->Auth->user('company_id');
debug($companyId); die;
}
When i see the value of $companyId, it is showing older value not updated one in beforeFilter method of AppController. However if i refresh the page and donot modify session again i will get updated $companyId value.
So my question is how can i update the value of Auth session data so that i can get updated value with $this->Auth->user('company_id') code in different places in same request?
The session storage used by the authentication component uses a buffering mechanism, ie the value from the session is usually only read once per request (unless it is being deleted/emptied).
https://github.com/cakephp/cakephp/blob/3.2.8/src/Auth/Storage/SessionStorage.php#L81-L83
So either read the value directly from the session in your controller action, or do not write to the session directly, but to the session storage, something along the lines of
$user = $this->Auth->user();
if (is_array($user) && $user) {
$user['company_id'] = $companyId;
$this->Auth->setUser($user);
}

Refresh Auth user data after update

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

CakePHP - Controller or No Controller?

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.

calling a controller function from a view in codeigniter

I'm a newbie to codeigniter and I'm attempting to write a function that would basically save a name and url to session data whenever you visited a certain page, then report it back in a small widget on the screen.
It's supposed to work as a kind of history function for what pages have been accessed and in what order. So far when working with test data it works great! however I'm trying to figure out how I can call the "add" function on each page that is visited, so we can supply the name and url of that page that was visited. Is there any way to do this? Or is there any way to report back a set of variables such as a name and url for a page after you visit it?
For example: say I visit page1, page2, page3, and page6 and I want each of those to show up in my history function. On each of those pages I would load the history view, and I would want to call the history's controller function "add(name,url)" and fill it in something like this:
add('page1','page1.php')
But I know that you're not supposed to access the controller from the history because that's not the way it's supposed to be done, however I cannot think of any better way to do this. Any help would be appreciated.
I don't know why dont you call this on every controller.
but if you want to call a function of the current controller, you have to get the instance of the current controller this way:
<?php
$CI =& get_instance();
$CI->method($param);
?>
the easiest way to do this would be to put a method in the constructor of your class. that way it will always run first thing, no matter what you are doing. remember that anything you can do in the controller -- sessions, validation, etc -- you can do in a model.
function __construct() {
parent::__construct();
// load model that has page tracker methods
$this->load->model( 'pagetracker_m' );
// call the method to track the pages, and have it return the results
if ( ! $this->history = $this->pagetracker_m->_trackpage(); ) {
echo 'Error getting history ' ; }
} // end construct
function something() {
// pass history to $data, then use echo $history->firstpage, etc in view
$data['history'] = $this->history ;
// call your view etc
}

pass a post value from view to controller to model, and back to controller in code igniter

I'm creating a login form with Codeigniter, and I have a controller that collects the inputs from the form, then I want to check to make sure what the user entered is in the database, so I'm collecting those values in the post and want to send them to the model for the database connection. Then if the results are in the database I want to send something back to the controller with a yes or no and then I can go from there. I'm kind of stuck, but this is what I have so far:
The controller:
function do_login()
{
$login = $this->input->post('Login');
$pwd = md5($this->input->post('Passwd'));
}
The Model:
function check_login()
{
$sql = $this->db->query("SELECT * FROM members WHERE loin = '?' AND password = '?'", array(//POST stuff goes in here));
return $sql->result();
}
I'm not sure how to pass the data to the model, and then back to the controller.
Any help would be great!
Thanks!
In any MVC form POST is sending to controller (in action property in form) and controller (as the name is decribed) controls what will happend, in your case should ask database for verification via model, get response, decide what to do, and use view to display results...
so in your controller:
function do_login() {
$login = $this->input->post('Login');
$pwd = md5($this->input->post('Passwd'));
$results = $this->...your_model_name...->chek_login( parameters as login and password would help )
// base on results: has records or has not - do something
// maybe display view
}
+1 to #bensiu (I tried to up the answer but wasn't able to yet)
Also: don't forget that you need to explicitly load your model.
Reading this part of the user guide should answer most of your questions.
I would add 2 parameters to check_login and make it boolean:
function check_login($user, $password)
{
$sql = $this->db->query("SELECT * FROM members WHERE loin = '?' AND password = '?'", array($user, $password));
if (...)
return TRUE;
else
return FALSE;
}
Make it boolean lets the full login checking inside the controller, so that if there are more tests to do, the developper who uses the model doesn't have to know them, so it avoids errors.
For instance if you want to check that there is only one row in the database, and an internal variable to know whether login is allowed or not (just an example).
Would all developer read the documentation about that variable that has to be checked before validating the login? Would that documentation be written?

Categories