simple grouping with php while loop? - php

I am outputting a table of rates. Each rate period has a Daily Rate and a Weekly rate, but the rate PERIODS remain the same.
So I am attempting to change the background color after ever TWO sets. So basically, the table will show:
Date 1 - Weekly Rate
Date 1 - Daily Rate
<change bg color>
Date 2 - Weekly Rate
Date 2 - Daily Rate
<change bg color back to original>
At the moment, I have two styles set up for background colors in my stylesheet. And the code i am using is giving me ALTERNATING rows. I just cannot see why it's changing every one, instead of every OTHER one!
To do this, I MUST compare one Date1 to Date2. ( I cannot make it change every two iterations, for reasons I do not want to go into.)
Here is my code so far inside the while loop. Help! And thank you.
if ($previous !== $row[datefrom])
{
$thecolor = "bg1";
}
else
{
$thecolor = "bg2";
}
echo "<tr class=\"".$thecolor."\"> \n";
echo "<td>" . $row[datefrom] . " - " . $row[dateto]. "</td> \n";
echo "<td>" . str_replace(" 3-5","",$row[Ratetype]) . "</td> \n";
echo "<td>$" . $row[Rate] . "</td> \n";
echo "</tr> \n";
$previous = $row[datefrom];

You also have to remember last used background color, without it background will change only for first entry in group. Example:
$use_original_bg = TRUE;
for(/*...*/){
if ($previous !== $row[datefrom]) {
$use_original_bg = !$use_original_bg;
}
$thecolor = $use_original_bg?"bg1":"bg2";
}

We can see the reason for this very easy if we set up the states of current date and prev for each iteration:
1. date1, prev = nothing => bg1
2. date1, prev = date1 => bg2
3. date2, prev = date1 => bg1
4. date2, prev = date2 => bg2
One easy way to solve this problem is to also take into account the state of the background. I'll leave that up to you to give it some thinking.

Related

Time Checking in PHP

