PHP and MySQL Data Formatting - php

I've created a database and stored some data along with the scheduled date for each item. I would like to output a schedule in the format like this:
January 1:
- 1:00 pm
Doctors
Appt -
4:45 pm
Birthday
Party January 3:
- 10:00 am
Hair Cut
Appt -
4:50 pm
Bob's House
The problem I've run into is I'm not sure on how to output the data like this. I only want to display the date once but the time and date are in the same row, so a foreach loop won't work. If there's a better way to structure my data to achieve this then I'm willing to do that also.
My Table contains the following data for each row:
id, name, about, date, time
Any help would be much appreciated. Thanks

You don't need to structure your data differently, it sounds like it's been normalised properly. Instead pre-process your data into a temporary array that groups results by date, then loop over that:
$dateArray = array();
foreach($dbResult as $result) {
$dateArray[$result['date']][] = $result;
}
foreach($dateArray as $date => $entries) {
echo $date . ':<br>';
foreach($entries as $entry) {
echo $entry['time'] . '<br>' . $entry['name'];
}
}
Avoid doing two queries because you can do what you need with one and it'll put your database under less load.

Personally I would consider structuring the database as such:
Table: Dates(DateId, Date)
Table: Times(TimeDateID, DateID, Time)
Table: Appointment(AppointmentID, Name)
Table: Appointment_Time(AppointmentID, TimeDateID)
That way you could loop through all your dates, for each date loop through all the times that have that DateID, then loop through all your appointment_times with that timedateID

Pull the data and then create a multidimensional array from it, e.g.:
$data = array(
'January 3' => array (
'1:00 PM' => array (
'Doctor\'s Appt'
),
'4:45 pm' => array (
'Birthday Party',
'Something else at 4:45 as well'
)
)
);
(Your dates and times will probably not be those strings, but you get the idea.)
Then loop through dates and times in a natural way.
To create an indexed data structure like that shown above:
foreach ($dbResult as $row){
$data[$row['date']][$row['time']] = $row;
}

You can run a query which selects data for a given date. First, run a query which will give you a list of dates... something like this:
SELECT DISTINCT date FROM table;
Then do a foreach loop on the resulting list, running this query inside the loop:
SELECT time, name, about FROM table WHERE date = currentdate;
This will give you a list of the items for the current date, and you can simply iterate over them. It shouldn't be a performance problem if this is a single-user application or low-load web application.
If you prefer only one query, try this:
SELECT date, time, name, about FROM table ORDER BY date ASC, time ASC
You can then use a single foreach and a placeholder variable to loop over this, without the semantic hoop-jumping of multiple associative arrays and the like. Set the initial value of the placeholder value to the first date in the array, and then check on each loop to see if the date has changed. If it has, output a date header before you output the time, name, and notes about each entry, set the placeholder to the new date, and repeat.

Related

How to sort foreach items from SQL by date (Today, Yesterday, 29 Aug, 28, etc.) in PHP?

Sorry, I couldn't explain it more in the title but here's the deal.
I have a SQL table with items which have a classic date column where I ordered them by date in the loop. Now I want to add an echo into an existing loop to display a row in the looped table which will show Items added today, Items added yesterday and so forth.
This is how I'd like it to look when looped. (The closest I got was it looped by every second and added echoed part per every item which was a total mess)
PS: Reading on google maybe it should be included as usort with if inside existing foreach?
----------------------------
Table
----------------------------
echoed `<tr><td>Added: today<td></tr>`
---------------------------
Item 1
Item 2
Item 3
---------------------------
echoed `<tr><td>Added: yesterday<td></tr>`
---------------------------
Item 4
Item 5
Item 6
Item 7
---------------------------
echoed `<tr><td>Added: 29 Aug<td></tr>`
---------------------------
Item 9
Item 10
Item 11
etc
Edit: Date format doesn't have to be 29 Aug. It's just for the reference I'll tweak it myself. I just need a help with the logic of how to implement this.
you should sort them first in the database!
then when looping through the items you essentially remember which section you last displayed, and before outputting the first row of a new section, you output the section title instead:
$current = null;
foreach($rows as $row) {
$display = date_create($row['timestamp'])->format('Ymd'); // or whatever!
// it must consistently return something that makes the following consistent:
if($display != $current) {
// add separator that contains "today" or "yesterday" or the date
echo '<tr><td>'.$display.'</td></tr>';
$current = $display;
}
// display the actual row here
}
the problem gets harder, if you want to also show separator rows for dates that don't exist in database. then, you would have to create a date object first, and subtract one day at a time until the date matches the rows date, outputting separators accordingly.
update: special displays (please note, that $today and $yesterday must be simple types like string or int or something for this to work):
// before the loop!
$today = date_create()->format('Ymd');
$yesterday = date_create("-1 day")->format('Ymd');
$replacements = [
$today => 'today', // or whatever
$yesterday => 'yesterday', // or whatever
];
in the loop when echoing the $display:
echo '<tr><td>'.($replacements[$display] ?? $display).'</td></tr>';
this will look, if the formatted date should be replaced.
You have mentioned that you have already got the data sorted on the basis of days i.e. the field "added".
What you can do next is to loop through the retrieved result set. This is how you can proceed.
$dtPrevDate = null;
The above variable is going to be useful for the purpose of comparison of the dates i.e. "added".
Now loop through the retrieved data:
foreach($data as $datum){
if($dtPrevDate == $datum['added']){
// Keep printing item
}
else{
echo "Item added on: $datum['added']";
}
$dtPrevDate = $datum['added'];
}
The essence of the above code is dependent on the sorting that you have already managed to do using MySQL.

Looping through a foreach and then grouping the data into date arrays

I want to loop through a foreach and group the result by date.
Example:
2017-10-05
2017-10-05
2017-10-07
2017-10-10
2017-10-10
2017-10-10
... and so on
As I don't know how to accomplish this I have only the standard code for a foreach to loop. I should point out the data is coming from an XML feed.
foreach($streamData->channel->item as $item) {
echo $item->date.'<br>';
}
The code above prints the dates like this:
2017-10-05
2017-10-05
2017-10-07
2017-10-10
2017-10-10
2017-10-10
... and so on
How can I accomplish this as the example shows?
If all you want to do is decide when to do the event processing then this is the sort of construct you might use.
$last_date = null;
foreach($streamData->channel->item as $item) {
if ( $last_date != $item->date ) {
echo '<br>' . $item->date . '<br>';
}
$last_date = $item->date;
// do event processing
}
How accurate this might be depends upon where you get your event information from.
Another potential solution would be to create a map, and store each grouping of dates as members of the map. The values of those members would be the array of dates, accessible in constant time O(1) by the date month key, which requires no loops later on when you want to search the groups or something like that.
For instance, this is the JSON representation of what I am thinking:
{
"10": [
"2017-10-10",
"2017-10-10",
"2017-10-10",
],
"9": [
"2017-10-9",
"2017-10-9",
"2017-10-9",
],
// ...
}
Now you can simply do a loop like "for each group of this object", and then "for each date of this group".
Since I don't have any object data to test on I'm not sure it works but maybe..
Edit I tested on an array and it seems I was wrong. Here is what does work on an array;
https://3v4l.org/VSJeQ
I think I matched your object with this array.
foreach($streamData->channel->item as $item) {
echo item->date.'<br>';
if(next($streamData)->date != $item->date) echo '<br>';
}
Basically use next() to see if the next item is not the same as the current. If it's true add another <br>
Edit; it may need to be changed to next($item) instead of next($item->date) now that I think about it

Cakephp2 filter dates from past

I'm wondering if it's possible to:
I have some string (10.07.2016-17.07.2016 , 19.07.2016-21.07.2016 , 22.07.2016-29.07.2016 etc... )
dates are separate by "," so for now i want to make array of dates separated by ",".
As result i will use this array to create select dropdown, so user can select data like for example (very generic, not cakephp style but it's just for understanding my question):
<select>
<option>10.07.2016-17.07.2016</option>
<option>19.07.2016-21.07.2016</option>
<option>22.07.2016-29.07.2016</option>
</select>
But now i'm wondering - how can i first filter this data to remove dates from past ?
Let's say that i have 11.07.2016 in calendar, so i should not see this in select ?
So, my question is - is this possible ? If yes, how should i filter this data? Filter array first using some function, or when i will generate select in form ?
Thanks for ideas.
first convert string into array,
$myString = "10.07.2016-17.07.2016, 19.07.2016-21.07.2016";
$myArray = explode(', ', $myString);
then use foreach to check if date is in the past
foreach($myArray as $element) {
if(strtotime($element)>strtotime("now")){
$futureDates[] = $element;
}
}
then you have only future dates for echo in
<select><option>...</option><option>...</option></select>

Percentage Difference Loop Array

First time poster so I hope you can help me with what I think is a simple task but can't figure out.
I have a table called exports which among other things has a year and value field. I currently have data for the years from 1992 to 2011.
What I want to be able to do is extract this data from the database and then calculate the year on year percentage difference and store the results in an array so the data can be passed to a view file.
For example: ((1993-1992)/1992)*100) then ((1994-1993)/1993)*100) then ((1995-1994)/1994)*100) etc etc.
I need it to be flexible so I can add future data. For example I will eventually add data for the year 2012.
I'm really stuck as how to progress this. Help would be greatly appreciated.
If I'm understanding that correctly, the solution wouldn't have to be that complicated. A simple SELECT query to fetch the year and value, which you could then go through using a loop in PHP and calculate the percentages. Something like this:
<?php
// Get all the data from the database.
$sql = "SELECT year, value FROM exports";
$stmt = $pdo->query($sql);
// An array to store the precentages.
$percentages = [];
// A variable to keep the value for the last year, to be
// used to calculate the percentage for the current year.
$lastValue = null;
foreach ($stmt as $row) {
// If there is no last value, the current year is the first one.
if ($lastValue == null) {
// The first year would always be 100%
$percentages[$row["year"]] = 1.0;
}
else {
// Store the percentage for the current year, based on the last year.
$percentages[$row["year"]] = (float)$row["value"] / $lastValue;
}
// Overwrite the last year value with the current year value
// to prepare for the next year.
$lastValue = (float)$row["value"];
}
The resulting array would look like this:
array (
[1992] = 1.0,
[1993] = 1.2,
[1994] = 0.95
... etc ...
)

Trying to access an associative array item via timestamp

So I have a MySQL object, which has columns (keys) for timestamp, category, and value.
Timestamp is a UNIX timestamp. Category is an emotion word. Value is a numeric value.
Here's my code:
foreach ($twitromney['timestamp']) {
echo $twitromney['timestamp']['value'];
}
Now, this should display the value per timestamp, right? This is how ONE of the arrays looks (the object has hundreds of these):
Array ( [category] => composed [value] => 330 [timestamp] => 1344384476.94 )
What I am trying to do is get the value per category per timestamp. Except for value, which is variable, both timestamp and category should repeat. I.e., there should be multiple 1344384476.94s, as well as several composed category values.
Once I get that (I don't think I need help with this), I am going to add the values for a particular category for a particular day (by converting the timestamp) together and output this.
Try this:
foreach ($twitromney as $flip) {
echo "$flip['category'], $flip['timestamp'], $flip['value'] <br />";
}
I really didn't understand your question but you have supplied wrong arguments in your foreach, you can try this
foreach ($twitromney as $item) {
echo $item['timestamp'].'<br />';
}
to echo every timestamp instead of
foreach ($twitromney['timestamp']){
echo $twitromney['timestamp']['value'];
}
If you see this example then you'll get an idea.

Categories