List of events with a list of timestamps, grouped

2019-02-19 17:03发布

问题:

While refactoring, I am looking for an optimised algorithm for a timetable (calendar) in PHP.

I have a list of events which have a list of timestamps. This must be presented in a tabular way. The current code works, but has a) quite some quircks and is b) very inflexible. I am looking to refactor this piece and looking for input on optimised ways.

Example here, notice the header of the table bearing the hours. And the times within that hour being grouped in that column. One event, having two timestamps in one hour can be ignored (may only happen in theory, as per the technical docs)

The table is built with Drupals theme_table(), which I can build up from any array, bearing arrays for each row. the Drupal part, however, is of little interest here :)

Current code (snippets):

<?php
//inside function that builds the content for the page linked to above:
$this_morning = _playdates_get_start_of_day_with($timestamp);
$this_night = _playdates_get_end_of_day_with($timestamp);
$nodes = _playdates_load_all_in_range($types, $this_morning, $this_night);
usort($nodes, '_playdates_cmp_titles');
//we now have a list of "nodes", being the events listed in the first column, which have
//  a list of playdates, the timestamps. $node->nid is a unique id for each event.  
foreach ($nodes as $node) {
  $times = $dates = array();
  if (is_array($node->starts_at)) {
    foreach ($node->starts_at as $starts_at) {
      $date = getdate($starts_at);
      $dates[$starts_at] = $date;
      if (!isset($active) && ($timestamp <= ($date[0] + $timezone))) {
        $active = _playdates_get_idx_hour($date);
      }
    }
    $times = _playdates_group_by_hour($dates);
    foreach ($times as $key => $value) {
      $header_times[$key] = $key;
    }
    $header = array_merge($header, $header_times);
    $entries[$node->nid] = $node;
    $entries[$node->nid]->times = $times;
  }
}

function _playdates_group_by_hour($timestamps, $playdate = NULL) {
  $indexes = array();
  foreach ($timestamps as $key => $value) {
    $indexes[_playdates_get_idx_hour($value)] = theme('playdates_format_time', $value, $playdate);
  }
  ksort($indexes);
  return $indexes;
}   

function _playdates_get_idx_hour($date) {
  return playdates_format_date($date[0], 'custom', 'H:00');
}

So, the pattern is: grab (and order) the list of events. Loop over that, for each event, loop over the timestamps and create an array with the key being the hour of the timestamp (group by hours).

Are there better patterns? Is there a more generic way to achieve this? Any keywords that I can search for (I have no idea how such a pattern would be called)?

example dataset The $nodes (unnessecary data removed) look like this:

array(15) {
  [1]=>
  object(stdClass)#48 (6) {
    ["title"]=> 
    string(19) "Cosa voglio di più"
    ["type"]=>
    string(4) "film"
    ["nid"]=>
    string(4) "2823"
    ["premiere"]=>
    object(stdClass)#49 (1) {
      ["starts_at"]=>
      string(10) "1286550000"
    }
    ["starts_at"]=>
    array(2) {
      [0]=>
      string(10) "1286550000"
      [1]=>
      string(10) "1286559000"
    }
    ["ends_at"]=>
    array(2) {
      [0]=>
      string(1) "0"
      [1]=>
      string(1) "0"
    }
  }
  [12]=>
  object(stdClass)#46 (6) {
    ["title"]=>
    string(5) "Tirza"
    ["type"]=>
    string(4) "film"
    ["nid"]=>
    string(4) "2813"
    ["premiere"]=>
    object(stdClass)#47 (1) {
      ["starts_at"]=>
      string(10) "1286550000"
    }
    ["starts_at"]=>
    array(3) {
      [0]=>
      string(10) "1286550000"
      [1]=>
      string(10) "1286558100"
      [2]=>
      string(10) "1286566200"
    }
    ["ends_at"]=>
    array(3) {
      [0]=>
      string(1) "0"
      [1]=>
      string(1) "0"
      [2]=>
      string(1) "0"
    }
  }
  [14]=>
  object(stdClass)#36 (6) {
    ["title"]=>
    string(47) "Vision - aus dem Leben der Hildegard von Bingen"
    ["type"]=>
    string(4) "film"
    ["nid"]=>
    string(4) "2783"
    ["premiere"]=>
    object(stdClass)#39 (1) {
      ["starts_at"]=>
      string(10) "1286541900"
    }
    ["starts_at"]=>
    array(1) {
      [0]=>
      string(10) "1286541900"
    }
    ["ends_at"]=>
    array(1) {
      [0]=>
      string(1) "0"
    }
  }
}

回答1:

I'm not familiar with Drupal at all, so I'm going to make a suggestion based on my own approach to your request to refactor the display of a list of movie titles in one column, and the start time in the appropriate time column.

You are starting with an array of movies (or 'films') containing movie titles and start timestamps. I assume somewhere you can retrieve or create an array of hours for the column title.

The example below ignores that you are dealing with an object, or that the object contains arrays, only to exhibit an alternate pattern approach. Rather than all the formatting and sorting you appear to be doing, this pattern iterates over each movie and uses a second foreach to iterate over the hour columns, and tests if the movie time matches the hour time.

<?php foreach($movie_array as $movie){
    echo '<td>'.$movie['title'].'</td>';
    foreach($hours as $hour){
        if(date('H',$movie['starts_at']) == date('H',$hour)){
            echo '<td>'.date('H:i',$movie['starts_at']).'</td>';
        }//endif
        else{
            echo '<td></td>';
        }//endelse
    }//endforeach
 }//endforeach
?>

I've skipped setting up the table, and of course, you could replace my html entities with however you prefer to set up the table.

I think this is a viable pattern that seems to simplify the logic of your original pattern, and remains flexible. Hopefully I haven't misunderstood and omitted a critical part of your problem.



回答2:

Have you tried "Calendar" module. The Calendar module can be used to list the events as calendar. It is having views, taxonomy and cck support. The customization is also very easy.

I am suggesting to find out contributed modules before thinking about our script. We can think about our script only if there is no contributed modules which satisfies our requirements.