Re-run function if false - php

I'm working on code that takes a random value, checks if it's correct with a few checks and if it is, it'll return it. If it isn't, it's supposed to rerun the function untill one that does is found.
If the random value is correct it'll set a var to 1 like this: $chosen = 1; and then using a while loop it'll keep running the current function untill it's 0:
public function generate_chair($id, $optredenID)
{
$model = new Model_Shop;
// Get all the chairs for the given room
$chairs = $model->check_chair($id);
// Get an array of reserved chairs for a given event
$reserved = $model->get_reserved($optredenID);
do {
// If chosen = 0, all chairs are available.
// If chosen = 1, one of the chairs is not available
$chosen = 0;
// Create a new empty array
$rand_chairs = array();
// Pick a random chair
$chair = array_rand($chairs);
// Based off the amount chosen in the dorpdown, build array
switch($_POST['AantalPlaatsen']) {
case '1':
array_push($rand_chairs, $chair);
break;
case '2':
array_push($rand_chairs, $chair);
array_push($rand_chairs, $chair+1);
// Check if the chair chosen is the last chair in a row
// If it is, check for another chair
if($chair == 20 || $chair == 40 || $chair == 60 || $chair == 80 || $chair == 100 || $chair == 120 || $chair == 140 ||$chair == 160 ||
$chair == 180 || $chair == 200) {
$chosen = 1;
}
break;
case '3':
array_push($rand_chairs, $chair);
array_push($rand_chairs, $chair+1);
array_push($rand_chairs, $chair+2);
break;
case '4':
array_push($rand_chairs, $chair);
array_push($rand_chairs, $chair+1);
array_push($rand_chairs, $chair+2);
array_push($rand_chairs, $chair+3);
break;
}
// Check if one of the random generated chairs is in the reserved array
// If so, the chair is unavailable and new random must be generated
if( count(array_intersect( $rand_chairs, $reserved )) != 0 ) {
$chosen = 1;
}
} while ($chosen == 1);
return $rand_chairs;
What I wanted works now, but I'm wondering if anyone has a idea for another issue.
As shown in the switch-case, when the customer chooses 2 chairs and the first one is at the end of a row, it has to check for a new chair, because you can't spread multiple chairs over multiple rows.
The way I do this is with alot (too many) if statements. Does anyone know a better solution?

Why are you using recursion here? Why not just repeat the part of the function which you need to rerun?
do {
$chosen = 0;
// create a new empty array
$rand_chairs = array();
// Pick a random chair
$chair = array_rand($chairs);
...
foreach($rand_chairs as $key) {
if(in_array($key, $reserved)) {
$chosen = 1;
break; // oops, we need to rerun
}
}
} while( $chosen == 1 )
This uses a do-while control structure, which runs through the body at least once.
The break statement exits out of the while loop early, since the key has been found.
Additionally, instead of the foreach statement, you could use array_intersect():
if( count(array_intersect( $rand_chairs, $reserved )) != 0 ) {
$chosen = 1;
}

Faster algorithm would go something like this: you would run it one row of seats at a time, since "sitting at opposite ends of adjacent rows" isn't really "sitting together"...
Boolean seatsTaken()
int startsAt(), runLength()
For each row in seatsTaken
adjacent = 0
seat = 0
while not row(seat):
++adjacent
if adjacent > 0:
startsAt.push(seat-adjacent)
runLength.push(adjacent)
When this is done you have an array of all the blocks. Select only the blocks that are big enough (runLength() >= needed) and randomly choose one of them

Related

adding up sums of multiple variables in php

ok
so I have been stuck on this problem for a while and I'm sure there is a more elegant way of doing it.
I have 3 columns in a database -
Stand1 | Stand2 | Stand3
each column will either have a stand number (i.e D30) or 'Not Assigned'
What I need to do is count how many stands have been assigned to that customer.
For example :
D30 | not assigned | not assigned would = 1
D30 | B30 | E30 = 3
The code I have so far is
if ($row["stand1"] == 'Not Assigned') {
$stand1 = '0';
}
else {
$stand1 = '1';
}
if ($row["stand2"] == 'Not Assigned') {
$stand2 = '0';
}
else {
$stand2 = '1';
}
if ($row["stand3"] == 'Not Assigned') {
$stand3 = '0';
}
else {
$stand3 = '1';
}
I then thought I could try and count how many stand were assigned :
$standcount = $stand1 + $stand2 + $stand3
But when I print this out (everything else is in an array so loops through every customer) all I get is the total 3 for every customer.
I tried saving the data into an array like:
$standcount = array($stand1, $stand2, $stand3);
But I get the same result. I thought a foreach loop may work but not sure how to do it.
I would suggest you to:
Set the columns' default value to NULL, so that if no value is provided in an entry you'll have a null value instead of a string (that can contains different letters, as in your case). After that you can simply perform the isset() check against each value.
Use a function to avoid code repetition (the main source of errors), something like:
function check($value) {
return (isset($value)) ? 1 : 0;
}
$stand_1 = check($row["stand1"]);
$stand_2 = check($row["stand2"]);
$stand_3 = check($row["stand3"]);
If you instead want to use a string as "Not Assigned" or "NA", you can perform a case-insensitive check with strcasecmp() between the strings in case, for any reason, a value contains an extra space or a lower-case letter.
In this case the check function would be:
function check($str) {
return (strcasecmp($str, "NA") == 0) ? 0 : 1;
}
$stand_1 = check($row["stand1"]);
$stand_2 = check($row["stand2"]);
$stand_3 = check($row["stand3"]);

How to get which condition has failed if any in a single sql query

This might be odd or not... but I need to find out which condition out of 3 has failed if any...
I explain...
In my query I have 3 condition if all goes fine then no problem, but if one of those conditions fail I need to know which condition or conditions have fail so that I can build a proper response...
Example:
if(strlen($k) == 16 && filter_var($em, FILTER_VALIDATE_EMAIL)) {
$con = $c->Con();
$q = $con->query("SELECT COUNT(*) FROM table WHERE v = '$k' AND ema = '$em' AND ve = '0'");
$r = $q->fetch_row();
if($r > 0) { $q = $con->query("UPDATE table SET ve = '1' WHERE v = '$key' AND emails = '$em'");
if($q){
$mss = 'Ready'; // MS 1
}
} else {
$mss = 'It was ready'; // MS 2
}
} else {
$mss = 'Something is wrong!'; // MS 3
}
So the first query has 3 conditions if all are ok then go to the next "query", BUT, how do I know is one of the conditions fail?... what if [v] is not a match, or if the email is not a match or if ve is not a match... that way I can show a proper message on the MS 2.... instead of a general message...
if v is not equal to $k then $mss = 'Your key is not a match';
if emails is not equal to $ema then $mss = 'Your email was not fund';
if ve is not equal to 0 then $mss = 'Your key has no value';
the thing is that I would like to keep it as short and clean as possible, I can do a separate query for each one of the conditions which is a lazy way to do it but effective...
I can come up with a clunky solution that mostly shifts the work to PHP.
Change you query to SELECT the rows using ORs. To return the set of possible rows.
SELECT v, ema, ve FROM table WHERE v = '$k' OR ema = '$em' OR ve = '0';
Now go through this result set to check the conditions.
Pseduocode
while( $row = fetch_row($result) ){
if( 1 and 2 and 3 ){
//SUCCESS
}
elseif( NOT 1 ){
//1 is the problem
}
elseif( NOT 2 ){
//2 is the problem
}
elseif( NOT 3 ){
//3 is the problem
}
}
1,2,3 are the condition (e.g. 1 = ($row['v'] == $k))
You'll have to figure out what to do about multiple rows, ideally the schema would prevent that.

Calculate no of fields in MYSQL between two data types

OK weird question.
Table consists of multiple fields. Some with data type int(5) and the rest with datatype int(11)
So lets take a row...
id =>int(5)
var1 =>int(11)
var2 =>int(11)
var3 =>int(11)
var4 =>int(11)
var5 =>int(5)
var6 =>int(11)
var7 =>int(11)
var8 =>int(11)
How can I count the fields in PHP BETWEEN id (int(5)) and var (int(5))
I need to return the values in the fields between using php... but Im stuck. Bad table design doesnt help...but Im stuck with it.
The full scenario is that i need to create an if statement which says, output the name and and data of the int(5) field IF any of the fields between it and the next int(5) contain data
sorry... ugly I know!!!
If run this so far
$sql2 = 'SHOW COLUMNS from services2';
$result2 = getDBResults($sql2, $level, $testing);
$total = count($result2);
$i=2;
while ($i<($total-1))
{
$data = $result2[$i]['Field'];
if ($result2[$i][1]=='int(5)')
{
$html .= '<h2>'.preg_replace('/(?<!\ )[A-Z]/', ' $0', $result2[$i]['Field']).'</h2>';
}
else
{
];
// "$result - This is a seperate query run previously to get the row
if ($result[0][$data] == 1)
{
$html .= '<p>'.preg_replace('/(?<!\ )[A-Z]/', ' $0', $data).'</p>';
}
}
$i++;
}
I have not had a chance to actually test this, so dont beat me up if you need to tweek it a bit to smooth off any rough edges.
But its a fairly standard, if not totally simple, process of processing over the column names result array in a loop and just remembering the last int(5) column name in a variable so you can use it, if and only if, you have found some data in any int(11) column types before seeing the next int(5) column type.
Now I understand why you had trouble explaining what you wanted, I am having the same trouble describing a solution.
Anyway, have a look at this code and see if it makes any sence to you.
$sql2 = 'SHOW COLUMNS from services2';
$columns = getDBResults($sql2, $level, $testing);
$total = count($columns);
$print_column = null;
$found_data = false;
foreach ( $columns as $idx => $column ) {
// skip first 2 columns
if ($idx < 3 ) { continue; }
// first time thru loop so remember the first int5 column name we saw
if ( $column['Type'] == 'int(5)' && empty($print_column) ) {
$print_column = $column['Field'];
$found_data = false;
continue;
}
// found the next int5 column, do we need to print anything
if ( $column['Type'] == 'int(5)' && $found_data ) {
// This is where you would do any output creation,
// I just kept it simple.
echo $result[0][$print_column];
// reset state and the next field that might be printed.
$found_data = false;
$print_column = $column['Field'];
continue;
}
// This may not need to be an if, but just in case you have other field types
// that you are not interested in processing I made it an if.
if ( $column['Type'] == 'int(11)' && ! empty($result[0][$column['Field']]) ) {
$found_data = true;
}
} // endforeach

