After completing the authentication tutorial I want to see whether and who is logged in.
Only the following from the authentication tutorial gave me a clue where the current user is stored:
However, this is within the ArticleController object.
How to access the identifier globally and how to echo this into the header continuously?
From this follows the desire to have a log-out link referring to the logout() function in the UserController. How can this be accessed from âthe general headerâ (which includes the home logo, API and Documentation)?
I quite doubt whether this basic question is not asked before, but I couldnât find it.
You can use Router::getRequest()->getAttribute('identity') anywhere in the system. Or, maybe better, have a universal beforeRender function in your base controller class which uses $this->request->getAttribute('identity') to set what you need as a view variable.
Thanks . I assume âbase controller classâ refers to AppController.php? And does that beforeRender needs the same setup as beforeFilter?
public function beforeRender (\Cake\Event\EventInterface $event)
{
parent::beforeRender ($event);
$this->request->getAttribute(âidentityâ)
}
Echoâing the identity doesnât work since it is not convertible to a string. I donât understand how to setup the view of the common header. The example of set()->view is in e.g. ArticlesController.php where functions/controllers refer to a specific URL view.
From debugging I learned that the to-be-printed email is stored like this:
object(App\Controller\ArticlesController){
âidentityâ => object(Authorization\Identity) {
[protected] attributes =>
[protected] identity => object(Authentication\Identity) {
The variable $identity will now be available in any view that gets rendered by this request, including the specific view for the action being run, any elements it might call, and, most importantly for the purpose at hand, your layout.
Documentation of the identity object states that âThe identity object provides ArrayAccess but as well a get() method to access data. It is strongly recommended to use the get() method over array accessâ, so getting the email address in a view should be as simple as $identity->get('email'). Do remember that getAttribute('identity') may return null if the user is not logged in, so be sure to check for that scenario, e.g. along these lines:
That is a clear explanation, thank you very much. I donât understand the need for the range of event handlers, but the basic understanding is more important for now. However, the set variable is unknown in the view ( [ Notice (8)](javascript:void(0);): Undefined variable: identity [ APP/View\AppView.php)
AppController.php
public function beforeRender(\Cake\Event\EventInterface $event){
parent::beforeRender($event);
$this->set(âidentityâ, $this->request->getAttribute(âidentityâ));
}
AppView.php
public function initialize(): void
{
echo $identity ? $identity->get(âemailâ) : âNot logged inâ; #echo(âa la playaâ);
}
Is this due to the difference between Event $event and the way I used it ? (which was necessary to comply with a Controller file, probably by using the initial bake all command)
Have you confirmed that the beforeRender function is actually being called? There are various scenarios which might be preventing that, and troubleshooting those is very different from troubleshooting why the set doesnât appear to work.
I thought the beforeRender to be automatically triggered. I called it explicitly in the initialize of AppController by $this->render(); which is obviously not the right way, based on the occurring errors.
Yes, the beforeRender event should be automatically triggered and sent to your controller at the appropriate time in the request lifecycle, which is not during initialization. You should only need to create it, not call it.
The question is whether your function (which youâve included above) is being called. There are, as I said, things that might stop that from happening. I donât want to dive into theoretical possibilities related to that if itâs not the actual problem, though, as it only muddies the waters. So, first check whether your function is being called, yes or no, and we proceed from there.
Oh, I see the problem! Youâre trying to reference the $identity variable in a function inside AppView. Thatâs not so much âa viewâ as âthe class the builds the viewâ. It works like any other class and function, so youâre trying to reference a variable that wasnât declared, with the expected result. Where $identity will be available to you is in places like src/Template/Users/view.ctp or, since you want it everywhere, src/Template/Layout/default.ctp. Those files are executed by the View class, in a context thatâs been specially set up with all the variables that youâve set.
The default.php template is indeed the file I was looking for, containing the lay-out of the âDocumentationâ and âAPIâ. Itâs hard to see the relation how the $this->set() in a Controller.php is enabling us through the View.php to have it available in the templates. The template comment gives a clue: * @var \App\View\AppView $this
Anyway, I got it working, thanks again!
To conclude for anyone that wants to do the same: AppController.php :
public function beforeRender(\Cake\Event\EventInterface $event){
parent::beforeRender($event);
$this->set(âidentityâ, $this->request->getAttribute(âidentityâ));
}
templates/layout/default.php :
in top PHP code section : $logged_label = $identity ? $identity->get('email') : 'Not logged in';
and in div: <div class="top-nav-links"> <?= $logged_label ?> </div>
(Direct PHP in the div does not seem to work: <div> <?= echo $identity ? $identity->get('email') : 'Not logged in'; ?> </div> )
Not sure whatâs not clear about controllers setting view variables. Itâs documented here. The documentation is short, because itâs a pretty simple concept, I think.
Direct PHP should work fine. The problem is that <?= and echo are redundant. Either <?php echo $identity... or <?= $identity...
since in UserController.php the view controller/function takes input ($id =null), I thought the following would make even less sense: $logged_ref = $identity ? $this->['action' => 'view',$user->($identity->get('id')]) : $user->login() ;
The error remains nevertheless Record not found in table "users" with primary key [NULL]
I donât know if the HTML helper is a better solution, but since the Documentation and API are also designed by <a> I thought of keeping that consistent for layout.
I have no knowledge about ternary operator performance, but your solution was indeed what I meant by using CakePHP methodology. I stored this code in a variable such that the code doesnât need to be inside the html.
However, I donât understand why this works and does not result in the same error of Record not found in table "users" with primary key [NULL] since I thought this was due to the view($id=null) in UserController.php.
So I see from this that the current user and the Users functions can be accessed through controller (whereas $user is unknown). I made a new topic since I canât apply similar access in the index View of Articles.
Itâs not about the performance of the ternary operator, itâs about readability and maintainability of the code. This if is quite possible to write with the ternary operator, and the performance would likely be identical, but this version is much easier to understand at a glance.
You never said what specific line of code was causing the primary key error, so I canât really comment on where that was coming from.