My code is evaluating to true for both ifelse conditions

The users of my website can complete a survey and have the option to publish it on their biographical account page. So if the publish field in the surveys table is 1, that means they want to publish it. I loop through all of the users on the biographical index page and show that they either published a biographical page, a survey or don’t publish a survey or a bio. Problem is that the one user that published a survey also shows up as publishing a bio. The third option to show that the bio and survey are empty and the one user that has an empty survey and bio gets displayed twice not once. I’ve tried different iterations of return, break, and continue and continue worked for the other conditions to some extent but not for the user that has publish == 1 (publish true) and not for the user that has an empty bio and survey.

In templates/Bios/index.php

foreach ($users as $user):
foreach ($surveys as $survey):
foreach ($bios as $bio):

if ((int)$survey->publish !== 0 && (int)$survey-> publish == 1 && (int)$survey-> publish !== false && $user->id == $survey-> user_id && $user->id == $bio->user_id) :
SURVEY PUBLISHED
elseif ((!isset($survey->publish) || (int)$survey-> publish == 0) && $user->id == $bio->user_id && empty($bio->body)) :
BIO AND SURVEY IS EMPTY
elseif (((int)$survey-> publish === 0 || (int)$survey-> publish !== true || (int)$survey-> publish == false || (string)$survey-> publish == “null”) && $user->id == $bio->user_id && !empty($bio->body)) :
BIO PUBLISHED

continue 3;

endif;
endforeach;
endforeach;
endforeach;


In PHPMyAdmin
the publish field in the Surveys table:
tinyint(1)
Null yes
Default NULL

In SurveysTable
$validator->integer(‘publish’)->notEmptyString(‘publish’);

I know that true is a boolean, I just wanted to cast it as an integer

