Link to home
Start Free TrialLog in
Avatar of ericcchamberlain
ericcchamberlain

asked on

Conditional Logic Problem (Pseudocode or PHP)

I need help with programming the conditional logic for the following problem in PHP:

File: report.php
-------------------------
This file lists ~20 questions each with multiple checkboxes to end user. The end user will select various checkboxes for various questions and on submit the page will return the total count of users that fit that criteria.

Logic:
If the end user selected multiple options in the same question then the options are “OR’ed”. EX: Return count of all users who selected Option 1 OR Option 3 on Question 5  
If the end user selected options from multiple questions then the questions are “AND’ed”. EX: Return count of all users who selected Option 4 on Question 2 AND Option 1 on Question 7

Advanced test case: Return count of users who answered (Option 1 OR Option 3 on Question1) AND (Option 2 OR Option 3 on Question 4) AND (Option 1 on Question 7).

The report.php file will post to process.php which I need to develop.

First, I need to capture all the variable data. I was going to _REQUEST all 100 or so variables but then thought about using explode on the _POST and loading the responses into an array. Any recommendations?

Then, I want to construct the query that will handle the above conditional logic. I was going to construct a string ($where) that contains something like this:

WHERE (q1=1 || q1=3) AND (q4_2 = 1 || q4_3 = 1) AND (q7 = 1)

Please help me understand the best way of implementing this. PHP or psuedocode would really be beneficial. Your time is much appreciated and thank you in advance.
Avatar of Ray Paseur
Ray Paseur
Flag of United States of America image

Have you started any code yet?  How strong are you in PHP programming?
Avatar of Aaron Tomosky
What database is the information in? Mysql?
Avatar of ericcchamberlain
ericcchamberlain

ASKER

Hello Ray, thank you for your reply. I am an intermediate level PHP programmer with 1 year of experience in programming with PHP and a comp sci background.

I have not started any code yet because I'm not sure what the best way to implement this would be. I started two different approached then thought about how extremely inefficient / tedious this would be and that there had to be a better way.

The problem I'm having is the mixing of AND and OR logic into groups, and keeping track of when to add the logic operators. I though about doing this as a multi-dimensional array such as:

Exploding the $_POST variable to and dumping it into a multi-dimensional array like: $array[question][option]  ... then constructing where SQL WHERE string by looping through the array so that the options are OR'ed and the questions are AND'ed.

Hello aarontomosky:

