source: trunk/include/calendar_monthly.class.php @ 12922

Last change on this file since 12922 was 12922, checked in by mistic100, 12 years ago

update Piwigo headers to 2012, last change before the expected (or not) apocalypse

  • Property svn:eol-style set to LF
File size: 14.4 KB
Line 
1<?php
2// +-----------------------------------------------------------------------+
3// | Piwigo - a PHP based photo gallery                                    |
4// +-----------------------------------------------------------------------+
5// | Copyright(C) 2008-2012 Piwigo Team                  http://piwigo.org |
6// | Copyright(C) 2003-2008 PhpWebGallery Team    http://phpwebgallery.net |
7// | Copyright(C) 2002-2003 Pierrick LE GALL   http://le-gall.net/pierrick |
8// +-----------------------------------------------------------------------+
9// | This program is free software; you can redistribute it and/or modify  |
10// | it under the terms of the GNU General Public License as published by  |
11// | the Free Software Foundation                                          |
12// |                                                                       |
13// | This program is distributed in the hope that it will be useful, but   |
14// | WITHOUT ANY WARRANTY; without even the implied warranty of            |
15// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      |
16// | General Public License for more details.                              |
17// |                                                                       |
18// | You should have received a copy of the GNU General Public License     |
19// | along with this program; if not, write to the Free Software           |
20// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
21// | USA.                                                                  |
22// +-----------------------------------------------------------------------+
23
24include_once(PHPWG_ROOT_PATH.'include/calendar_base.class.php');
25
26define ('CYEAR',  0);
27define ('CMONTH', 1);
28define ('CDAY',   2);
29
30/**
31 * Monthly calendar style (composed of years/months and days)
32 */
33class Calendar extends CalendarBase
34{
35
36  /**
37   * Initialize the calendar
38   * @param string inner_sql used for queries (INNER JOIN or normal)
39   */
40  function initialize($inner_sql)
41  {
42    parent::initialize($inner_sql);
43    global $lang;
44    $this->calendar_levels = array(
45      array(
46          'sql'=> pwg_db_get_year($this->date_field),
47          'labels' => null
48        ),
49      array(
50          'sql'=> pwg_db_get_month($this->date_field),
51          'labels' => $lang['month']
52        ),
53      array(
54          'sql'=> pwg_db_get_dayofmonth($this->date_field),
55          'labels' => null
56        ),
57     );
58  }
59
60/**
61 * Generate navigation bars for category page
62 * @return boolean false to indicate that thumbnails
63 * where not included here, true otherwise
64 */
65function generate_category_content()
66{
67  global $conf, $page;
68
69  $view_type = $page['chronology_view'];
70  if ($view_type==CAL_VIEW_CALENDAR)
71  {
72    global $template;
73    $tpl_var = array();
74    if ( count($page['chronology_date'])==0 )
75    {//case A: no year given - display all years+months
76      if ($this->build_global_calendar($tpl_var))
77      {
78        $template->assign('chronology_calendar', $tpl_var);
79        return true;
80      }
81    }
82
83    if ( count($page['chronology_date'])==1 )
84    {//case B: year given - display all days in given year
85      if ($this->build_year_calendar($tpl_var))
86      {
87        $template->assign('chronology_calendar', $tpl_var);
88        $this->build_nav_bar(CYEAR); // years
89        return true;
90      }
91    }
92
93    if ( count($page['chronology_date'])==2 )
94    {//case C: year+month given - display a nice month calendar
95      if ( $this->build_month_calendar($tpl_var) )
96      {
97        $template->assign('chronology_calendar', $tpl_var);
98      }
99      $this->build_next_prev();
100      return true;
101    }
102  }
103
104  if ($view_type==CAL_VIEW_LIST or count($page['chronology_date'])==3)
105  {
106    if ( count($page['chronology_date'])==0 )
107    {
108      $this->build_nav_bar(CYEAR); // years
109    }
110    if ( count($page['chronology_date'])==1)
111    {
112      $this->build_nav_bar(CMONTH); // month
113    }
114    if ( count($page['chronology_date'])==2 )
115    {
116      $day_labels = range( 1, $this->get_all_days_in_month(
117              $page['chronology_date'][CYEAR] ,$page['chronology_date'][CMONTH] ) );
118      array_unshift($day_labels, 0);
119      unset( $day_labels[0] );
120      $this->build_nav_bar( CDAY, $day_labels ); // days
121    }
122    $this->build_next_prev();
123  }
124  return false;
125}
126
127
128/**
129 * Returns a sql where subquery for the date field
130 * @param int max_levels return the where up to this level
131 * (e.g. 2=only year and month)
132 * @return string
133 */
134function get_date_where($max_levels=3)
135{
136  global $page;
137
138  $date = $page['chronology_date'];
139  while (count($date)>$max_levels)
140  {
141    array_pop($date);
142  }
143  $res = '';
144  if (isset($date[CYEAR]) and $date[CYEAR]!=='any')
145  {
146    $b = $date[CYEAR] . '-';
147    $e = $date[CYEAR] . '-';
148    if (isset($date[CMONTH]) and $date[CMONTH]!=='any')
149    {
150      $b .= sprintf('%02d-', $date[CMONTH]);
151      $e .= sprintf('%02d-', $date[CMONTH]);
152      if (isset($date[CDAY]) and $date[CDAY]!=='any')
153      {
154        $b .= sprintf('%02d', $date[CDAY]);
155        $e .= sprintf('%02d', $date[CDAY]);
156      }
157      else
158      {
159        $b .= '01';
160        $e .= $this->get_all_days_in_month($date[CYEAR], $date[CMONTH]);
161      }
162    }
163    else
164    {
165      $b .= '01-01';
166      $e .= '12-31';
167      if (isset($date[CMONTH]) and $date[CMONTH]!=='any')
168      {
169        $res .= ' AND '.$this->calendar_levels[CMONTH]['sql'].'='.$date[CMONTH];
170      }
171      if (isset($date[CDAY]) and $date[CDAY]!=='any')
172      {
173        $res .= ' AND '.$this->calendar_levels[CDAY]['sql'].'='.$date[CDAY];
174      }
175    }
176    $res = " AND $this->date_field BETWEEN '$b' AND '$e 23:59:59'" . $res;
177  }
178  else
179  {
180    $res = ' AND '.$this->date_field.' IS NOT NULL';
181    if (isset($date[CMONTH]) and $date[CMONTH]!=='any')
182    {
183      $res .= ' AND '.$this->calendar_levels[CMONTH]['sql'].'='.$date[CMONTH];
184    }
185    if (isset($date[CDAY]) and $date[CDAY]!=='any')
186    {
187      $res .= ' AND '.$this->calendar_levels[CDAY]['sql'].'='.$date[CDAY];
188    }
189  }
190  return $res;
191}
192
193
194
195//--------------------------------------------------------- private members ---
196
197// returns an array with all the days in a given month
198function get_all_days_in_month($year, $month)
199{
200  $md= array(1=>31,28,31,30,31,30,31,31,30,31,30,31);
201
202  if ( is_numeric($year) and $month==2)
203  {
204    $nb_days = $md[2];
205    if ( ($year%4==0)  and ( ($year%100!=0) or ($year%400!=0) ) )
206    {
207      $nb_days++;
208    }
209  }
210  elseif ( is_numeric($month) )
211  {
212    $nb_days = $md[ $month ];
213  }
214  else
215  {
216    $nb_days = 31;
217  }
218  return $nb_days;
219}
220
221function build_global_calendar(&$tpl_var)
222{
223  global $page;
224
225  assert( count($page['chronology_date']) == 0 );
226  $query='
227SELECT '.pwg_db_get_date_YYYYMM($this->date_field).' as period,
228  COUNT(distinct id) as count';
229  $query.= $this->inner_sql;
230  $query.= $this->get_date_where();
231  $query.= '
232  GROUP BY period
233  ORDER BY '.pwg_db_get_year($this->date_field).' DESC, '.pwg_db_get_month($this->date_field).' ASC';
234
235  $result = pwg_query($query);
236  $items=array();
237  while ($row = pwg_db_fetch_assoc($result))
238  {
239    $y = substr($row['period'], 0, 4);
240    $m = (int)substr($row['period'], 4, 2);
241    if ( ! isset($items[$y]) )
242    {
243      $items[$y] = array('nb_images'=>0, 'children'=>array() );
244    }
245    $items[$y]['children'][$m] = $row['count'];
246    $items[$y]['nb_images'] += $row['count'];
247  }
248  //echo ('<pre>'. var_export($items, true) . '</pre>');
249  if (count($items)==1)
250  {// only one year exists so bail out to year view
251    list($y) = array_keys($items);
252    $page['chronology_date'][CYEAR] = $y;
253    return false;
254  }
255
256  global $lang;
257  foreach ( $items as $year=>$year_data)
258  {
259    $chronology_date = array( $year );
260    $url = duplicate_index_url( array('chronology_date'=>$chronology_date) );
261
262    $nav_bar = $this->get_nav_bar_from_items( $chronology_date,
263            $year_data['children'], false, false, $lang['month'] );
264
265    $tpl_var['calendar_bars'][] =
266      array(
267        'U_HEAD'  => $url,
268        'NB_IMAGES' => $year_data['nb_images'],
269        'HEAD_LABEL' => $year,
270        'items' => $nav_bar,
271      );
272  }
273  return true;
274}
275
276function build_year_calendar(&$tpl_var)
277{
278  global $page;
279
280  assert( count($page['chronology_date']) == 1 );
281  $query='SELECT '.pwg_db_get_date_MMDD($this->date_field).' as period,
282            COUNT(DISTINCT id) as count';
283  $query.= $this->inner_sql;
284  $query.= $this->get_date_where();
285  $query.= '
286  GROUP BY period
287  ORDER BY period ASC';
288
289  $result = pwg_query($query);
290  $items=array();
291  while ($row = pwg_db_fetch_assoc($result))
292  {
293    $m = (int)substr($row['period'], 0, 2);
294    $d = substr($row['period'], 2, 2);
295    if ( ! isset($items[$m]) )
296    {
297      $items[$m] = array('nb_images'=>0, 'children'=>array() );
298    }
299    $items[$m]['children'][$d] = $row['count'];
300    $items[$m]['nb_images'] += $row['count'];
301  }
302  if (count($items)==1)
303  { // only one month exists so bail out to month view
304    list($m) = array_keys($items);
305    $page['chronology_date'][CMONTH] = $m;
306    return false;
307  }
308  global $lang;
309  foreach ( $items as $month=>$month_data)
310  {
311    $chronology_date = array( $page['chronology_date'][CYEAR], $month );
312    $url = duplicate_index_url( array('chronology_date'=>$chronology_date) );
313
314    $nav_bar = $this->get_nav_bar_from_items( $chronology_date,
315                     $month_data['children'], false );
316
317    $tpl_var['calendar_bars'][] =
318      array(
319        'U_HEAD'  => $url,
320        'NB_IMAGES' => $month_data['nb_images'],
321        'HEAD_LABEL' => $lang['month'][$month],
322        'items' => $nav_bar,
323      );
324  }
325  return true;
326
327}
328
329function build_month_calendar(&$tpl_var)
330{
331  global $page, $lang, $conf;
332
333  $query='SELECT '.pwg_db_get_dayofmonth($this->date_field).' as period,
334            COUNT(DISTINCT id) as count';
335  $query.= $this->inner_sql;
336  $query.= $this->get_date_where();
337  $query.= '
338  GROUP BY period
339  ORDER BY period ASC';
340
341  $items=array();
342  $result = pwg_query($query);
343  while ($row = pwg_db_fetch_assoc($result))
344  {
345    $d = (int)$row['period'];
346    $items[$d] = array('nb_images'=>$row['count']);
347  }
348
349  foreach ( $items as $day=>$data)
350  {
351    $page['chronology_date'][CDAY]=$day;
352    $query = '
353SELECT id, file,representative_ext,path,width, height, '.pwg_db_get_dayofweek($this->date_field).'-1 as dow';
354    $query.= $this->inner_sql;
355    $query.= $this->get_date_where();
356    $query.= '
357  ORDER BY '.DB_RANDOM_FUNCTION.'()
358  LIMIT 1';
359    unset ( $page['chronology_date'][CDAY] );
360
361    $row = pwg_db_fetch_assoc(pwg_query($query));
362    $derivative = new DerivativeImage(IMG_SQUARE, new SrcImage($row));
363    $items[$day]['derivative'] = $derivative;
364    $items[$day]['file'] = $row['file'];
365    $items[$day]['dow'] = $row['dow'];
366  }
367
368  if ( !empty($items) )
369  {
370    list($known_day) = array_keys($items);
371    $known_dow = $items[$known_day]['dow'];
372    $first_day_dow = ($known_dow-($known_day-1))%7;
373    if ($first_day_dow<0)
374    {
375      $first_day_dow += 7;
376    }
377    //first_day_dow = week day corresponding to the first day of this month
378    $wday_labels = $lang['day'];
379
380    if ('monday' == $conf['week_starts_on'])
381    {
382      if ($first_day_dow==0)
383      {
384        $first_day_dow = 6;
385      }
386      else
387      {
388        $first_day_dow -= 1;
389      }
390
391      array_push( $wday_labels, array_shift($wday_labels) );
392    }
393
394    list($cell_width, $cell_height) = ImageStdParams::get_by_type(IMG_SQUARE)->sizing->ideal_size;
395
396    $tpl_weeks    = array();
397    $tpl_crt_week = array();
398
399    //fill the empty days in the week before first day of this month
400    for ($i=0; $i<$first_day_dow; $i++)
401    {
402      $tpl_crt_week[] = array();
403    }
404
405    for ( $day = 1;
406          $day <= $this->get_all_days_in_month(
407            $page['chronology_date'][CYEAR], $page['chronology_date'][CMONTH]
408              );
409          $day++)
410    {
411      $dow = ($first_day_dow + $day-1)%7;
412      if ($dow==0 and $day!=1)
413      {
414        $tpl_weeks[]    = $tpl_crt_week; // add finished week to week list
415        $tpl_crt_week   = array(); // start new week
416      }
417
418      if ( !isset($items[$day]) )
419      {// empty day
420        $tpl_crt_week[]   =
421          array(
422              'DAY' => $day
423            );
424      }
425      else
426      {
427        list($tn_width,$tn_height) = $items[$day]['derivative']->get_size();
428
429        // now need to fit the thumbnail of size tn_size within
430        // a cell of size cell_size by playing with CSS position (left/top)
431        // and the width and height of <img>.
432        $ratio_w = $tn_width/$cell_width;
433        $ratio_h = $tn_height/$cell_height;
434
435        $pos_top=$pos_left=0;
436        $css_style = '';
437
438        if ( $ratio_w>1 and $ratio_h>1)
439        {// cell completely smaller than the thumbnail so we will let the browser
440         // resize the thumbnail
441          if ($ratio_w > $ratio_h )
442          {// thumbnail ratio compared to cell -> wide format
443            $css_style = 'height:'.$cell_height.'px;';
444            $browser_img_width = $cell_height*$tn_width/$tn_height;
445            $pos_left = ($browser_img_width-$cell_width)/2;
446          }
447          else
448          {
449            $css_style = 'width:'.$cell_width.'px;';
450            $browser_img_height = $cell_width*$tn_height/$tn_width;
451            $pos_top = ($browser_img_height-$cell_height)/2;
452          }
453        }
454        else
455        {
456          $pos_left = ($tn_width-$cell_width)/2;
457          $pos_top = ($tn_height-$cell_height)/2;
458        }
459
460        if ( round($pos_left)!=0)
461        {
462          $css_style.='left:'.round(-$pos_left).'px;';
463        }
464        if ( round($pos_top)!=0)
465        {
466          $css_style.='top:'.round(-$pos_top).'px;';
467        }
468        $url = duplicate_index_url(
469            array(
470              'chronology_date' =>
471                array(
472                  $page['chronology_date'][CYEAR],
473                  $page['chronology_date'][CMONTH],
474                  $day
475                )
476            )
477          );
478
479        $tpl_crt_week[]   =
480          array(
481              'DAY'         => $day,
482              'DOW'         => $dow,
483              'NB_ELEMENTS' => $items[$day]['nb_images'],
484              'IMAGE'       => $items[$day]['derivative']->get_url(),
485              'U_IMG_LINK'  => $url,
486              'IMAGE_STYLE' => $css_style,
487              'IMAGE_ALT'   => $items[$day]['file'],
488            );
489      }
490    }
491    //fill the empty days in the week after the last day of this month
492    while ( $dow<6 )
493    {
494      $tpl_crt_week[] = array();
495      $dow++;
496    }
497    $tpl_weeks[]    = $tpl_crt_week;
498
499    $tpl_var['month_view'] =
500        array(
501           'CELL_WIDTH'   => $cell_width,
502           'CELL_HEIGHT' => $cell_height,
503           'wday_labels' => $wday_labels,
504           'weeks' => $tpl_weeks,
505          );
506  }
507
508  return true;
509}
510
511}
512?>
Note: See TracBrowser for help on using the repository browser.