views:

321

answers:

4

This is part of an events page that can be filtered by date (using pre-defined date ranges or a date picker).

I want to avoid repeating the whole foreach ($days as $day_number)... etc. loop for every condition.

I guess that whole loop could be moved to a function, but I'm not sure how to implement it.

<?php

// open the db connection
$db = new wpdb('user', 'pass', 'db', 'server');


// $today = date('Y-m-d');
$today = '2009-06-21';
$tomorrow  = date( 'Y-m-d', mktime(0, 0, 0, date('m'), date('d')+1, date('Y')) );
$seven_days_ahead = date( 'Y-m-d', mktime(0, 0, 0, date('m'), date('d')+6, date('Y')) );
$thirty_days_ahead = date( 'Y-m-d', mktime(0, 0, 0, date('m'), date('d')+29, date('Y')) );


echo '<div class="column first">';


if ( ! empty($_REQUEST['date_range']) )    
{
    // user has chosen a date/range, show matching events 


    $date_range = mysql_real_escape_string($_REQUEST['date_range']);


    switch( $date_range )
    {
        case 'all':

            // code here

            break;

        case 'next_7_days':

            // code here

            break;

        case 'next_30_days':

            // code here

            break;

        default:

            // code here

    }


}
else
{
    // no date selected, show todays events

    $days = convert_date_to_day_number( $today );

    foreach ( $days as $day_number )
    {
        $where = sprintf( 'WHERE e.day_id = %s', $day_number );

        $events = get_events( $where );

        if ($events)
        {
            echo '<table class="results">';

            render_day( $day_number );

            foreach ($events as $event)
            {
                render_event($event);
            }  

            echo '</table>';
        }
        else
        {
            echo 'No events';                            
        }
    }

}

echo '</div> <!--/column-->';





function convert_date_to_day_number($date)
{
    global $db;

    $sql = "SELECT day_number FROM days WHERE day_date = '$date'";

    $day_numbers = $db->get_results($sql);

    foreach ($day_numbers as $key => $value)
    {
        $day_number[] = $value->day_number;
    }

    return $day_number;
}


function get_events($where)
{
    global $db;

    $sql = "SELECT
                 e.id,
                 TIME_FORMAT(e.start_time, '%H:%i' ) AS start_time,
                 e.x_prod_desc AS title,
                 -- e.title_en AS title,
                 p.name_en AS place,
                 et.name_en AS type,
                 w.week_number,
                 d.day_date AS start_date
             FROM event AS e
             LEFT JOIN place AS p ON p.id = e.place_id
             LEFT JOIN event_type AS et ON et.id = e.event_type_id
             LEFT JOIN days AS d ON d.id = e.day_id
             LEFT JOIN week AS w ON w.id = d.week_id ";   

    $sql .= $where;

    $events = $db->get_results($sql);

    return $events;          
}

function render_event($event)
{
    $request_uri = $_SERVER['REQUEST_URI'];

    $output = <<<EOD

    <tr class="week-$event->week_number">
        <td class="topic"></td>
        <td class="time">$event->start_time</td>
        <td class="summary">
         <a href="$request_uri&amp;event_id=$event->id">$event->title</a>   
        </td>
        <td class="type">$event->type</td>
        <td class="location">
           <span class="addr">$event->place</span>
        </td>
    </tr>

EOD;

    echo $output;
}


function render_day( $day_number )
{
    global $db;

    $sql = "SELECT
                d.day_number,
                DATE_FORMAT( d.day_date, '%W %e %M %Y' ) AS date,
                DATE_FORMAT( d.day_date, '%b' ) AS month,
                DATE_FORMAT( d.day_date, '%e' ) AS day
            FROM days AS d
            WHERE day_number = " . $day_number;

    $day = $db->get_results($sql);

    $day = $day[0];

    $output = <<<EOD

    <tr class="day">
        <th colspan="5">
            <em class="date">
                <abbr class="dtstart" title="20090605T1806Z">
                    <span title="$day->date">
                        <span class="month">$day->month</span>
                        <span class="day">$day->day</span>
                </span>
                </abbr>
            </em>
            $day->date
            <span class="event-day">Day $day->day_number</span>
        </th>
    </tr>

EOD;

    echo $output;
}
?>
+1  A: 

Rather than querying the database once for every day, I would make a WHERE statement that fetched all events for the desired date range, and then send that to a render function which loops through every row in the result set and if the day is different from previous one, calls render_day() before calling render_event().

switch (/* input from user */) {
    // Build a date range here.
    // Resulting statement would be something like:
    // WHERE event_date >= '2009-06-10' AND event_date < '2009-06-17'
}

$events = get_events($filter);
$prev_date = null;
foreach ($events as $event) {
    if ($event->date != $prev_date) render_day($event->date);
    render_event($event);
    $prev_date = $event->date;
}
Blixt
+3  A: 

First, you may want to use strtotime for relative dates :

$today = '2009-06-21';
$tomorrow  = date( 'Y-m-d', strtotime('+1 day') );
$seven_days_ahead = date( 'Y-m-d', strtotime('+7 days') );
$thirty_days_ahead = date( 'Y-m-d', strtotime('+30 day') );
    // or +1 month (=> calendar month)

Second, you can set two variables with begin & end dates, then:

$date = $start_date; // 'Y-m-d' format
while( $date <= $end_date ) {
    //code here or fill up a table with your days
    // using $date
    $date = date( 'Y-m-d', strtotime( '+1day', strtotime($date) ) );
}

Whenever working with dates in PHP, you should check strtotime.

streetpc
+1 for pointing out strtotime
Luiz Damim
$tomorrow = date('Y-m-d', strtotime($today . ' +1 day')); etc...
meleyal
A: 

Wow! I've read it!

First of all use template engine (like smarty) or any other way to split your code and HTML. That's a bad idea to echo HTML from inside the functions.

I'm not sure but I think that using unix-timestamps in DB could simplify your data structure. The same is about php code. Read carefully about date/time functions in php manual, I think, you'll find a lot of interesting things...

Actually, as I see from your code using timestamps and templates will reduce your code to some line for fetching data and assigning it to template engine. PHP's "date()" function already has an option to return week numbe, day number in a week or in a year etc...

This is dummy exaple what could your code look like:

$begin = mktime(...);
$end = mktime(...);
$query = "
    SELECT a,b,c 
    FROM events 
    WHERE ctime >= $begin AND ctime <= $end AND ...
";
$events = array();
while ($fetch = fetch_here(...))
{
    $event = new MyEvent();
    $event->loadDBFetch($fetch);
    array_push($events, $event);
}
$tplEngine->assign('events', $events);

Sure, this is not a ready-to-go solution, but it seems to me, that your code could be similar to this.

Jet
I'm not able to use smarty, it's part of a Wordpress template. Can you suggest a better way to render the HTML?
meleyal
A: 
function generateEventsTable($dateStr)
{
    $days = convert_date_to_day_number( $today );
    foreach ( $days as $day_number )
    {
        $where = sprintf( 'WHERE e.day_id = %s', $day_number );
        $events = get_events( $where );
        if ($events)
        {
            echo '<table class="results">';
            render_day( $day_number );
            foreach ($events as $event)
            {
                render_event($event);
            }  
            echo '</table>';
        }
        else
        {
            echo 'No events';                            
        }
    }
}

Call it like this:

generateEventsTable($today);
karim79