You are correct, the database is MySQL. I'm working on a LAMP stack.
ASKER CERTIFIED SOLUTION
Avatar of Ray Paseur
Ray Paseur
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
I would use the bitwise operators to make each question one integer. If you've never used bitwise operations, then this is a good time to learn.
Quick tutorial
1 as a byte is stored as 00000001 (integers have more bytes, but I don't want to type that many 0s)
2 is 00000010
4 is 00000100
8 is 00001000
etc
So if you set each option to a power of two and bitwise or them together (using the | operator) then you can keep each question as one integer.
8 | 2 = 00001010 etc
The & operator does the same thing except it ands them. So 00000111 & 00001110 = 00000110
The other operator that's useful here is << which shifts the bits to the left
So 00000001 << 1 = 00000010
and 00000001 << 3 = 00001000
$a << $b is the same as $a * 2^$b only much faster.

So if a question has n options (must be less than the number of bits in an int so a 4-byte int can have 32 options)

int $q1 = 0
for i = 1 to n
{
  if(Option i is true) then
    $q1 = $q1 |  ( 1 << (i-1))
}
Now to compare your $q1 with the stored $Q1just compare $q1 | $Q1. If it's > 0 then one of the options matches. If $q1 = 0 then no option was selected and it can be ignored.

Where ( ($q1 == 0 || $q1 | $Q1 > 0) && ($q2 == 0 || $q2 | $Q2 > 0)
I'm not that good at PHP at all. But in C 0 means false and !=0 means true so you could shorten it to
Where (!$q1 || $q1|$Q1) && (!$q2 || $q2|$Q2)
@TommySzalap… in PHP, 0 == NULL == FALSE, etc.  Double equal signs are used to test for equivalent loosely-typed meanings, whereas triple equal signs are used to test for identical meanings.  0!== NULL !== FALSE, etc.

TRUE, non-zero values, not NULL strings all evaluate TRUE.
Thank you Ray_Paseur and TommySzalapski for your insight. I am not sure if using bitwise operators makes sense for this senario but I have found both of your responses helpful.

I wrote the following to show you what I want to avoid doing, since it is tedious and inefficient. There must be a more elegant solution.

In the code below I am constructing the MySQL conditional logic to append onto the WHERE in the query that will return the count of users that fit that criteria.

 
<?php 
global $query; 

function group_string ($string) {
	$string = " (" . $string . ") "; 
	return $string; 
}

//Question 1 
if ( $_REQUEST["q1_1"] == 1 || $_REQUEST["q1_2"] == 1 || $_REQUEST["q1_3"] == 1 ) { 
	$temp = "";
	if ($_REQUEST["q1_1"] == 1) {
		$temp .= "q1 = 1";
		if ($_REQUEST["q1_2"] == 1) {
			$temp .= " OR q1 = 2";
		}
		if ($_REQUEST["q1_3"] == 1) {
			$temp .= " OR q1 = 3";
		}
	}
	else if ($_REQUEST["q1_2"] == 1) {
		$temp .= "q1 = 2";
		if ($_REQUEST["q1_3"] == 1) {
			$query .= " OR q1 = 3";
		}	
	}
	else if ($_REQUEST["q1_3"] == 1) {
		$temp .= "q1 = 3";
	}	
	$temp = group_string($temp);
	$query .= $temp; 
}

//Question 2
if ( $_REQUEST["q2_1"] == 1 || $_REQUEST["q2_2"] == 1 || $_REQUEST["q2_3"] == 1 || $_REQUEST["q2_4" == 1 || $_REQUEST["q2_5"] == 1] ) { 
	$temp = "";
	if ($_REQUEST["q2_1"] == 1) {
		$temp .= "q2 = 1";
		if ($_REQUEST["q2_2"] == 1) {
			$temp .= " OR q2 = 2";
		}
		if ($_REQUEST["q2_3"] == 1) {
			$temp .= " OR q2 = 3";
		}
		if ($_REQUEST["q2_4"] == 1) {
			$temp .= " OR q2 = 4";
		}
		if ($_REQUEST["q2_5"] == 1) {
			$temp .= " OR q2 = 5";
		}
	}
	else if ($_REQUEST["q2_2"] == 1) {
		$temp .= "q2 = 2";
		if ($_REQUEST["q2_3"] == 1) {
			$temp .= " OR q2 = 3";
		}
		if ($_REQUEST["q2_4"] == 1) {
			$temp .= " OR q2 = 4";
		}
		if ($_REQUEST["q2_5"] == 1) {
			$temp .= " OR q2 = 5";
		}
	}
	else if ($_REQUEST["q2_3"] == 1) {
		$temp .= "q2 = 3";
		if ($_REQUEST["q2_4"] == 1) {
			$temp .= " OR q2 = 4";
		}
		if ($_REQUEST["q2_5"] == 1) {
			$temp .= " OR q2 = 5";
		}
	}
	else if ($_REQUEST["q2_4"] == 1) {
		$temp .= "q2 = 4";
		if ($_REQUEST["q2_5"] == 1) {
			$temp .= " OR q2 = 5";
		}
	}
	else if ($_REQUEST["q2_5"] == 1) {
		$temp .= "q2 = 5";
	}
	$temp = group_string($temp);
	$query .= " AND " . $temp; 
}

//Question 3 
if ( $_REQUEST["q3_1"] == 1 || $_REQUEST["q3_2"] == 1 ) { 
	$temp = "";
	if ($_REQUEST["q3_1"] == 1) {
		$temp .= "q3 = 1";
		if ($_REQUEST["q3_2"] == 1) {
			$temp .= " OR q3 = 2";
		}
	}
	else if ($_REQUEST["q3_2"] == 1) {
		$temp .= "q3 = 2";
	}
	$temp = group_string($temp);
	$query .= " AND " . $temp; 
}

//Question 4
if ( $_REQUEST["q4_1"] == 1 || $_REQUEST["q4_2"] == 1 || $_REQUEST["q4_3"] == 1 || $_REQUEST["q4_4" == 1 || $_REQUEST["q4_5"] == 1] || $_REQUEST["q4_6"] == 1 ) { 
	$temp = "";
	if ($_REQUEST["q4_1"] == 1) {
		$temp .= "q4 = 1";
		if ($_REQUEST["q4_2"] == 1) {
			$temp .= " OR q4 = 2";
		}
		if ($_REQUEST["q4_3"] == 1) {
			$temp .= " OR q4 = 3";
		}
		if ($_REQUEST["q4_4"] == 1) {
			$temp .= " OR q4 = 4";
		}
		if ($_REQUEST["q4_5"] == 1) {
			$temp .= " OR q4 = 5";
		}
		if ($_REQUEST["q4_6"] == 1) {
			$temp .= " OR q4 = 6";
		}
	}
	else if ($_REQUEST["q4_2"] == 1) {
		$temp .= "q4 = 2";
		if ($_REQUEST["q4_3"] == 1) {
			$temp .= " OR q4 = 3";
		}
		if ($_REQUEST["q4_4"] == 1) {
			$temp .= " OR q4 = 4";
		}
		if ($_REQUEST["q4_5"] == 1) {
			$temp .= " OR q4 = 5";
		}
		if ($_REQUEST["q4_6"] == 1) {
			$temp .= " OR q4 = 6";
		}
	}
	else if ($_REQUEST["q4_3"] == 1) {
		$temp .= "q4 = 3";
		if ($_REQUEST["q4_4"] == 1) {
			$temp .= " OR q4 = 4";
		}
		if ($_REQUEST["q4_5"] == 1) {
			$temp .= " OR q4 = 5";
		}
		if ($_REQUEST["q4_6"] == 1) {
			$temp .= " OR q4 = 6";
		}
	}
	else if ($_REQUEST["q4_4"] == 1) {
		$temp .= "q4 = 4";
		if ($_REQUEST["q4_5"] == 1) {
			$temp .= " OR q4 = 5";
		}
		if ($_REQUEST["q4_6"] == 1) {
			$temp .= " OR q4 = 6";
		}
	}
	else if ($_REQUEST["q4_5"] == 1) {
		$temp .= "q4 = 5";
		if ($_REQUEST["q4_6"] == 1) {
			$temp .= " OR q4 = 6";
		}
	}
	else if ($_REQUEST["q4_6"] == 1) {
		$temp .= "q4 = 6";
	}
	$temp = group_string($temp);
	$query .= " AND " . $temp; 
}

echo $query;

?>

Open in new window


I'm looking for a more elegant way to constructing the following:
(q1 = 1 OR q1 = 3) AND (q2 = 1 OR q2 = 3 OR q2 = 4) AND (q3 = 1) AND (q4 = 1 OR q4 = 2 OR q4 = 3 OR q4 = 4 OR q4 = 5 OR q4 = 6)



SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
I missed the parentheses. Change line 28 to the following and it should be almost perfect.
$query .= "(".$temp.")";

There may be typos and such, but I think you can get it from there.