Logical clean up

I am currently having logical structure errors and I can't seem to think of a proper way of writing it out so it looks clean. Currently, I have a table in my database named USER. User has 6 fields out of the many, named: first, second, third, fourth, fifth, sixth.
What my code does is switch the data with two of the fields. So for example: the data in first is changed with the data in sixth.
Before: First - 1, Sixth - 6
After: First - 6, Sixth - 1
Currently, what I have is something that looks very messy, and I'm not sure how I can clean it up.
if($switch == true){ /* $switch just indicates if the numbers being switched is one of the fields i.e. first, second, etc.. */
if($slot == 1){ // The number is being switched into the first slot
if($first == $number){
return 1; // error, can't switch with itself
} else if ($second == $number){
$temp = $first;
// 1st QUERY TO UPDATE THE DATA IN FIRST, WITH THE DATA IN THE SECOND
// 2nd QUERY TO UPDATE THE DATA IN SECOND, WITH THE INFO STORED IN VARIABLE $temp
} else if ($third == $number){
$temp = $first;
// 1st QUERY TO UPDATE THE DATA IN FIRST, WITH THE DATA IN THE THIRD
// 2nd QUERY TO UPDATE THE DATA IN THIRD, WITH THE INFO STORED IN VARIABLE $temp
} // ... continues to check for 4, 5, 6...
} else if($slot == 2){ /* Then checks to see if it was slot 2, i.e. Second */
// ....
} else if($slot == 3){ /* Then checks to see if it was slot 3, i.e. Third */
// ....
} else if($slot == 4){ /* Then checks to see if it was slot 4, i.e. Fourth */
// ....
} else if($slot == 5){ /* Then checks to see if it was slot 5, i.e. Fifth */
// ....
} else if($slot == 6){ /* Then checks to see if it was slot 6, i.e. Sixth */
// ....
}
}
It continues for each slot, , 6 times each... I know it's bad programming but I have just started learning PHP (it's my first language, so bear with me). Any suggestions on what I can do to make this cleaner? Or even a better way of writing it? If anyone cares to explain to me over Skype or anything, I would be really grateful. Thank you.
Use a switch statement:
if($switch == true){
switch($slot) {
case 1 :
if($first == $number){
return 1; // error, can't switch with itself
} else if ($second == $number){
$temp = $first;
// 1st QUERY TO UPDATE THE DATA IN FIRST, WITH THE DATA IN THE SECOND
// 2nd QUERY TO UPDATE THE DATA IN SECOND, WITH THE INFO STORED IN VARIABLE $temp
} else if ($third == $number){
$temp = $first;
// 1st QUERY TO UPDATE THE DATA IN FIRST, WITH THE DATA IN THE THIRD
// 2nd QUERY TO UPDATE THE DATA IN THIRD, WITH THE INFO STORED IN VARIABLE $temp
}
break;
case 2 :
// ....
break;
case 3 :
// ....
break;
case 4 :
// ....
break;
case 5 :
// ....
break;
case 6 :
// ....
break;
default:
// ...
}
}
You will notice a default at the bottom. It's always good to have one in place in case none of your conditions match.
Also notice the break keyword. Without it the code block does not stop at the end and will "fall through" to the next block. This can be handy sometimes but not in your case.
You could do something like this:
// This function returns the column name for the specified slot
function getSlotColumn($slotNum)
{
switch($slotNum)
{
case 1:
retrun "first";
case 2:
return "second";
......
}
}
then in the switching function
// This function swaps the values of the two specified slots
function swapValues($slot1Num, $slot2Num)
{
if($slot1Num == $slot2Num) return;
if($slot1Num < 1 || $slot1Num > 6) return;
if($slot2Num < 1 || $slot2Num > 6) return;
$slot1Col = getSlotColumn($slot1Num);
$slot2Col = getSlotColumn($slot2Num);
//get value of the first slot
$slot1Val = //SELECT $slot1Col FROM ... WHERE ... slot
// Now since we have the value of the first slot, we can update it from the second slot with this pseudo query
//UPDATE ... SET $slot1Col = $slot2Col WHERE ...
// Then update second slot from the value in $slot1Val
//UPDATE ... SET $slot2Col = $slot1Val WHERE ...
}
Then use it like this:
if(switch == true)
{
swapValues(1, 6);
}

