SitePoint Sponsor

User Tag List

Results 1 to 15 of 15
  1. #1
    SitePoint Member
    Join Date
    May 2004
    Location
    Brisbane
    Posts
    19
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Unhappy Help w/ PEAR Calendar and multiple events

    I've been playing with pear calendar and urgently need a little help with displaying multiple events that occur at the same time. I've modified example 11 (from the package documentation) so that the dummy db result includes 2 events that occur at the same time:
    PHP Code:
    // An array simulating data from a database
    $result = array (array('eventtime'=>mktime(9,0,0,10,24,2003),'entry'=>'Meeting with sales team'),
        array(
    'eventtime'=>mktime(9,0,0,10,24,2003),'entry'=>'Personal Time: Coke and Hookers'),
        array(
    'eventtime'=>mktime(15,0,0,10,24,2003),'entry'=>'Presentation to board of directors')
        ); 
    The problem is that inside the "foreach" loop, it just creates a new DiaryEvent object for each timestamp it pulls out from the array. What I think I need is a way to check if a DiaryEvent already exists

    PHP Code:
    foreach ( $result as $row ) {
        
    $Hour = new Calendar_Hour(2000,1,1,1); // Create Hour with dummy values
        
    $Hour->setTimeStamp($row['eventtime']); // Set the real time with setTimeStamp

        // Create the decorator, passing it the Hour
        
    $DiaryEvent = new DiaryEvent($Hour);

        
    // Attach the payload
        
    $DiaryEvent->setEntry($row['entry']);
        
         
    //**Additional code goes here**
            
        // Add the decorator to the selection
        
    $selection[] = $DiaryEvent;

    Any ideas?
    Last edited by ehando; May 25, 2004 at 09:39. Reason: Edited for clarity

  2. #2
    SitePoint Member
    Join Date
    May 2004
    Location
    Brisbane
    Posts
    19
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    narrowing it down...

    Ok, I've done some tests, narrowed down a few things, and changed some assumptions I was making. I think (and would glady be proved wrong) that I could modify things one of two ways:

    1. In the foreach($result as $row) I could check to see if an object already exists in $selection, and if so, call setEntry on it which would add the append the new event entry. The question then is, how do I check that a certain object instance exists?
    would in_array work? if so, how? Do I loop through $selection looking for a value?

    2.inside the "while ( $Hour = & $Day->fetch() ) {"
    there is a "if ( $Hour->isSelected() ) {"
    hour->isselected (I think) corresponds to the values in $selection so perhaps I can somehow modify that loop so that if an hour has already been "isSelected" then we append instead of the default action?

    As you can probably tell, at the moment I'm just throwing ideas against a wall to see what sticks. If anyone has already used pear Calendar or has an idea, puh-lease feel free to throw your 2 cents in.

  3. #3
    Non-Member
    Join Date
    Jan 2004
    Location
    Planet Earth
    Posts
    1,764
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    The question then is, how do I check that a certain object instance exists?
    http://us3.php.net/manual/en/functio...ed-classes.php

    Hope this link to the on-line manual helps you out

  4. #4
    SitePoint Member
    Join Date
    May 2004
    Location
    Brisbane
    Posts
    19
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Sorry, I guess I meant, how do I check that a certain DiaryEvent object exists in the $selection array?

    I tried in_array but it gave me an error - "Wrong datatype for first argument. My code:
    PHP Code:
    if (in_array($DiaryEvent$selection)) { 
    I should mention that I'm trying my first approach. That is, check to see if an object already exists in $selection and then decided to add the new object or just append the info. I just know that it's going to be such a simple solution and I'm gonna feel like an idiot but I'm afraid I just don't how to solve the problem.

    I haven't slept and I start work in 3 hours

  5. #5
    Non-Member
    Join Date
    Jan 2004
    Location
    Planet Earth
    Posts
    1,764
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Not actually sure that the in_array(..,..) works with objects ?

    Not got a solution for you, sorry, but maybe after this length of time, your approach to the problem could be hindering you ?

    I've never used PEAR Calander, which doesn't help you either

  6. #6
    SitePoint Member
    Join Date
    May 2004
    Location
    Brisbane
    Posts
    19
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Not got a solution for you, sorry, but maybe after this length of time, your approach to the problem could be hindering you
    Only if you count staring-bleary-eyed-into-a-computer-screen-until inspiration-hits a hindrance

    I'm rushed for time in terms of coming up with a solution. I need to deliver a working version of an events calendar by the end of the week. I'm halfway through writing my own calendar class but I keep thinking "Why am I doing this if Pear calendar already does it for you?!?".

    Anyways, I stumbled upon a bogus bug report . The "solution" is exactly how I've coded my example, so the problem is obviously either in adding the events into the $selection array OR displaying the event data. (neither of which have code examples in the postings)

    I've never used PEAR Calander, which doesn't help you either
    I've searched the forums and while a few others have used PEAR Calendar, no-one seems to be around to help out at the moment, so I'll happily accept any help I can get.

    Maybe I'll think clearer after an hour's sleep.

    Oh, and in_array doesn't seem to work with objects.
    Last edited by ehando; May 25, 2004 at 10:48. Reason: added in_array comment

  7. #7
    Non-Member
    Join Date
    Jan 2004
    Location
    Planet Earth
    Posts
    1,764
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Thinking, pseudo code though, and it's a hack really

    IF [NAME_OF_OBJECT] EXISTS THEN
    IF IN_ARRAY( 'NAME_OF_OBJECT', SELECTION) THEN {
    }
    ELSE { }

    So I'm thinking that the 'NAME_OF_OBJECT' is something you name, in relation to the actual object ? Thus if there is an instance of the required object, you have a term or name in the selection you know of to check against once you know the object instance exists or not ??

    Hope this bit make some sense to you, in regards to what I'm trying to get at anyways

  8. #8
    SitePoint Wizard gold trophysilver trophy
    Join Date
    Nov 2000
    Location
    Switzerland
    Posts
    2,479
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    OK - just to recap - you've seen that bug report and Lorenzo's answer and now have a DiaryEvent class capable of storing multiple events. I'm I right in saying the problem now is loading a single DiaryEvent with the correct objects?

    One way to do this would be something like this (note I haven't tested or even executed this code).

    First a DiaryEvent capable of storing multiple events using a slightly different iterator mechanism;

    PHP Code:
    class DiaryEvent extends Calendar_Decorator {
        var 
    $entries = array();
        function 
    DiaryEvent($calendar) {
            
    Calendar_Decorator::Calendar_Decorator($calendar);
        }
        function 
    addEntry($entry) {
            
    $this->entries[] = $entry;
        }
        
    // Simple iterator
        
    function getEntry() {
            
    $entry each $this->entries );
            if ( 
    $entry ) {
                return 
    $entry['value'];
            } else {
                
    reset ($this->entries);
                return 
    FALSE;
            }
        }

    You'll be able to call getEntry() inside a while loop to pull the events back off it.

    Now a class managing the creation of DiaryEvent objects as well as building the selection array;

    PHP Code:
    class SelectionManager {
        var 
    $year;
        var 
    $month;
        var 
    $day;
        var 
    $events = array();
        
        function & 
    getEvent($timestamp) {
        
            
    $human_date date("Y n j G",$timestamp);
            
    // sscanf helps avoid calling date lots of times - need to use this myself more
            
    $date_array sscanf($human_date"%d %d %d %d");
            list(
    $year,$month,$day,$hour) = $date_array;
            
            
    // Assign these so we can find the hours later - could be done in constructor perhaps
            
    $this->year $year;
            
    $this->month $month;
            
    $this->day $day;
            
            
    // Do we have an event already for this time?
            
    if ( !isset($events[$year][$month][$day][$hour]) ) {
            
                
    // If not create it
                
    $Hour = new Calendar_Hour($year,$month,$day,$hour);
                
    $DiaryEvent = & new DiaryEvent($Hour);
                
    $this->events[$year][$month][$day][$hour] = & $DiaryEvent;    
            }
            
            
    // Return the event
            
    return $this->events[$year][$month][$day][$hour];    
        }
        
        function 
    getSelection() {
            
    $selection = array();
            foreach ( 
    $this->events[$this->year][$this->month][$this->day] as $event ) {
                
    $selection[] = $event;
            }
            return 
    $selection;
        }

    Now here's how you could use this;

    PHP Code:
    $SM = & new SelectionManager();

    foreach ( 
    $result as $row ) {
        
    $DiaryEvent = & $SM->getEvent($row['eventtime']);

        
    // Attach the payload - note renamed to addEntry instead of setEntry
        
    $DiaryEvent->addEntry($row['entry']);
    }

    $selection $SM->getSelection();

    // Continue as before... 
    Hope that helps. There's are other ways to do this (such as drilling down to minutes and seconds) but that's probably a relatively efficient way to do things.

  9. #9
    SitePoint Member
    Join Date
    May 2004
    Location
    Brisbane
    Posts
    19
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Getting closer

    HarryF - it's close, but I still can't display multiple events that occur at the same time. With your changes I'm now getting these results:

    1. a DiaryEvent is only created for each unique $row['eventtime'], not for each $row returned from $result. (cool, this is partly what I was after)

    2. a DiaryEvent will only store one $row['event']. (damn!)

    The DiaryEvent object only stores the last $row['event'] it receives, so in the case of 'Meeting with Sales Staff' and 'Personal Time', only 'Personal Time' is stored since it is returned from $result AFTER 'Meeting with Sales Staff'.

  10. #10
    SitePoint Wizard gold trophysilver trophy
    Join Date
    Nov 2000
    Location
    Switzerland
    Posts
    2,479
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Sorry - bug in the code - the SelectionManager;

    PHP Code:
            if ( !isset($events[$year][$month][$day][$hour]) ) { 
    Should be;

    PHP Code:
            if ( !isset($this->events[$year][$month][$day][$hour]) ) { 
    Here's a complete working example;

    PHP Code:
    <?php
    /**
    * Description: demonstrates a decorator used to "attach a payload" to a selection
    * to make it available when iterating over calendar children
    */
    define('CALENDAR_ROOT','Calendar/');
    require_once 
    'Calendar/Calendar.php';
    require_once 
    CALENDAR_ROOT.'Day.php';
    require_once 
    CALENDAR_ROOT.'Hour.php';
    require_once 
    CALENDAR_ROOT.'Decorator.php';

    // Decorator to "attach" functionality to selected hours
    class DiaryEvent extends Calendar_Decorator {
        var 
    $entries = array();
        function 
    DiaryEvent($calendar) {
            
    Calendar_Decorator::Calendar_Decorator($calendar);
        }
        function 
    addEntry($entry) {
            
    $this->entries[] = $entry;
        }
        
    // Simple iterator
        
    function getEntry() {
            
    $entry each $this->entries );
            if ( 
    $entry ) {
                return 
    $entry['value'];
            } else {
                
    reset ($this->entries);
                return 
    FALSE;
            }
        }
    }

    class 
    SelectionManager {
        var 
    $year;
        var 
    $month;
        var 
    $day;
        var 
    $events = array();
        
        function & 
    getEvent($timestamp) {
        
            
    $human_date date("Y n j G",$timestamp);
            
    // sscanf helps avoid calling date lots of times - need to use this myself more
            
    $date_array sscanf($human_date"%d %d %d %d");
            list(
    $year,$month,$day,$hour) = $date_array;
            
            
    // Assign these so we can find the hours later - could be done in constructor perhaps
            
    $this->year $year;
            
    $this->month $month;
            
    $this->day $day;
            
    // Do we have an event already for this time?
            
    if ( !isset($this->events[$year][$month][$day][$hour]) ) {
                
    // If not create it
                
    $Hour = new Calendar_Hour($year,$month,$day,$hour);
                
    $DiaryEvent = & new DiaryEvent($Hour);
                
    $this->events[$year][$month][$day][$hour] = & $DiaryEvent;
            }
            
            
    // Return the event
            
    return $this->events[$year][$month][$day][$hour];
        }
        
        function 
    getSelection() {
            
    $selection = array();
            foreach ( 
    $this->events[$this->year][$this->month][$this->day] as $event ) {
                
    $selection[] = $event;
            }
            return 
    $selection;
        }


    // Create a day to view the hours for
    $Day = & new Calendar_Day(2003,10,24);

    // An array simulating data from a database
    $result = array (
        array(
    'eventtime'=>mktime(9,0,0,10,24,2003),'entry'=>'Meeting with sales team'),
        array(
    'eventtime'=>mktime(11,0,0,10,24,2003),'entry'=>'Conference call with Widget Inc.'),
        array(
    'eventtime'=>mktime(11,30,0,10,24,2003),'entry'=>'Conference call with suppliers'),
        array(
    'eventtime'=>mktime(15,0,0,10,24,2003),'entry'=>'Presentation to board of directors')
        );


    $SM = & new SelectionManager();

    foreach ( 
    $result as $row ) {
        
    $DiaryEvent = & $SM->getEvent($row['eventtime']);

        
    // Attach the payload - note renamed to addEntry instead of setEntry
        
    $DiaryEvent->addEntry($row['entry']);
    }

    $selection $SM->getSelection(); 


    // Build the hours in that day, passing the selection
    $Day->build($selection);
    ?>
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
    <html>
    <head>
    <title> Passing a Selection Payload with a Decorator </title>
    </head>
    <body>
    <h1>Passing a Selection "Payload" using a Decorator</h1>
    <table>
    <caption><b>Your Schedule for <?php echo ( date('D nS F Y',$Day->thisDay(TRUE)) ); ?></b></caption>
    <tr>
    <th width="5%">Time</th>
    <th>Entry</th>
    </tr>
    <?php
    while ( $Hour = & $Day->fetch() ) {

        
    $hour $Hour->thisHour();
        
    $minute $Hour->thisMinute();

        
    // Office hours only...
        
    if ( $hour >= && $hour <= 18 ) {
            echo ( 
    "<tr valign=\"top\">\n" );
            echo ( 
    "<td>$hour:$minute</td>\n" );

            
    // If the hour is selected, call the decorator method...
            
    if ( $Hour->isSelected() ) {
                echo ( 
    "<td bgcolor=\"silver\">" );

                
    // Loop through the entries in the hour
                
    while ( $entry $Hour->getEntry() ) {
                    echo  
    $entry."<br>";
                }

                echo ( 
    "</td>\n" );
            } else {
                echo ( 
    "<td>&nbsp;</td>\n" );
            }
            echo ( 
    "</tr>\n" );
        }
    }
    ?>
    </table>
    </body>
    </html>

  11. #11
    SitePoint Member
    Join Date
    May 2004
    Location
    Brisbane
    Posts
    19
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    HarryF, I really appreciate the help thus far and ask that you bear with me just a little further

    I used the same code in a week view and a month view but unfortunately have run into some problems.

    Code used was similar except that it varies in a couple of places
    - requires week.php
    - selection manager creates Calendar_Day, not Calendar_Hour
    - a Calendar_Week is created and built rather than a Calendar_Day

    Fairly straightforward and no surprises. My problem is that with viewing week/days rather than day/hours, once again ALL the events are not being listed.

    It seems to only list those events that occur on the same day as the last $row['eventtime']. So with the following

    PHP Code:
    //Create a week
    $Week = new Calendar_Week(200457);

    // An array simulating data from a database
    $result = array (
        array(
    'eventtime'=>mktime(0,0,0,5,2,2004),'entry'=>'Meeting with sales team'),
        array(
    'eventtime'=>mktime(0,0,0,5,7,2004),'entry'=>'Conference call with Widget Inc.'),
        array(
    'eventtime'=>mktime(0,0,0,5,2,2004),'entry'=>'Conference call with suppliers'),
        array(
    'eventtime'=>mktime(0,0,0,5,7,2004),'entry'=>'Presentation to board of directors')
        ); 
    Only those events occuring on the 7th of May are displayed.
    This is happening with both the week and month views.

    print_r($selection) shows that only those dates are stored in the array but print_r($SM) holds all the events so the problem is with the selection manager's getSelection().
    EDIT:
    I think the problem is being caused by
    PHP Code:
    foreach ( $this->events[$this->year][$this->month][$this->day] as $event ) { 
    being set (??) to the last value inserted. So if it could somehow reset..or something?

    I don't know if this is relevant but I'm using the latest release (version 0.5.1)
    Last edited by ehando; May 27, 2004 at 11:13. Reason: Narrowing down the problem

  12. #12
    SitePoint Wizard gold trophysilver trophy
    Join Date
    Nov 2000
    Location
    Switzerland
    Posts
    2,479
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Hmmm - weeks are more tricky because they're not something that directly relates to PHP's date function. You're right in spotting the problem - the solution lies in being able to identify by week not day.

    This might work as to modification of the SelectionManager's getEvent method;

    PHP Code:
        function & getEvent($timestamp) {
        
            
    // See manual on "W" option
            
    $human_date date("Y W n j",$timestamp);

            
    $date_array sscanf($human_date"%d %d %n %j");

            list(
    $year,$week_in_year$month$day) = $date_array;

            
    // Just assign the year        
            
    $this->year $year;

            
    // Do we have an event already for this time?
            
    if ( !isset($this->events[$year][$week_in_year]) {
                
    // If not create it
                
    $Week = new Calendar_Week($year,$month,$day);

                
    $DiaryEvent = & new DiaryEvent($Week);
                
    $this->events[$year][$week_in_year] = & $DiaryEvent;
            }
            
            
    // Return the event
            
    return $this->events[$year][$week_in_year];
        } 
    That may get wierd though around the beginning and end of a year, 'W' being the ISO-8601 week number. The alternative will probably be creating a Week every time getEvent is called, so you can use it to check if an event already exists - somewhat inefficient but lacking bright ideas right now.

    It's also worth being aware that the SelectionManager, as is, won't allow you to have selections spanning across multiple years - the applies to the original version as well. Needs some more thought there.

    Doing some work on Calendar at the moment and will see if there's a way to make stuff like this alot easier. Thanks for the feedback - helps alot.

  13. #13
    SitePoint Member
    Join Date
    May 2004
    Location
    Brisbane
    Posts
    19
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by HarryF
    Doing some work on Calendar at the moment and will see if there's a way to make stuff like this alot easier. Thanks for the feedback - helps alot.
    I should be the one thanking you. With my rather rusty PHP skills it's been a godsend to have someone with an intimate knowledge of the class lend a hand.

  14. #14
    SitePoint Enthusiast duff_beer's Avatar
    Join Date
    Jul 2003
    Location
    up in the clouds
    Posts
    51
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I just checked a new example in the pear cvs repository. In the near future we'll probably change a few things in PEAR::Calendar to make this sort of things easier.

    Until then, I hope this can be an useful starting point:
    http://cvs.php.net/co.php/pear/Calen...s/20.php?r=1.1

    Disclaimer: it's just a quick'n'dirty script, there are some things that may be done in a better way, for instance the MonthPayload_Decorator probably shouldn't be a decorator at all, but a class extending Calendar_Month_Weekdays, and Calendar_Decorator_Wrapper could help in writing a cleaner script. Nevertheless, it works, so someone may find it useful.
    I will update it when I have some more time.

  15. #15
    SitePoint Member
    Join Date
    May 2004
    Location
    Brisbane
    Posts
    19
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Thanks duff_beer, every little bit helps. Unfortunately I've decided to go with my own calendar class library. The reason for this was basically it's a lot easier for a PHP newbie to work out how the code works. I sat down and talked with the client's web developer and we both agreed that while PEAR::Calendar could do everything that was required, that a simpler solution would be the best solution in this case.

    Why? Basically the level of PHP experience and programming concepts (design patterns, classes, decorators) were a little too high for the ppl who would be in charge of maintaining the events calendar application. (My view - what maintance?!?)

    What this has meant is that the whole project is now simplified - PHP wise, database design wise. I don't particularly like or agree with it but that's what I'm getting paid to do.


Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •