Change element's text in CakePHP - php

I have an element called userbar on every page - it tells the user if he/she is logged in or not. I created this element and echoed it in default.ctp:
<?php echo $this->element('userbar', array('text' => 'You are not logged in.')); ?>
Now it shows on every page. However, I can't find anywhere how to change this text. For e.g., I would like to access this element from some controller and change it. How?

You set a view variable and then use that.
<?php
class MyController extends AppController
{
function myaction () {
$this->set ('my_var', 'You are not logged in');
}
}
?>
And then in the view:
<?php echo $this->element ('userbar', array ('text' => $my_var)); ?>
Considering this is something you'd do on every page request its best to put it in the AppController::beforeFilter().
There are other ways to do this. But if you render the element in the controller you still need to set a view variable and echo that in the view.
Hope this helps.

I think that vanneto did a good job on answering the question very specifically. But based on my opinion what happens here is a design flaw. That's why I add this answer to give you another option on how to approach this question. Because I see this kind of solutions and on the longer run they cause issues.
The case is a logged-in or logged-out text.
Let's say that you use the Auth component:
http://book.cakephp.org/2.0/en/core-libraries/components/authentication.html
We will start at the controller, likely you have something like this in the AppController:
public function beforeFilter() {
parent::beforeFilter();
$this->set('userIsLoggedIn', AuthComponent:: loggedIn());
$this->set('loggedInUser', AuthComponent::user());
}
So what this does: At every request it sends the logged in user to the view. Now you could say the controller could have an if statement to detect which text should be sent out but it's not really necessary.
In you element you could do that also.
So in your element put something like:
if($userIsLoggedIn) {
echo 'User is logged in.';
}else{
echo 'You are not logged in!';
}
Generally we move a bit more to helper to implement this kind of logic because they are classes which have more options for well styled coding. But it's also doable simply with an element.
So now you got the texts right. Then you get to the point: Does a static text belong to the element? No, it does not. So what would improve it is to implement it like:
if($userIsLoggedIn) {
echo __('User is logged in');
}else{
echo __('User is not logged in');
}
That way you can put the static texts into your .po files. If you don't know what they are:
http://book.cakephp.org/2.0/en/core-libraries/internationalization-and-localization.html
The element can now be used also if your site becomes multi language for example. Or you could let your textwriter edit the texts without touching the source code.
As you see it's a different approach but I think it will give you more clear code. It decoupled the code, the controller does his task, the element does his task and the text is also seperated out because it doesn't belong hardcoded in the views.
In terms of code it's not much more so I would strongly advise some solution which looks like this. Could also be done with a helper.
Some sources on this kind of approaches:
http://en.wikipedia.org/wiki/Object-oriented_programming#Decoupling
http://en.wikipedia.org/wiki/Single_responsibility_principle

Related

add values to cakephp layout from model app wide

