Updating user data in the authentication object

CakePHP 4

I do have this working, but I’m sure its a hacky (non-cake) solution.

The logged in user has the ability to edit his own account, specifically their name, and I use that name which I get via: $this->Authentication->getResult()->getData()->fullname.

When the user edits their name, on save it goes back to the front screen, where it welcomes them by name. In my UsersController.php I have this: -

    public function edit($id = null)
    {
        $user = $this->Users->get($id, [
            'contain' => [],
        ]);
        $this->Authorization->authorize($user);
        
        if ($this->request->is(['patch', 'post', 'put'])) 
        {
            $user = $this->Users->patchEntity($user, $this->request->getData());
            if ($this->Users->save($user)) 
            {
                if ($user->id === $this->loggedInID) //if edited by owner (not admin)
                   $this->Authentication->getResult()->getData()->offsetSet('fullname', $user->fullname);

where that last line is how I am putting my fullname field back into my Authentication object.

In my AppController I set a few variables which I use site-wide, thus in my beforeFilter()

        $data = $this->Authentication->getResult()->getData(); //actual user entity, null when not logged in
        $this->isLoggedIn = $this->Authentication->getResult()->isValid();
        $this->loggedInID = $this->isLoggedIn ? $data->id : -1;
        $this->loggedInEmail = $this->isLoggedIn ? h($data->email) : "";
        $this->loggedInFullname = $this->isLoggedIn ? h($data->fullname) : ""; // h() to sanitise
        $this->adminLevel = $this->isLoggedIn ? $data->adminlevel : -1;
        $this->set(['isLoggedIn' => $this->isLoggedIn,
                    'loggedInID' => $this->loggedInID,
                    'loggedInEmail' => $this->loggedInEmail,
                    'loggedInFullname' => $this->loggedInFullname,
                    'adminLevel' => $this->adminLevel
                  ]);

I’m pulling fullname directly from Authentication so I don’t need to load up my user data, as its the only field which can be changed by the user. And I access $loggedInFullname in my templates.

Question is then, how should I really be doing $this->Authentication->getResult()->getData()->offsetSet('fullname', $user->fullname); in my UserController edit() context?

To update user data use

$this->Authentication->setIdentity($user);

https://book.cakephp.org/authentication/2/en/migration-from-the-authcomponent.html#checking-identities

Aha yes, I saw that command and thought its what I was supposed to be using. Only thing is, it didn’t work. In that, my fullname field in my user table did update on the edit post - as expected, but it did not update the $this->Authentication->getResult()->getData()->fullname property, so maybe I’m accessing that incorrectly too? I don’t want to load the User model in my AppController just for that one field - not when it should already be present.

grab user identity in AppController::beforeRender() method like:

/**
 * @inheritDoc
 */
public function beforeRender(\Cake\Event\EventInterface $event)
{
    $authUser = property_exists($this, 'Authentication') && $this->Authentication->getIdentity() ? $this->Authentication->getIdentity()->getOriginalData() : null;
    $this->set(compact('authUser'));
}

then in any template echo $authUser->fullname

That comes close, but beforeRender in the AppController executes too late. You may note those values are being set in 2 places, once in the App object itself as I use them in my Controllers - which happens before the render, thus they are not defined. (The other place obviously being those $ php variables in the set() which is for the templates.)

So the answer is correct, in that my template will no doubt be getting the right value, but as my app crashes before then I won’t know! (Spefically accessing $this->loggedInID in UserController action login, and other areas/controllers.) I guess I’m just back to manually stuffing that field directly into the Authentication object via offsetSet() in the user edit submit/post and back to using AppController beforeFilter.


Edit: Putting $authUser = property_exists($this, 'Authentication') && $this->Authentication->getIdentity() ? $this->Authentication->getIdentity()->getOriginalData() : null; in the beforeFilter supplied old data, not the update from the user edit when $this->Authentication->setIdentity($user); was used there.)

simple use:

$authUser = $this->Authentication->getIdentity();
$this->set(compact('authUser'));


echo $authUser->fullname

Sorry, I didn’t explain myself properly. I don’t only use that variable in my templates, it’s also used in the controllers. (Setting the var [ via set() ] is just so a variable can be used by the template - but I am not talking about that.) So although what you put does work for templates [albeit untested], it does not work for the controllers.

Specifically the line in my AppController: -

$this->loggedInFullname = $this->isLoggedIn ? h($data->fullname) : "";

 ( where $data = $this->Authentication->getResult()->getData() )

is setting an object property of the application controller, which I can then use in my other inherited controllers, in their actions.

For whatever reason $this->Authentication->setIdentity($user) is either not updating my user fullname property, or its happening after beforeFilter executes. So that any reference to any of my custom $this-> properties is undefined when declared in the beforeRender as that is executed after the control actions.

Let me know if I have still failed to explain my question and I can create a proof-of-concept.