source: trunk/include/functions_category.inc.php @ 29268

Last change on this file since 29268 was 28587, checked in by mistic100, 10 years ago

feature 3010 : replace trigger_action/event by trigger_notify/change

  • Property svn:eol-style set to LF
File size: 16.5 KB
RevLine 
[2]1<?php
[362]2// +-----------------------------------------------------------------------+
[8728]3// | Piwigo - a PHP based photo gallery                                    |
[2297]4// +-----------------------------------------------------------------------+
[26461]5// | Copyright(C) 2008-2014 Piwigo Team                  http://piwigo.org |
[2297]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// +-----------------------------------------------------------------------+
[2]23
[423]24/**
[25508]25 * @package functions\category
[423]26 */
27
[25508]28
[423]29/**
[25508]30 * Callback used for sorting by global_rank
31 */
32function global_rank_compare($a, $b)
33{
34  return strnatcasecmp($a['global_rank'], $b['global_rank']);
35}
36
37/**
38 * Callback used for sorting by rank
39 */
40function rank_compare($a, $b)
41{
42  return $a['rank'] - $b['rank'];
43}
44
45/**
[423]46 * Is the category accessible to the connected user ?
[25508]47 * If the user is not authorized to see this category, script exits
[423]48 *
[25508]49 * @param int $category_id
[423]50 */
[808]51function check_restrictions($category_id)
[2]52{
[1113]53  global $user;
[2]54
[1677]55  // $filter['visible_categories'] and $filter['visible_images']
56  // are not used because it's not necessary (filter <> restriction)
[808]57  if (in_array($category_id, explode(',', $user['forbidden_categories'])))
[2]58  {
[1113]59    access_denied();
[2]60  }
61}
[345]62
[25508]63/**
64 * Returns template vars for main categories menu.
65 *
66 * @return array[]
67 */
[614]68function get_categories_menu()
[2]69{
[11285]70  global $page, $user, $filter, $conf;
[1059]71
[1624]72  $query = '
73SELECT ';
74  // From CATEGORIES_TABLE
75  $query.= '
[1866]76  id, name, permalink, nb_images, global_rank,';
[1624]77  // From USER_CACHE_CATEGORIES_TABLE
78  $query.= '
[1641]79  date_last, max_date_last, count_images, count_categories';
[1059]80
[1624]81  // $user['forbidden_categories'] including with USER_CACHE_CATEGORIES_TABLE
82  $query.= '
[1677]83FROM '.CATEGORIES_TABLE.' INNER JOIN '.USER_CACHE_CATEGORIES_TABLE.'
[1624]84  ON id = cat_id and user_id = '.$user['id'];
[1677]85
86  // Always expand when filter is activated
87  if (!$user['expand'] and !$filter['enabled'])
[345]88  {
[2070]89    $where = '
[1677]90(id_uppercat is NULL';
91    if (isset($page['category']))
92    {
[2070]93      $where .= ' OR id_uppercat IN ('.$page['category']['uppercats'].')';
[1677]94    }
[2070]95    $where .= ')';
[1648]96  }
97  else
98  {
[2070]99    $where = '
[1677]100  '.get_sql_condition_FandF
101    (
102      array
103        (
104          'visible_categories' => 'id',
105        ),
[2070]106      null,
107      true
[1677]108    );
[2]109  }
[1677]110
[28587]111  $where = trigger_change('get_categories_menu_sql_where',
[2070]112    $where, $user['expand'], $filter['enabled'] );
113
[589]114  $query.= '
[2070]115WHERE '.$where.'
[589]116;';
[26]117
[589]118  $result = pwg_query($query);
[614]119  $cats = array();
[3171]120  $selected_category = isset($page['category']) ? $page['category'] : null;
[4325]121  while ($row = pwg_db_fetch_assoc($result))
[2]122  {
[3171]123    $child_date_last = @$row['max_date_last']> @$row['date_last'];
124    $row = array_merge($row,
125      array(
[28587]126        'NAME' => trigger_change(
[3171]127          'render_category_name',
128          $row['name'],
129          'get_categories_menu'
[11285]130          ),
[3171]131        'TITLE' => get_display_images_count(
132          $row['nb_images'],
133          $row['count_images'],
134          $row['count_categories'],
135          false,
136          ' / '
[11285]137          ),
[3171]138        'URL' => make_index_url(array('category' => $row)),
139        'LEVEL' => substr_count($row['global_rank'], '.') + 1,
140        'SELECTED' => $selected_category['id'] == $row['id'] ? true : false,
141        'IS_UPPERCAT' => $selected_category['id_uppercat'] == $row['id'] ? true : false,
[11285]142        )
143      );
144    if ($conf['index_new_icon'])
145    {
146      $row['icon_ts'] = get_icon($row['max_date_last'], $child_date_last);
147    }
[18579]148    $cats[] = $row;
[2586]149    if ($row['id']==@$page['category']['id']) //save the number of subcats for later optim
150      $page['category']['count_categories'] = $row['count_categories'];
[26]151  }
[614]152  usort($cats, 'global_rank_compare');
[2]153
[1677]154  // Update filtered data
[1722]155  if (function_exists('update_cats_with_filtered_data'))
156  {
157    update_cats_with_filtered_data($cats);
158  }
[1677]159
[3171]160  return $cats;
[26]161}
[2]162
[761]163/**
[25508]164 * Retrieves informations about a category.
[423]165 *
[25508]166 * @param int $id
[423]167 * @return array
168 */
[25508]169function get_cat_info($id)
[2]170{
[603]171  $query = '
[1861]172SELECT *
[603]173  FROM '.CATEGORIES_TABLE.'
174  WHERE id = '.$id.'
175;';
[4325]176  $cat = pwg_db_fetch_assoc(pwg_query($query));
[1861]177  if (empty($cat))
[1288]178    return null;
[345]179
[1861]180  foreach ($cat as $k => $v)
[603]181  {
[345]182    // If the field is true or false, the variable is transformed into a
183    // boolean value.
[1861]184    if ($cat[$k] == 'true' or $cat[$k] == 'false')
[345]185    {
[1861]186      $cat[$k] = get_boolean( $cat[$k] );
[345]187    }
188  }
189
[1866]190  $upper_ids = explode(',', $cat['uppercats']);
191  if ( count($upper_ids)==1 )
192  {// no need to make a query for level 1
193    $cat['upper_names'] = array(
194        array(
195          'id' => $cat['id'],
196          'name' => $cat['name'],
197          'permalink' => $cat['permalink'],
198          )
199      );
200  }
201  else
[2]202  {
[1866]203    $query = '
204  SELECT id, name, permalink
205    FROM '.CATEGORIES_TABLE.'
206    WHERE id IN ('.$cat['uppercats'].')
207  ;';
[27369]208    $names = query2array($query, 'id');
[672]209
[1866]210    // category names must be in the same order than uppercats list
211    $cat['upper_names'] = array();
212    foreach ($upper_ids as $cat_id)
213    {
[18579]214      $cat['upper_names'][] = $names[$cat_id];
[1866]215    }
[672]216  }
[2]217  return $cat;
218}
[61]219
[25508]220/**
221 * Returns an array of image orders available for users/visitors.
222 * Each entry is an array containing
223 *  0: name
224 *  1: SQL ORDER command
225 *  2: visiblity (true or false)
226 *
227 * @return array[]
228 */
[1020]229function get_category_preferred_image_orders()
230{
[2517]231  global $conf, $page;
[18579]232
[28587]233  return trigger_change('get_category_preferred_image_orders', array(
[13839]234    array(l10n('Default'),                        '',                     true),
[23813]235    array(l10n('Photo title, A &rarr; Z'),        'name ASC',             true),
[13839]236    array(l10n('Photo title, Z &rarr; A'),        'name DESC',            true),
237    array(l10n('Date created, new &rarr; old'),   'date_creation DESC',   true),
[23813]238    array(l10n('Date created, old &rarr; new'),   'date_creation ASC',    true),
[13839]239    array(l10n('Date posted, new &rarr; old'),    'date_available DESC',  true),
[23813]240    array(l10n('Date posted, old &rarr; new'),    'date_available ASC',   true),
[13839]241    array(l10n('Rating score, high &rarr; low'),  'rating_score DESC',    $conf['rate']),
[23813]242    array(l10n('Rating score, low &rarr; high'),  'rating_score ASC',     $conf['rate']),
[13839]243    array(l10n('Visits, high &rarr; low'),        'hit DESC',             true),
[23813]244    array(l10n('Visits, low &rarr; high'),        'hit ASC',              true),
[13839]245    array(l10n('Permissions'),                    'level DESC',           is_admin()),
[2521]246    ));
[1020]247}
248
[25508]249/**
250 * Assign a template var useable with {html_options} from a list of categories
251 *
252 * @param array[] $categories (at least id,name,global_rank,uppercats for each)
253 * @param int[] $selected ids of selected items
254 * @param string $blockname variable name in template
255 * @param bool $fullname full breadcrumb or not
256 */
[589]257function display_select_categories($categories,
258                                   $selecteds,
[602]259                                   $blockname,
[614]260                                   $fullname = true)
[589]261{
[614]262  global $template;
[589]263
[2223]264  $tpl_cats = array();
265  foreach ($categories as $category)
266  {
267    if ($fullname)
268    {
[11512]269      $option = strip_tags(
270        get_cat_display_name_cache(
271          $category['uppercats'],
[25425]272          null
[11512]273          )
274        );
[2223]275    }
276    else
277    {
278      $option = str_repeat('&nbsp;',
279                           (3 * substr_count($category['global_rank'], '.')));
[2433]280      $option.= '- ';
281      $option.= strip_tags(
[28587]282        trigger_change(
[2433]283          'render_category_name',
284          $category['name'],
285          'display_select_categories'
286          )
287        );
[2223]288    }
289    $tpl_cats[ $category['id'] ] = $option;
290  }
291
[2290]292  $template->assign( $blockname, $tpl_cats);
293  $template->assign( $blockname.'_selected', $selecteds);
[589]294}
[603]295
[25508]296/**
297 * Same as display_select_categories but categories are ordered by rank
298 * @see display_select_categories()
299 */
300function display_select_cat_wrapper($query,
301                                    $selecteds,
302                                    $blockname,
[614]303                                    $fullname = true)
304{
[27369]305  $categories = query2array($query);
[614]306  usort($categories, 'global_rank_compare');
307  display_select_categories($categories, $selecteds, $blockname, $fullname);
308}
309
[603]310/**
[25508]311 * Returns all subcategory identifiers of given category ids
[603]312 *
[25508]313 * @param int[] $ids
314 * @return int[]
[603]315 */
316function get_subcat_ids($ids)
317{
318  $query = '
319SELECT DISTINCT(id)
320  FROM '.CATEGORIES_TABLE.'
321  WHERE ';
322  foreach ($ids as $num => $category_id)
323  {
[1861]324    is_numeric($category_id)
325      or trigger_error(
326        'get_subcat_ids expecting numeric, not '.gettype($category_id),
327        E_USER_WARNING
328      );
[603]329    if ($num > 0)
330    {
331      $query.= '
332    OR ';
333    }
[4367]334    $query.= 'uppercats '.DB_REGEX_OPERATOR.' \'(^|,)'.$category_id.'(,|$)\'';
[603]335  }
336  $query.= '
337;';
[18579]338  return array_from_query($query, 'id');
[603]339}
[614]340
[25508]341/**
342 * Finds a matching category id from a potential list of permalinks
343 *
344 * @param string[] $permalinks
[25658]345 * @param int &$idx filled with the index in $permalinks that matches
[25508]346 * @return int|null
[1866]347 */
[25508]348function get_cat_id_from_permalinks($permalinks, &$idx)
[1866]349{
[2047]350  $in = '';
351  foreach($permalinks as $permalink)
[1866]352  {
[2047]353    if ( !empty($in) ) $in.=', ';
[6664]354    $in .= '\''.$permalink.'\'';
[1866]355  }
[2047]356  $query ='
[2356]357SELECT cat_id AS id, permalink, 1 AS is_old
358  FROM '.OLD_PERMALINKS_TABLE.'
359  WHERE permalink IN ('.$in.')
[2047]360UNION
361SELECT id, permalink, 0 AS is_old
362  FROM '.CATEGORIES_TABLE.'
363  WHERE permalink IN ('.$in.')
364;';
[27369]365  $perma_hash = query2array($query, 'permalink');
[1866]366
[2047]367  if ( empty($perma_hash) )
368    return null;
369  for ($i=count($permalinks)-1; $i>=0; $i--)
[1866]370  {
[2047]371    if ( isset( $perma_hash[ $permalinks[$i] ] ) )
372    {
373      $idx = $i;
374      $cat_id = $perma_hash[ $permalinks[$i] ]['id'];
375      if ($perma_hash[ $permalinks[$i] ]['is_old'])
376      {
377        $query='
[1866]378UPDATE '.OLD_PERMALINKS_TABLE.' SET last_hit=NOW(), hit=hit+1
[6654]379  WHERE permalink=\''.$permalinks[$i].'\' AND cat_id='.$cat_id.'
[1866]380  LIMIT 1';
[2047]381        pwg_query($query);
382      }
383      return $cat_id;
384    }
[1866]385  }
[2047]386  return null;
[1866]387}
388
[1624]389/**
[25508]390 * Returns display text for images counter of category
[1624]391 *
[25508]392 * @param int $cat_nb_images nb images directly in category
393 * @param int $cat_count_images nb images in category (including subcats)
394 * @param int $cat_count_categories nb subcats
395 * @param bool $short_message if true append " in this album"
396 * @param string $separator
[1624]397 * @return string
398 */
[25508]399function get_display_images_count($cat_nb_images, $cat_count_images, $cat_count_categories, $short_message = true, $separator = '\n')
[1624]400{
401  $display_text = '';
402
[1851]403  if ($cat_count_images > 0)
404  {
405    if ($cat_nb_images > 0 and $cat_nb_images < $cat_count_images)
406    {
[25508]407      $display_text.= get_display_images_count($cat_nb_images, $cat_nb_images, 0, $short_message, $separator).$separator;
[1851]408      $cat_count_images-= $cat_nb_images;
409      $cat_nb_images = 0;
410    }
[2117]411
[1851]412    //at least one image direct or indirect
[8665]413    $display_text.= l10n_dec('%d photo', '%d photos', $cat_count_images);
[1624]414
[1851]415    if ($cat_count_categories == 0 or $cat_nb_images == $cat_count_images)
416    {
417      //no descendant categories or descendants do not contain images
[25508]418      if (!$short_message)
[1624]419      {
[6951]420        $display_text.= ' '.l10n('in this album');
[1624]421      }
422    }
423    else
424    {
[6951]425      $display_text.= ' '.l10n_dec('in %d sub-album', 'in %d sub-albums', $cat_count_categories);
[1624]426    }
427  }
428
429  return $display_text;
430}
431
[8802]432/**
[25508]433 * Find a random photo among all photos inside an album (including sub-albums)
[8802]434 *
[25508]435 * @param array $category (at least id,uppercats,count_images)
436 * @param bool $recursive
437 * @return int|null
[8802]438 */
[11481]439function get_random_image_in_category($category, $recursive=true)
[8802]440{
441  $image_id = null;
442  if ($category['count_images']>0)
443  {
444    $query = '
445SELECT image_id
446  FROM '.CATEGORIES_TABLE.' AS c
447    INNER JOIN '.IMAGE_CATEGORY_TABLE.' AS ic ON ic.category_id = c.id
[11481]448  WHERE ';
449    if ($recursive)
450    {
451      $query.= '
452    (c.id='.$category['id'].' OR uppercats LIKE \''.$category['uppercats'].',%\')';
453    }
454    else
455    {
456      $query.= '
457    c.id='.$category['id'];
458    }
459    $query.= '
460    '.get_sql_condition_FandF
[8802]461    (
462      array
463        (
464          'forbidden_categories' => 'c.id',
465          'visible_categories' => 'c.id',
466          'visible_images' => 'image_id',
467        ),
468      "\n  AND"
469    ).'
470  ORDER BY '.DB_RANDOM_FUNCTION.'()
471  LIMIT 1
472;';
473    $result = pwg_query($query);
474    if (pwg_db_num_rows($result) > 0)
475    {
476      list($image_id) = pwg_db_fetch_row($result);
477    }
478  }
479
480  return $image_id;
481}
[11155]482
[25728]483/**
484 * Get computed array of categories, that means cache data of all categories
485 * available for the current user (count_categories, count_images, etc.).
486 *
487 * @param array &$userdata
488 * @param int $filter_days number of recent days to filter on or null
489 * @return array
490 */
491function get_computed_categories(&$userdata, $filter_days=null)
492{
493  $query = 'SELECT c.id AS cat_id, id_uppercat';
494  // Count by date_available to avoid count null
495  $query .= ',
496  MAX(date_available) AS date_last, COUNT(date_available) AS nb_images
497FROM '.CATEGORIES_TABLE.' as c
498  LEFT JOIN '.IMAGE_CATEGORY_TABLE.' AS ic ON ic.category_id = c.id
499  LEFT JOIN '.IMAGES_TABLE.' AS i
500    ON ic.image_id = i.id
501      AND i.level<='.$userdata['level'];
502
503  if ( isset($filter_days) )
504  {
505    $query .= ' AND i.date_available > '.pwg_db_get_recent_period_expression($filter_days);
506  }
507
508  if ( !empty($userdata['forbidden_categories']) )
509  {
510    $query.= '
511  WHERE c.id NOT IN ('.$userdata['forbidden_categories'].')';
512  }
513
514  $query.= '
515  GROUP BY c.id';
516
517  $result = pwg_query($query);
518
519  $userdata['last_photo_date'] = null;
520  $cats = array();
521  while ($row = pwg_db_fetch_assoc($result))
522  {
523    $row['user_id'] = $userdata['id'];
524    $row['nb_categories'] = 0;
525    $row['count_categories'] = 0;
526    $row['count_images'] = (int)$row['nb_images'];
527    $row['max_date_last'] = $row['date_last'];
528    if ($row['date_last'] > $userdata['last_photo_date'])
529    {
530      $userdata['last_photo_date'] = $row['date_last'];
531    }
532
533    $cats[$row['cat_id']] = $row;
534  }
535
536  foreach ($cats as $cat)
537  {
538    if ( !isset( $cat['id_uppercat'] ) )
539      continue;
540
[27926]541    // Piwigo before 2.5.3 may have generated inconsistent permissions, ie
542    // private album A1/A2 permitted to user U1 but private album A1 not
543    // permitted to U1.
544    //
545    // TODO 2.7: add an upgrade script to repair permissions and remove this
546    // test
547    if ( !isset($cats[ $cat['id_uppercat'] ]))
548      continue;
549
[25728]550    $parent = & $cats[ $cat['id_uppercat'] ];
551    $parent['nb_categories']++;
552
553    do
554    {
555      $parent['count_images'] += $cat['nb_images'];
556      $parent['count_categories']++;
557
558      if ((empty($parent['max_date_last'])) or ($parent['max_date_last'] < $cat['date_last']))
559      {
560        $parent['max_date_last'] = $cat['date_last'];
561      }
562
563      if ( !isset( $parent['id_uppercat'] ) )
564        break;
565      $parent = & $cats[$parent['id_uppercat']];
566    }
567    while (true);
568    unset($parent);
569  }
570
571  if ( isset($filter_days) )
572  {
573    foreach ($cats as $category)
574    {
575      if (empty($category['max_date_last']))
576      {
577        remove_computed_category($cats, $category);
578      }
579    }
580  }
581  return $cats;
582}
583
584/**
585 * Removes a category from computed array of categories and updates counters.
586 *
587 * @param array &$cats
588 * @param array $cat category to remove
589 */
590function remove_computed_category(&$cats, $cat)
591{
592  if ( isset($cats[$cat['id_uppercat']]) )
593  {
594    $parent = &$cats[ $cat['id_uppercat'] ];
595    $parent['nb_categories']--;
596
597    do
598    {
599      $parent['count_images'] -= $cat['nb_images'];
600      $parent['count_categories'] -= 1+$cat['count_categories'];
601
602      if ( !isset($cats[$parent['id_uppercat']]) )
603      {
604        break;
605      }
606      $parent = &$cats[$parent['id_uppercat']];
607    }
608    while (true);
609  }
610
611  unset($cats[$cat['cat_id']]);
612}
613
[2770]614?>
Note: See TracBrowser for help on using the repository browser.