To start off I'm sorry for the noob question. Learning as I go but I'm having issues with this and couldn't fine the right search.
What I'm trying to accomplish:
I'm currently trying to combine strings of text and numbers for a ban list.
For example a person is banned for 40 minutes, In the SQL database it is stored as the value 40.That is fine when displayed in a table however issues arise when a person is banned for 10080 minutes (1 week)
What I have:
$sql = "SELECT name, authid, name, length FROM sb_ctbans";
$result = mysqli_query($conn, $sql);
if (mysqli_num_rows($result) > 0) {
// output data of each row
while($row = mysqli_fetch_assoc($result)) {
if ($row["length"] < '60'){
$row["length"] . "Minutes" == $ban['length'];
echo $ban['length'];
} else {
$row["length"] . "Undefined length" == $ban['length'];
}
echo "<tr>"."<td>" . $row["name"] ."</td>" . "<td>" . $row["authid"] ."</td>" . "<td>" . $ban['length'] . "</td>" ."</tr>";
}
Expected output: 2 Minutes
Actual output:
Cheers for any help.
Edit:
After changing from:
$row["length"] . "Minutes" == $ban['length'];
To:
` $ban['length'] = $row.['length'] . 'Minutes';`
I am now reviving the output ArrayArray Minutes
You have a couple of problems here. You fixed the first wrong line, but it's again wrong at $row["length"] . "Undefined length" == $ban['length'];. Also, you're checking if the $row['length'] is less than the STRING '60', not the number 60, which could be causing errors. Finally, as others have said, storing the number of minutes to ban is sure to cause problems eventually. Instead, when the ban is first established, calculate the time it will be when the ban expires and store that instead. When you check it, calculate how long til the time you stored. Otherwise as time passes, you must update every ban record every minute or they become inaccurate.

How to loop data for the same id without showing the id repeatedly using foreach?

I'm trying to display rental amount and days relevant to car id. I'm first displaying car names for car Make clicked by user.
When it displays car names,it must display number of rental days and rental amount as well.
But since I store days and amount for a car id in the backend three times, it also loop three times in front end.
To make it clearer:
// in the back end,
I stored the days and amount for a car multiple times instead of one time
carName days amount
carname1 1 50
carname1 7 650
carname1 30 2000
And I'm calling the carName,gallery,rental_days and rental_amount like this:
if(isset($q))
{
mysql_select_db($database);
/*$query_showmake="SELECT carName FROM car_name WHERE carMake_id='$q'";*/
$query_showmake="SELECT rental.rental_days,rental.rental_amount,rental.carName_id,car_name.carName_id,car_name.carName,car_name.carMake_id,gallery,gallery_id,gallery.gallery,gallery.carName_id,car_make.carMake_id FROM rental,car_name,gallery,car_make WHERE car_name.carName_id=gallery.carName_id AND car_name.carMake_id='$q' AND car_name.carMake_id=car_make.carMake_id AND rental.carName_id=car_name.carName_id ORDER BY rental_days ASC";
$result_showmake=mysql_query($query_showmake)or die(mysql_error());
while($row_showmake=mysql_fetch_array($result_showmake))
{
$carMake_show=$row_showmake['carName'];
$carmake[$row['carName_id']][]=$row_showmake;
/* echo $carMake_show.'<br/>';*/
}
?>
<table border="0" style="border-collapse:collapse">
<?php
foreach($carmake as $make=>$name)
{
foreach($name as $n)
{
echo "<tr>";
echo "<td class='carname'>".$n{'carName'}.'</td><td rowspan="2" valign="top" class="cardetail">Car Details</td></tr>';
/*echo $n{'carMake_id'}.'<br/>';
echo $n{'gallery'}.'<br/>';*/
echo"<tr><td class='img'><img src='management/uploads/{$n['carMake_id']}/{$n['gallery']}' width='400' height='200'>";
echo "</td></tr>";
echo"<tr><td colspan='2' class='days'>Days : ";
$days[]=$n['rental_days'];
foreach($days as $day)
{
echo $day." ";
}
echo "</td></tr>";
echo"<tr><td colspan='2' class='days'>Amount : ";
$amount[]=$n['rental_amount'];
foreach($amount as $amt)
{
echo "RM ".$amt." ";
}
echo "</td></tr>";
echo"<tr><td height='50' colspan='2'></td></tr>";
}
}?>
</table>
<?php
}
And it displays the result like this:
carName 1
image 1
days 1
amount 50
carName 1
image 1
days 7
amount 650
carName 1
image 1
days 30
amount 2000
AND I want to display like:
carname 1
days:1 7 30
amt: 50 650 2000
In your main fetch loop stack the values you want to display in an indexed array like this
while($row = mysql_fetch_array($result_showmake)) {
$carmake[$row['carName_id']]['amounts'][] = $row['rental_amount'];
$carmake[$row['carName_id']]['days'][] = $row['rental_days'];
$carmake[$row['carName_id']]['images'][] = $row['gallery'];
}
Then use implode to render the stacked values as a space separated string
foreach($carmake as $id => $make) {
print "carName $id\n"
. "images " . implode(' ', $make['images']) . "\n"
. "days " . implode(' ', $make['days']) . "\n"
. "amounts " . implode(' ', $make['amounts']) . "\n";
}
Btw, you shouldn't use mysql_* functions as they're deprecated. Consider moving to mysqli or PDO.

How to manage couple of combo box working together?

I'm having two comboboxes. One is like 'admin', 'city' , 'theatre' and the other one is daily and weekly. If user select one of item in first and daily in second it shows daily operations. If user select one of item in the first one select nothing in second one it shows daily and weekly operations. If user does not select anything in first and daily in second it brings all operations daily and son on.
Therefore I think there is 2^3 if conditions. Is there anyway to reduce this? I am using PHP language but I think core algorithm is same in all languages!
Following is what I have done so far for three conditions if it is admin and daily and weekly:
<?php
if(strlen($_POST['attribute'])>0)
{
echo "For admin: ";
echo "</br>";
//If admin
if($_POST['attribute'] == 'Admin'){
//If daily
if($_POST['date'] == 'Daily'){
echo "The only feature to show update is making a user admin\n";
echo "</br>";
$fh = fopen('back-up/makeadmin.txt','r');
$foo = true;
while ($line = fgets($fh)) {
if($foo){
//Current time
$now = new DateTimeImmutable();
//One week ago
$oneDayAgo = $now->sub(new DateInterval('P1D'));
echo "</br>";
echo "</br>";
$date = DateTime::createFromFormat('m/d/Y h:i:s a+', $line);
//Here you can compare your dates like any other variables
if ($date > $oneDayAgo) {
/* Nothing echo "Current date is less than 1 week old";
Break;
*/
break;
}
if ($date < $oneDayAgo) {
echo "$line";
}
var_dump($line);
}
$foo = (!$foo);
}
fclose($fh);
}
else { /*if($_POST['date'] == 'Weekly'){*/
echo "The only feature to show update is making a user admin\n";
echo "</br>";
$fh = fopen('back-up/makeadmin.txt','r');
$foo = true;
while ($line = fgets($fh)) {
if($foo){
//Current time
$now = new DateTimeImmutable();
//One week ago
$oneWeekAgo = $now->sub(new DateInterval('P1W'));
echo "</br>";
echo "</br>";
$date = DateTime::createFromFormat('m/d/Y h:i:s a+', $line);
//Here you can compare your dates like any other variables
if ($date > $oneWeekAgo) {
/* Nothing echo "Current date is less than 1 week old";
Break;
*/
}
if ($date < $oneWeekAgo) {
echo "Current date is more than 1 week old";
}
var_dump($line);
}
$foo = (!$foo);
}
fclose($fh);
}
//If not daily
else
{
echo "weekly";
}
}
}
else
{
echo "Not admin";
}
?>
I'm not familiar with PHP, but if your code has a lot of hard-coded if statements, it's a clear sign that you need a better data structure, or maybe any data structure at all.
For example, you duplicate a whole block of code that only differs in that the first uses $oneDayAgo and the second $oneWeekAgo?. You could easily make that into a variable someTimeAgo that is a time span of seven days or one day, depending on the value of your second list box.
I'm not sure what the selection of the first box is for, maybe the file to read from? You might be able to find some common behaviour fro these three cases, too, and try to express them in variables rather than code.
You could probably store the relevant data is an associative array whose keys are the values of the list boxes:
$span = array("Daily" => "P1D", "Weekly" => "P1W");
As a next step, you could even populate your list from PHP with the keys (the values left of the fat arrows) of the array and you could easily extens the list together with the time spans without adding any new code, just new data.
Lastly, an UI niggle: If you have only two values, you shouldn't use a drop-down list box. Use a group of two radio-buttons next to each other and the user will be able to see both options at one glance without having to click anything. (I also don't think these are combo boxes, because combo boxes allow to enter a value by either typing it in manually or selecting it from a drop-down list.)

