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

Last change on this file since 16878 was 14143, checked in by rvelices, 12 years ago

bug 2615 php notice in calendar amd web service
multisize improve handling of cases where the original is smaller than a requested derivative, but rotation/watermarking is required

  • Property svn:eol-style set to LF
File size: 14.5 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,rotation, '.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    if ($cell_width>120)
396    {
397      $cell_width = $cell_height = 120;
398    }
399
400    $tpl_weeks    = array();
401    $tpl_crt_week = array();
402
403    //fill the empty days in the week before first day of this month
404    for ($i=0; $i<$first_day_dow; $i++)
405    {
406      $tpl_crt_week[] = array();
407    }
408
409    for ( $day = 1;
410          $day <= $this->get_all_days_in_month(
411            $page['chronology_date'][CYEAR], $page['chronology_date'][CMONTH]
412              );
413          $day++)
414    {
415      $dow = ($first_day_dow + $day-1)%7;
416      if ($dow==0 and $day!=1)
417      {
418        $tpl_weeks[]    = $tpl_crt_week; // add finished week to week list
419        $tpl_crt_week   = array(); // start new week
420      }
421
422      if ( !isset($items[$day]) )
423      {// empty day
424        $tpl_crt_week[]   =
425          array(
426              'DAY' => $day
427            );
428      }
429      else
430      {
431        list($tn_width,$tn_height) = $items[$day]['derivative']->get_size();
432
433        // now need to fit the thumbnail of size tn_size within
434        // a cell of size cell_size by playing with CSS position (left/top)
435        // and the width and height of <img>.
436        $ratio_w = $tn_width/$cell_width;
437        $ratio_h = $tn_height/$cell_height;
438
439        $pos_top=$pos_left=0;
440        $css_style = '';
441
442        if ( $ratio_w>1 and $ratio_h>1)
443        {// cell completely smaller than the thumbnail so we will let the browser
444         // resize the thumbnail
445          if ($ratio_w > $ratio_h )
446          {// thumbnail ratio compared to cell -> wide format
447            $css_style = 'height:'.$cell_height.'px;';
448            $browser_img_width = $cell_height*$tn_width/$tn_height;
449            $pos_left = ($browser_img_width-$cell_width)/2;
450          }
451          else
452          {
453            $css_style = 'width:'.$cell_width.'px;';
454            $browser_img_height = $cell_width*$tn_height/$tn_width;
455            $pos_top = ($browser_img_height-$cell_height)/2;
456          }
457        }
458        else
459        {
460          $pos_left = ($tn_width-$cell_width)/2;
461          $pos_top = ($tn_height-$cell_height)/2;
462        }
463
464        if ( round($pos_left)!=0)
465        {
466          $css_style.='left:'.round(-$pos_left).'px;';
467        }
468        if ( round($pos_top)!=0)
469        {
470          $css_style.='top:'.round(-$pos_top).'px;';
471        }
472        $url = duplicate_index_url(
473            array(
474              'chronology_date' =>
475                array(
476                  $page['chronology_date'][CYEAR],
477                  $page['chronology_date'][CMONTH],
478                  $day
479                )
480            )
481          );
482
483        $tpl_crt_week[]   =
484          array(
485              'DAY'         => $day,
486              'DOW'         => $dow,
487              'NB_ELEMENTS' => $items[$day]['nb_images'],
488              'IMAGE'       => $items[$day]['derivative']->get_url(),
489              'U_IMG_LINK'  => $url,
490              'IMAGE_STYLE' => $css_style,
491              'IMAGE_ALT'   => $items[$day]['file'],
492            );
493      }
494    }
495    //fill the empty days in the week after the last day of this month
496    while ( $dow<6 )
497    {
498      $tpl_crt_week[] = array();
499      $dow++;
500    }
501    $tpl_weeks[]    = $tpl_crt_week;
502
503    $tpl_var['month_view'] =
504        array(
505           'CELL_WIDTH'   => $cell_width,
506           'CELL_HEIGHT' => $cell_height,
507           'wday_labels' => $wday_labels,
508           'weeks' => $tpl_weeks,
509          );
510  }
511
512  return true;
513}
514
515}
516?>
Note: See TracBrowser for help on using the repository browser.