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 = "";
}
}
}
Related
I am new to php so please mind if it easy question. I have a php script, I want it to be executed only 10 times a day and not more than that. I don't want to use cron for this. Is there any way to do this in php only?
Right now I have set a counter which increases by one every time any one runs the script and loop it to 10 times only. if it exceeds it it shows an error message.
function limit_run_times(){
$counter = 1;
$file = 'counter.txt';
if(file_exists($file)){
$counter += file_get_contents($file);
}
file_put_contents($file,$counter);
if($counter > 11 ){
die("limit is exceeded!");
}
}
I want some efficient way to do this so everyday the script is only executed for 10 times and this is applicable for everyday i.e this counter gets refreshed to 0 everyday or is there any other efficient method.
I would rather recommend that you use a database instead - its cleaner and more simple to maintain.
However, it is achievable with file-handling as well. The file will be of format 2019-05-15 1 (separated by tab, \t). Fetch the contents of the file and split the values by explode(). Then do your comparisons and checks, and return values accordingly.
function limit_run_times() {
// Variable declarations
$fileName = 'my_log.txt';
$dailyLimit = 10;
$content = file_get_contents($fileName);
$parts = explode("\t", $content);
$date = $parts[0];
$counter = $parts[1] + 1;
// Check the counter - if its higher than 10 on this date, return false
if ($counter > $dailyLimit && date("Y-m-d") === $date) {
die("Daily executing limit ($dailyLimit) exceeded! Please try again tomorrow.");
}
// We only get here if the count is $dailyLimit or less
// Check if the date is today, if so increment the counter by 1
// Else set the new date and reset the counter to 1 (as it is executed now)
if (date("Y-m-d") !== $date) {
$counter = 1;
$date = date("Y-m-d");
}
file_put_contents($fileName, $date."\t".$counter);
return true;
}
I have been working for a while to combine a "foreach loop" and a "while loop". I would like my foreach to run 30 times. This is indicated by $counter. Now the problem is that my "while" again starts the "foreach" every time. But it hears 30 times turning the "while" each time again.
If I get the while part away and use static code, it will work completely. But I need to link my DB for the information. Perhaps an option is to make a "foreach" a "for" or a whole different option. But I have no idea how to set him up.
$counter = days in a month
$index = foreach time for running. Max $counter
$NUM = unique number of 1 people
The $ index together with $ cut_startday together indicate when a box is to be red or green.
Here's the code for the none working foreach:
foreach(range(1,$counter) as $index) {/*open foreach*/
$get_data = "
SELECT *
FROM core";
$result1 = $conn->query($get_data) or die($conn ->error);
//Start query 1
if($result1) {
while($row = $result1->fetch_assoc()) {
// Get NUM, START DATE and END DATE
$NUM = ($row['c_m_num']);
$startdate = ($row['e_date_s']);
$enddate = ($row['e_date_e']);
// Cut strings for date
$sort_year = substr($startdate, 6, 4); // START YEAR -> 2017
$sort_month = substr($startdate, 0, 2); // START MONTH -> 09
$cut_startday = substr($startdate, 3, 2); // START DAY -> 17
$cut_endday = substr($enddate, 3, 2); // END DAY -> 19
if($load_m_NUM == "$NUM" and $index >= $cut_startday && $index <= $cut_endday ){
echo"<td style='background-color:red;'>x</td>";
}
else{
echo"<td style='background-color:green;'></td>";
}
}
}
/*end foreach*/ }
What the idea is of the code. I want a calendar with a top row de days of a month and on the left side al the people. If the core find a match between days and 1 men, color the td red if not color green.
Any help greatly appreciated!
You could change the foreach statement to for ($index = 0; $index < 30; $index++). To improve your code I suggest putting the for loop inside the while loop instead. That way you only query the database once instead of 30 times.
PHP+SQL question:
I have table for assignments
one of the field is "progTargetDate" -> linux time (eg: 1348185600 )
I also built calender and I want to check if I have any assignment for each day I print
so - I wrote the query that bring me all the assignment for the current month
$query = mysql_query("SELECT ass.id, ass.title, ass.des, ass.progTargetDate
FROM pro_assignments AS ass, pro_progs2assignments AS pr
WHERE (ass.progTargetDate >= $ChoosenMonth_start) AND
(ass.progTargetDate <= $ChoosenMonth_end)
ORDER BY ass.progTargetDate ASC
");
(I delete part of the SQL query))
and I have the loop that build the calendar cell
for ($i = 1 ; $i <= $total_days_in_month ; $i++)
{
}
$i = each day in the month
I tried to build IF condition without success
I want to check for each day if it found inside the array (that I got from the first query)
(this code goes inside the FOR loop:)
echo "<td>$i";
while($index = mysql_fetch_array($query))
{
$progTargetDate = $index['progTargetDate'];
if ((mktime(0, 0, 0, date($ChoosenMonth) , $i, date($ChoosenYear)) == $progTargetDate))
echo "<p>found</p>";
else
echo "<p>not</p>";
}
echo "</td>";
What do I do wrong?
for 31 days I should have 31 cell with "found" or "not" in each one. but for some reason only in the first cell I see this result
I am attempting to make a timetable using data in a MySQL table that has the day, start and durtaion of each event.
My logic at the moment goes like this.
Find all events with monday, put in an array for monday
Find all events with tuesday, put in an array for tuesday
etc
then i run a for each loop on each array to go through each time slot in the day (9-5) and if it matches the current event, create a table cell, if not create and empty cell and finally if the event duration is longer than 1 slott then dont put anything. here is my code for the above:
function createTableEvent($day,$previousfinish)
{
$completeDay = '';
$day = explode(',',$day);
$ev = $day[0];
$start = $day[1];
$end = $day[2];
$event = "<div class=\"table_event\">$ev<br>Starts:$start<br>Ends:$end<br></div>";
$times= array('09','10','11','12','13','14','15','16','17');
//TIMES
foreach ($times as $time)
{
if($start == $time.":00" && $previousfinish == !)
{
$completeDay .= "<td class=\"$time\" colspan=\"$end\">
<div class=\"table_event\">$event</div></td>";
$previousfinish = $end;
}
else if($previousfinish > 1
{
}
else
{
$completeDay .= "<td class=\"$time\" colspan=\"1\"></td>";
}
}
return $completeDay;
}
The reason i wanna skip the cell if it is more than 1 is because if an event runs over more than one block, i set the column span to the duration of the event, there for it shhouldnt put a cell in for the next time if the previous event was longer than one block.
My output works for single hour events however not when a day has say 1 2 hour event and a 2nd 1 hour event. My code still makes the extra cells for the times that should be empty.
Any input or help would be very useful
The obvious things I notices were:
The second if statement (right after the 'else')'s condition is not
followed by a closing ')'.
I couldn't make out if this is wanted, but there are no commands to
whenever this condition is met
At the first condition inside the for loop you compare the
$previousfinish parameter to '!'. Is this really what you want to do?
Did you mean to compare it to '1'?
Other things I noticed is that if the last condition is met, you put the event time but not the event name (as you did in the first place).
I tried to further investigatethe problem, but it's bit hard, since I don't know what data is passed to the function in the arguments.
I suggest you fix the above problems and see if this fixes you problem.
If not, I would be happy to look further into this issue, if you supply a sample data being passed to the function.
Also, I re-arranged the code for readability, if you find it better -
<?php
function createTableEvent($day, $previousfinish)
{
$completeDay = '';
list ($ev, $start, $end) = explode(',',$day);
$event = "<div class=\"table_event\">$ev<br>Starts:$start<br>Ends:$end<br></div>";
//TIMES
foreach (array('09','10','11','12','13','14','15','16','17') as $time)
{
if ($start == ($time.":00") && $previousfinish == !)
{
$completeDay .= "<td class=\"$time\" colspan=\"$end\">
<div class=\"table_event\">$event</div></td>";
$previousfinish = $end;
}
else if($previousfinish > 1)
{
}
else
{
$completeDay .= "<td class=\"$time\" colspan=\"1\"></td>";
}
}
return $completeDay;
}
?>
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.