I don’t understand your whole code, but if your goal is to show user based info and for some reason you don’t want to ask database for each user in separate query, I think you should:

  1. build user table (in php array) like ```$userArray[user_id] = [‘survey’=>false,’bio’=>false]
  2. iterate via $surveys, set opions above
  3. iterate $bios, set options above
  4. eventually iterate $userArray and decide what you should display.

I’m not using an array, I’m using database queries. This is what I have in my controller:

$this->set(‘bios’, $this->paginate($this->Bios));

$surveys = $this->fetchTable(‘Surveys’)
->find()
->select([‘Surveys.id’, ‘Surveys.publish’,‘Surveys.user_id’])
->distinct([‘Surveys.user_id’])
->contain([
‘Users’ => [
‘fields’ => [
‘Users.id’,        // Must include the primary key
‘Surveys.user_id’ // Must include the foreign key from the parent table
]
]
]);

$this->set(compact(‘surveys’));

$users = $this->fetchTable(‘Users’)
->find()
->select([‘Users.id’, ‘Users.contributor’])
->distinct([‘Users.id’]);

$this->set(compact(‘users’));

I know you don’t use array, I suggest you should start (build it) based on query result.

Why don’t you do something like this:


$query = $this->Users->find()->contain(["Surveys","Bios"]);
foreach ($query as $q)
{
  $surveyPublished = false;
  foreach ($q->surveys as $s) {if ($s->published) {$surveyPublished=true;break;}}
  $bioExist = !empty($q->bios);
  //now you have 2 simple variables, connected with user
  //and don't waste time for multiple nested loops
}

Maybe try to describe what is final goal, give some example. Do you want to see those text SURVEY PUBLISHED, BIO AND SURVEY IS EMPTY, BIO PUBLISHED on your page, or is it only demo for forum?

I assume that every survey and bios is linked to the user?

1 Like

Thanks Jarekgol, I will try out your code. I uploaded a screen shot of the project. I changed the names and pictures to anonymous users. The first item is a user who published a survey and the other items are from users who had bios.

Hi Jarekgol. I haven’t been able to understand the code you sent me and I keep logging warnings when I try to implement it. Can you give me some more clues or maybe you can provide a link to a tutorial that shows your type of code?

Notice I use 3.1 version everyday so my code may not fit 1:1 to newer cakes.

Now, first question is, do you want make your view based on users? Like one row (this pink box from screen) per user? That what I understand from this screen.

Or do you want to have a mix of users, bios and surveys on one screen so viewer can browse trough everything? (I doubt it, but it seems so based on your first code where you have separately fetched users, bios and surveys).

If just want add to those pink boxes short info about if user published something, I think my code (approach) from post #4 should be OK. The idea is you take users from your database and ask DB to join (using cake “contain”) surveys and bios of each user to his entity.
Have you ever use contain in cakephp? If you need more specific help with errors and syntax you must give us those errors, exactly code that make them, version of your cake, also schema of DB tables could help (src/Model/Table/YourTable.php)

And more clues to my code: I assume that you are in UsersController so we’ve got working $this→Users I assume that surveys and bios are linked via models to users. Check something simpler:

$query = $this→Users→find();
$rows = $query->toArray();
debug($rows);

You should see your every user (I don’t know how many you have them).
Then you can add $query->contain(["Surveys"]); and you should see users with their surveys.
Also my code from #4 is different approach than from #2 so don’t put them together (at least not 1:1)

What is surveys in this line of code? field, key, value, array, entity, etc? What does this line of code do?

$q will be a User entity. $q->surveys will be an array of Survey entities that user has done (empty array if there are nonw). $q->bios will be an array of Bio entities for them. If one of these is a hasOne association instead of hasMany, then it’ll instead be like $q->bio which will be a single Bio entity, or null if there isn’t one. This is all very standard behaviour from the contain method.

1 Like

Exactly as Zuluru said. Also remember that debug() is your friend. I most of the time put there everything new that I’m writing, watch the structure and adapt for it.
If you write debug($q) you should saw to your own eyes what I had in mind with my solution.

Btw. we use here “cake conventions” which in short give you less writing (of code) if your names (table names, foreign key in sql, models, etc) follows the convention.
What is nice about cake is that you don’t have to use it and can define most of it by hand, but this a lot more work to do.

Why is the convention to give the user entity a dollar sign in front of it but the survey and bio entity don’t have a dollar sign in their syntax

That’s not a convention. That’s PHP object oriented syntax. $q is a variable. $q->surveys is the surveys property of the variable $q. $q->$surveys is something very, very different, which I will not get into right here, because it will only confuse things, and has no bearing whatsoever on the main question.

but when I googled php arrow notation I got the result “The arrow operator → is specific to objects and cannot be used to access elements of an array (for arrays, square bracket notation is used).” So the google result says it can’t be used for arrays.

I know how to use the arrow operator now. I just wrote in my controller:

 foreach ($query as $q) {
       if (!empty($q->survey)) {
            echo $q->contributor . ' published the survey ' . $q->survey->publish;
        } else {
            echo $q->contributor . ' didn\'t take the survey.';;
        }
    }  

Right. In $q->surveys, $q is an object, and surveys is a property of it. -> is used to access the property of the object. That property happens to be an array in this instance, so you can do things like $q->surveys[0]. That in turn would be an object, so you can do $q->surveys[0]->id.

Thanks Jarekgol and Zuluru. All of my complicated code has been reduced to a simple loop thru the array:

foreach ($query as $q) :
if (!empty($q->bio)) :
if ($q->bio-> user_id == $q->id) :
if (!empty($q->survey) && $q->survey->publish ==1) :
echo $q->contributor . ’ published the survey ’ . $q->survey->publish . ‘’;
elseif(!empty($q->bio->body)) :
echo $q->contributor . ’ published their bio ’ . ‘’;
else:
echo $q->contributor . ’ hasn't written a bio yet’ . ‘’;
endif;
endif;
endif;
endforeach;

So it is an ArrayObject :smiley:

cake when retrieving data from DB builds entities for you and uses this stuff. Nice thing, you can access your properties via → or [‘key’] and they are easy translate to json.

ps. you don’t like curly brackets { } aren’t you ? Add some indent at least, it will be easier to read.
Anyway, I’m glad I could help.

In my local text editor the code is indented but when I pasted it over to the forum the indentations disappeared. So I tried to edit my post but the website editor wouldn’t allow me to use tabs to indent the code.

I tried to include an element like this
echo $this->element(‘thumb’, [‘q->bio’ => $q->bio]);
but it doesn’t work and I haven’t been able to find the correct syntax.