Creating a unique ID for every item within an array, even if called more than once on a page

On a website I am creating, I have the store 'open hours' in three locations on one page. One in the header, one in the body and one in the footer. I am trying to pull these in with PHP for simplicity when updating. I wrote an array:
<?php
$UniqID = uniqid(day);
$day1 = 'Mon-Fri: 9:00a-5:00p';
$day2 = 'Saturday: 9:00a-1:00p';
$day3 = 'Sunday: CLOSED';
$days = array(
"1" => "<span id=" . $UniqID . " class='editable-text'>" . $day1 . "</span>",
"2" => "<span id=" . $UniqID . " class='editable-text'>" . $day2 . "</span>",
"3" => "<span id=" . $UniqID . " class='editable-text'>" . $day3 . "</span>",<
);
?>
and then am calling it on the page as such:
<span>Address | Phone <br/> Our Hours: <?php echo $days[1] ?>, <?php echo $days[2] ?>, <?php echo $days[3] ?></span>
The problem I have is that I need a unique ID EVERY time these are called to the page, and obviously this gives a unique ID for 1, 2 and 3 - but if I call that same thing on the page 2 or 3 times... well, then all three of the first instances have the same ID and so on.
So to sum it all up, I want to create an array that stores the hours like above - and be able to call them to the page however many times necessary but always get a unique ID wherever they show up.
Any help is appreciated, I can't process this anymore!
What you can do is declare the unique ID at the very top, like you have with $uniqueID=X
Then, every time you insert $uniqueID into the DOM, increment it as well. So:
<?php echo "<span id='".$uniqueID++."'>STUFF IN SPAN</span>"; ?>
If $uniqueID is an int, the "++" will increment it, thus maintaining a unique one for each time it's inserted.
Instead of declaring one unique ID at the top, declare it once for every <span>. It is also possible to declare it in a loop with a variable variable, like this:
$day1 = 'Mon-Fri: 9:00a-5:00p';
$day2 = 'Saturday: 9:00a-1:00p';
$day3 = 'Sunday: CLOSED';
for ($i = 1; $i <= 3; $i++) {
$days[$i] = "<span id='uid" . uniqid() . "' class='editable-text'>" . ${'day'.$i} . "</span>";
}
This will produce something like:
Array
(
[1] => <span id='uid53350c2f730eb' class='editable-text'>Mon-Fri: 9:00a-5:00p</span>
[2] => <span id='uid53350c2f73156' class='editable-text'>Saturday: 9:00a-1:00p</span>
[3] => <span id='uid53350c2f731d0' class='editable-text'>Sunday: CLOSED</span>
)
Note that the id attribute cannot start with a number (or else it's not valid HTML), so you should probably put some letters before the uniqid() like I did (with uid). Also, you were missing quotes around the id value.

PHP - Grouping Duration based events / rows into single html blocks

So I've got a bunch of 'events' in a table in which they have a start and an end column (both DATETIME). I'm fetching every event for a single day and somehow need to group them together so that they can be displayed as a single HTML block.
For example...
Row #1: Has a duration of 30 minutes, starts at 09:00:00 and ends at 09:30:00
Row #2: Has a duration of 30 minutes, starts at 09:30:00 and ends at 10:00:00
Row #3: Has a duration of 90 minutes, starts at 12:00:00 and ends at 13:30:00
What would be the best way to know that I need 2 html blocks... One that is a div that has a 60px height (for rows 1 and 2), and then because there's a break between 10:00:00 and 12:00:00 to have the another div that is 90px height (row 3).
Can this be done with MySQL somehow? Or do I have to do a PHP loop to check for empty spaces of time in order to know when I should close a div and begin a new one?
Any help would be beneficial.
This is more of a logic question than code question.
You can do this in MySQL. One way is using a correlated subquery to determine when "event periods" begin. A new event period begins when it does not overlap with any others. Then use this information to assign an "event period id" to each event.
Such a query would perform reasonably well with the right indexes.
You could do this in php. I am biased toward putting such logic into the database rather than in application code.
My personal bias is to keep formatting out of the database layer. I would do this using PHP.
Assumptions based on the text of your question:
Duration is stored in the database
Duration increment = 30 minutes
Events do not overlap.
Duration data has been queried with ODBC
Duration query includes ORDER BY Start_Time
Duration data loaded into appropriate $result variables
Event blocks are 30px per event.
$job_count = 0;
$event_increment = 30;
$event_height = 30;
$this_block_height = 0;
$this_block_content = "";
while(odbc_fetch_row($result)) {
//fetch all your results into arrays
$duration[] = odbc_result($result, 1);
$start_time[] = odbc_result($result, 2);
$end_time[] = odbc_result($result,3);
$event_count++;
}
for($x=0;$x < $event_count; $x++) {
//loop through the arrays to format the blocks
if($x + 1 == $job_count) {
//if this is true, we are at the last element
$this_block_height += $event_height;
$this_block_content .= $start_time[$x] . " to " . $end_time[$x] . PHP_EOL;
echo "<DIV style='height:" . $this_block_height . "px;'>$this_block_content</DIV>";
}
else {
if($end_time[$x] == $start_time[$x+1]) {
//if this is true there is no gap.
$this_block_height += $event_height;
$this_block_content .= $start_time[$x] . " to " . $end_time[$x] . PHP_EOL;
}
else {
//gap identified
//write old block to file with padding on the end
//reset values to start over
$end_seconds = strtotime($end_time[$x]);
$start_seconds = strtotime($start_time[$x+1]);
$gap = $start_seconds - $end_seconds;
$gap_minutes = $gap / 3600;
$gap_increments = $gap_minutes / $event_increment;
$this_block_height += ($event_height * $gap_increments);
echo "<DIV style='height:" . $this_block_height . "px;'>$this_block_content</DIV>";
//this will put the space padding at the end of the first block
//instead of at the start of the second block
$this_block_height = 0;
$this_block_content = "";
}
}
}

Categories