php: looping thru results from mysql query to increment counter (associative array)

I'm retrieving data from a MySQL db and creating reports from it. I need to get counts when certain conditions are met, and since db queries are rather expensive (and I will have a lot of traffic), I'm looping thru the results from a single query in order to increment a counter.
It seems like it's working (the counter is incrementing) and the results are somewhat close, but the counters are not correct.
At the moment, there are 411 records in the table, but I'm getting numbers like 934 from a ['total'] counter and 927 for ['males'], and that definitely can't be right. However, I get 4 from ['females'], which is correct…
I'm pretty sure it was working last night, but now it's not—I'm quite baffled. (there are still just 411 records)
$surveydata = mysql_query("SELECT `age`,`e_part`,`gender` FROM $db_surveydata;") or die(mysql_error());
$rowcount = mysql_num_rows($surveydata);
$age=array('18+'=>0,'<18'=>0,'total'=>0);
$e_part=array('yes'=>0,'no'=>0,'total'=>0);
$genders=array('male'=>0,'female'=>0,'trans'=>0,'don\'t know'=>0,'total'=>0);
while ($responses = mysql_fetch_assoc($surveydata)) {
foreach ($responses as $response){
switch ($response){
case $responses['age']:
if ($responses['age'] > 18) {$age['18+']++;$age['total']++;}
// i tried putting the ['total'] incrementer in the if/else
// just in case, but same result
else {$age['<18']++;$age['total']++;}
break;
case $responses['e_part']:
if ($responses['e_part']) {$e_part['yes']++;}
else {$e_part['no']++;}
$e_part['total']++;
break;
case $responses['gender']:
switch ($responses['gender']){
case 1:$genders['male']++;break;
case 2:$genders['female']++;break;
case 3:$genders['trans']++;break;
case 9:$genders['don\'t know']++;break;
default:break;
}
$genders['total']++;
break;
default:break;
} // end switch
} //end for
} // end while
thanks!
this is the problem:
foreach ($responses as $response){
switch ($response){
case $responses['age']:
switch $responses looks for match
foreach ($responses as $k=>$v){
switch ($k){
case 'age':
if ($v > 18) ....
mysql_fetch_assoc() retrieves a single row from the table. You then loop over that row, processing each individual field. Then the long set of if() checks to determine which field you're on. That entire structure could be changed to:
while($response = mysql_fetch_assoc($surveydata)) {
if ($responses['age'] > 18) {
$age['18+']++;
} else {
$age['<18']++;
$age['total']++;}
if ($responses['e_part']) {
$e_part['yes']++;
} else {
$e_part['no']++;
}
$e_part['total']++;
switch ($responses['gender']){
case 1:$genders['male']++;break;
case 2:$genders['female']++;break;
case 3:$genders['trans']++;break;
case 9:$genders['don\'t know']++;break;
default:break;
}
$genders['total']++;
}
There's no need for the switch ($response); you can't really switch on an array like that. And even if you could, the 'values' you get wouldn't make any sense -- i'm thinking if it works at all, the value you're switching on would be either 'Array' or the length of the array. (I forget how PHP handles arrays-as-scalars.)
You'll want something like this...
$total = 0;
while ($response = mysql_fetch_assoc($surveydata))
{
if (isset($response['age']))
{
++$age[($response['age'] < 18) ? '<18' : '18+'];
++$age['total'];
}
if (isset($response['e_part']))
{
++$e_part[($responses['e_part']) ? 'yes' : 'no'];
++$e_part['total'];
}
if (isset($response['gender']))
{
switch ($response['gender'])
{
case 1: ++$genders['male']; break;
case 2: ++$genders['female']; break;
case 3: ++$genders['trans']; break;
case 9: ++$genders["don't know"]; break;
}
++$genders['total'];
}
++$total;
}
The benefit of the if (isset(...)) is that if 'age', 'e_part', or 'gender' is null, the corresponding code to count it won't get activated. It does about the same thing as your code, minus the embarrassing loop -- and minus the counting of the field even though it is null, because every row will have the same fields.

Categories