thanks for reading, I know the question might sound fairly common, and well I wont deny the fact that maybe I'm just formulating what i want wrongly.
Lets start by shooting it straight, then specifying.
I have a cakephp app with 2 layouts, one layout renders the whole "public" page, and lets call it admin "admin" layout that will render only actions to authenticated users.
in my admin layout, I am printing an element which is the navigation bar.
what I want to do is, without setting on every single controller, the options to set a variable containing the navigation bar values (yes dynamically filled from a specific model)
I want to be able, to set a variable, which will contain a list of values gotten from a model.
The Model is called "Section", which is a table, that contains a list of "sections" of the application.
this navigation bar, needs to print the values of each section, so I need them to be dynamic, hence, I think (again I might be wrong) i need to set that variable somewhere, to make it available to the element, so when the layout "admin" is rendered, the menu bar, is actually filled with the available values of the sections.
I tried doing a Configure::write on AppController, but no dice, it just allowes me to use a variable on controllers, when what I want to do is, loop through the arrah "sections_for_menu" or whatever we call it, and then print the options avaliable on the menu bar.
so you are a bit more comfortable with the idea, the nav bar is a bootstrap based "navbar" with "dropdowns".
i should be able to
<ul class="mycoolclass">
<?php
foreach($sections as $section) {
echo '<li>" . $section . "</li>';
}
</ul>
and thus, printing each value on a new list with its link, and whatnot.
I have been reading with no luck, and have to admin that I am myself fairly new to cakephp, been using it for no longer than 2 weeks.
Any help reaching a solution to this need, is highly appreciated.
UPDATE:
Hi #nunser, thank you very much for your reply.
indeed I'm using an element
this is my layout "base"
<body>
<?php echo $this->element('admin_navbar'); ?>
<!-- container -->
<div class="container-fluid">
<!-- , array('element' => 'flash') -->
<?php echo $this->Session->flash('flash'); ?>
<?php /*echo $this->fetch('content');*/echo $content_for_layout; ?>
</div>
</body>
I'll try your suggestion and see how it goes
I have a controller "SectionsController" which is in charge of well all Section related actions on the app, what I need is to set in the global variable, a list of sections, so I can print the link inside my navbar!
lets assume the following scenario
$this->set('sections_for_navigation', $this->Section->find('list', array('fields' => array('id', 'name'))));
so then i can access the variable $sections_for_navigation from my element, and render the list of sections.
[19-02-2014 - update] tried it.
based on what #nunser suggested, im actually able to, beforeFilter, setting the value, as if i var_dump it, it actually gives me the array as i expected.
public function beforeFilter(){
$this->loadModel('Section');
$secciones = $this->Section->find(
'list', array(
'fields' => array(
'id',
'name'
)
)
);
$this->set('navigation', $secciones);
Then call
public function beforeFilter() {
parent::beforeFilter();
}
from the controllers, did the trick!, now, do i have to add a beforeFilter to every controller to share the navigation through all the app?, is there a way to avoid having to add that method to every single controller? (not that it bothers me, so far it does what i need,which is actually great)
For those kind of navigation things, I do it in beforeFilter or beforeRender in the AppController.
public function beforeFilter() {
//queries and stuff that gets the array for navigation
$this->set('mainNavigationBar', $navigation)
//remember to pass that variable to the element in the view
}
As of to where, beforeFilter or beforeRender, it depends on what type of rule you want to stablish. For example, if you will have same elements for navigation everywhere, be it that the user has permission or not, or if you might want to alter the navigation variable depending on the action being executed, I'd go with doing it in beforeFilter. That way you can tweak things in navigation if, for example, the user doesn't have permission to access any Section (totally making up the model relation here). Though for that, you might want to keep access to the navigation array in the controller.
Tweaked example
protected $_mainNav = array();
public function beforeFilter() {
//queries and stuff that gets the array for navigation
$this->set('mainNavigationBar', $navigation)
//remember to pass that variable to the element in the view
$_mainNav = $navigation;
}
//other controller
public function randomAction() {
//some reason that makes you modify the navigation
unset($_mainNav[0]); //making that up...
$this->set('mainNavigationBar', $navigation)
}
Now, if you won't change the navigation values (once you've added them dynamically), then go with beforeRender, that way you can check permissions and other stuff before bothering with queries for navigation (example to follow would be the first one).
If values of the navigation change per controller, overwrite the function like
RandomController
public function beforeFilter() {
parent::beforeFilter();
$_mainNav = array('no nav'); //example
}
And that's it. Don't know if you need more detail than that, if so, please explain you problem a little more. Oh, and you mention "to make it available to the element", so I'm guessing you're using an element for the navigation bar. If not, please do.

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.

Access Controller's action variable in layout in ZF

I want to access the variable in layout in zend framework, how can I do that. I searched a lot but can't find any thing useful or helpful for me. Below are the links that I already tried so admin please don't mark this question as duplicate one..
Thanks..
Zend Framework 2 - Layout and variable
access controller action variables to zf2 layout
Senario
I have a link in layout.phtml that I want to display on conditional bases. Like some user of my sites cannot see that link but other can do. That condition comes from the databases that I have but I don't know how to access that in layout.phtml
Example
<?php if($this->check == true) {?>This Link<?php } ?>
if $this->check == true than show the link otherwise not.
Pass the variable from the action to the view like
$this->view->check = true;
Then access it in the view like $this->check and do the checking
if($this->check){
//Do something
}
else{
//Do something
}
I got the solution of my problem
write the below code in IndexController's init Function
$this->_helper->layout()->myvar = $someValue;
and access it in the layout by this code
$this->placeholder('Zend_Layout')->myvar;
One has to so this for each controller that he/she has in his/her application. Otherwise will get an error regarding undefined variable.
Reference:
http://framework.zend.com/manual/1.12/en/zend.layout.quickstart.html
Line 15 of first code listing....

