I want foreach loop to execute only one time

The user_id shows up three times in the mealplans table so this prints out the name of the contributor three times. How can I re-write this so it only prints out once?

I have the following code in templates/Mealplans/index.php:

<h1>Meal Plans for 

<?php 

foreach ($users as $user):
foreach ($mealplans as $mealplan):

if ($user->id == $mealplan->user_id){

echo $user->contributor;

}
endforeach; 
endforeach; 
?></h1>

This displays:
Meal Plans for MaureenMaureenMaureen
in the browser

You’re better off asking what output you want.
Did you only want the list of users who have a meal plan?
Did you want to show what all those meal plans are?
There may well be a faster & simpler way of doing what you want here.

I suspect you should be building this as a nested query in the controller, and just passing that result set to the template (have the controller do the heavy lifting) - then you need only loop over that result - your loop is complexity O(n^2).

If you can post your table structures of both users & mealplan we can show you what code to write to make it faster and cleaner.

To answer your question outright, put a break; line after your echo. That is the answer, but just saying its the wrong approach.

The code is just wrong. I only want to print out the name of the logged in user but I don’t know how to do that.

Users Table

id
email
contributor
password
password_confirm
birthmonth
created

Mealplans Table

id
user_id
draggables
end_date
event_date
total_calories
created
modified

If you’re only looking to output one user, why do you have $users instead of just $user? As @Jawfin said, it seems like maybe it’s your query that’s wrong, moreso than your view.

Assuming you’re using the authentication you will have the user_id in that object.

I only know CakePHP 4, so not sure if it’ll be different in other versions, but you can get that directly in any controller. You could do something like this AppController in beforeFilter() so it’s available in all templates and all other controllers.

        $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->contributor = $this->isLoggedIn ? h($data->contributor) : ""; //should work if your Model/Entity/User.php has this in $_accessible
        $this->set(['isLoggedIn' => $this->isLoggedIn,
                    'loggedInID' => $this->loggedInID,
                    'loggedInEmail' => $this->loggedInEmail,
                    'contributor' => $this->contributor,
                  ]);       

This allows access to these variables in the template as you’re doing, but it can be done inline: -

<!-- HTML -->
<h1>Meal Plans for <?= $contributor ?></h1>

And in all your actions in all your controllers those fields can be accessed as they are set here within the parent app object, like $this->contributor which can save you loading the User model and doing a find just for a field which is already present in your authorization object.

This all means, of course, that your actual title of your question is no longer relevant, as we aren’t even looping, let alone a nested one, to get this info.

Please don’t take offence to this next comment: but this is programming, and I feel you should get some formal training for your code design, object oriented, algorithms, usage & scope of variables - just the whole gamut really :\

1 Like

Thanks, Jawfin. I wasn’t able to get it to work.

Bah, sorry to hear that. If you could turn on debugging and see if its firing up any errors. As you’ve changed the user table from the CMS tut make sure you’ve cleared the cache so the new structure comes through, via: bin/cake cache clear_all

And check your user entity actually has the contributor field. If its how you think it should be, try simpler, comment out the code except for say the isLoggedIn stuff and pass that variable and echo it. Then try for the email, etc. Get it working on something simple then incrementally expand to what your goal is.

Imagine CakePHP as its own language; you’re not going to get by without understanding it - its not friendly to just dumping in pasted code found elsewhere. Its like writing a novel in a language you don’t know and that was the approach taken. (Actually, that analogy applies to all languages!)

Thanks, Jawfin
When I do <?php dump($contributor)?> it prints out ^ “”
There is noone in the users table with that contributor name
When I use debug($contributor);, it doesn’t print out anything.
In the tutorial: Debugging - 4.x
He writes: “Output from this function is only shown if the core $debug variable has been set to true.”
Where can I find where to set $debug to true?

Use debug($this->contributor); in your AppController after the line where you set it’s value.

There’s little point in doing it in the template as you know it’s not getting that far anyway. But it is handy if you need to dump a whole object.

If you’re working in your own play environment you can enable the debugger in config/app_local.php by setting ‘debug’ & ‘DebugKit.forceEnable’ to true. You may also need to set ‘DebugKit.ignoreAuthorization’ to true too if you are testing and want to bypass authorization.

I still get the feeling you’re trying to get this to work via brute force and not understanding it.

Also, never, ever set those debug variables to true on a web-facing site. There are ways you can debug live - and if you need to do that make another thread in that regard.

Thanks, Jawfin

When I do debug($this->contributor); in the AppController I get the message: Cannot modify header information - headers already sent All of the sites that I have googled say this is a result of re-directing. When I do var_dump($this->contributor); in the AppController, I get: string(0) “”

I’m just replying now as I won’t get the chance later. Maybe beforeFilter() is not the place to sneak a debug in; perhaps try putting it at the start if the action the controller its using. Also check you’re using var_dump [not dump] for when you’re not using debug (but in the templates only).

The redirect may possibly be the authorization kicking in, so check ‘DebugKit.ignoreAuthorization’ is true too. I may be missing something fundamental in my attempts to help, so hopefully someone else who knows more may have a idea!

I think the reason that var_dump() is returning string(0) “” is that nobody is logged in. I get the error: “Invalid email or password” when I try to log in so that has to be fixed as well.

If you can’t log in, it’s no surprise at all that there would be no details available about the currently logged in user. :slight_smile:

I added password hashing and now I can log in. The contributor’s name now shows up at http://localhost/mealplans/index