cakephp - callback function for every controller action to set available navigation links

I'm trying to achieve something so basic in my cakephp-app, that I'm quite surprised I didn't easily find a solution to it...
What I just want to do is to set available links for my app's main navigation depending on the user being logged in or not and if he is, depending on his role (which is stored in the users-table).
So basically a function like this:
if(!$this->request->is('ajax')) {
if(_user_is_not_logged_in_) {
$availableNavItems = array('login','help');
}
else {
if($this->Auth->User('role') == 'user') {
$availableNavItems = array('something','something else','whatever','help','logout');
}
elseif($this->Auth->User('role') == 'admin') {
$availableNavItems = array('something','something else','whatever','admin-tool','user management','help','logout');
}
}
// set available pages for layout
$this->set('availableNavItems',$availableNavItems);
}
In my layout of course I would create a navbar with links to those available pages.
The only question I have - where would I put code like the above? Is there any callback-function I could put in AppController which cakephp calls on every request?
And, what would be a good way to check what I wrote as pseudo-code "_user_is_not_logged_in_" above?
Thanks in advance for any help!
if(_user_is_not_logged_in_) {
could be written as
if(!$this->Auth->user('id')){
And you could put the function in your beforeRender method of your AppController, which executes on every request, right before the view is rendered.
Also of note is the beforeFilter method, which gets called early, before the controller logic executes. You shouldn't need it in this case, but it's worth knowing about.

Admin panel - what is the best way to display "static" data in the layout?

I'm about to write a admin panel for my CMS written in CodeIgniter. There will be some user information visible at all time - both in the layout's header section and the sidebar. I'm used to do it in a way that I personally hope and think could be done a lot easier, since I'm tired of sending the same parametres to the view over and over again, when it's dynamic data that needs to be displayed on every page anyways (such as unread messages, username, name, status, etc).
I'll need controllers and models, I know that, but do I have to pass, just for an example, the user's username, unread messages etc. every time I need to load a view? Should I do some kind of library for this?
Now my question is: How would I do it when it comes to best practice and for making it easy to maintain in the future?
I hope my question is understandable :)
Personally, I would extend the Controller library (create a MY_Controller by following the guidance at the bottom of Creating Libraries at codeigniter.com).
You would use your model etc as normal. Then you would create a private function in your MY_Controller class to get the relevant "global" data and call
$this->load->vars('everywhere_data', $data_from_relevant_models);
which would make the data available to all views called from that point on as $everywhere_data. Then add a reference to that function in the constructor of MY_Controller, perhaps with a conditional checking for the user to be actually logged in.
If it's complex to collect and get all that data, you might write a library to handle it for you, but the 'controller' part would still be done by MY_Controller: i.e. to get the data and then use load->vars() to publish it to the view.
As a quick and untested example, MY_Controller would start something like as follows:
<?php
class MY_Controller extends Controller
{
private $logged_in_user;
function MY_Controller()
{
parent::Controller();
if( $this->_logged_in_userid() > 0 )
{
$this->logged_in_user = $this->_get_user( $this->logged_in_userid() );
$this->load->vars('logged_in_username', $this->logged_in_user->username );
} else {
$this->logged_in_user = false;
}
}
...
}
Note that things like _logged_in_userid() would access the session for you (e.g. return $this->session->userdata('logged_in_userid');), and _get_user() would access the relevant models.
Finally, you would have a view that accesses $logged_in_username (or everywhere_data in my first example) which you would call into your headers etc. This leaves your normal controllers uncluttered so that they can focus on delivering their specific functionality, stops you rewriting your code several times AND maintains the MVC ideals.
You could create a View just to hold the information and get it from a $_SESSION variable in the View itself if you want to keep it all in one place.

Categories