source: trunk/include/functions_tag.inc.php @ 2135

Last change on this file since 2135 was 2087, checked in by rvelices, 17 years ago

bug 376: improved get_available_tags sql queries for large databases

  • Property svn:eol-style set to LF
  • Property svn:keywords set to Author Date Id Revision
File size: 7.6 KB
Line 
1<?php
2// +-----------------------------------------------------------------------+
3// | PhpWebGallery - a PHP based picture gallery                           |
4// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
5// | Copyright (C) 2003-2007 PhpWebGallery Team - http://phpwebgallery.net |
6// +-----------------------------------------------------------------------+
7// | file          : $Id: functions_tag.inc.php 2087 2007-09-12 03:37:01Z rvelices $
8// | last update   : $Date: 2007-09-12 03:37:01 +0000 (Wed, 12 Sep 2007) $
9// | last modifier : $Author: rvelices $
10// | revision      : $Revision: 2087 $
11// +-----------------------------------------------------------------------+
12// | This program is free software; you can redistribute it and/or modify  |
13// | it under the terms of the GNU General Public License as published by  |
14// | the Free Software Foundation                                          |
15// |                                                                       |
16// | This program is distributed in the hope that it will be useful, but   |
17// | WITHOUT ANY WARRANTY; without even the implied warranty of            |
18// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      |
19// | General Public License for more details.                              |
20// |                                                                       |
21// | You should have received a copy of the GNU General Public License     |
22// | along with this program; if not, write to the Free Software           |
23// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
24// | USA.                                                                  |
25// +-----------------------------------------------------------------------+
26
27
28/**
29 * Tags available. Each return tag is represented as an array with its id,
30 * its name, its weight (count), its url name. Tags are not sorted.
31 *
32 * The returned list can be a subset of all existing tags due to
33 * permissions, only if a list of forbidden categories is provided
34 *
35 * @param array forbidden categories
36 * @return array
37 */
38function get_available_tags()
39{
40  // we can find top fatter tags among reachable images
41  $query = '
42SELECT tag_id, COUNT(DISTINCT(it.image_id)) counter
43  FROM '.IMAGE_CATEGORY_TABLE.' ic
44    INNER JOIN '.IMAGE_TAG_TABLE.' it ON ic.image_id=it.image_id'.get_sql_condition_FandF
45    (
46      array
47        (
48          'forbidden_categories' => 'category_id',
49          'visible_categories' => 'category_id',
50          'visible_images' => 'ic.image_id'
51        ),
52      '
53  WHERE'
54    ).'
55  GROUP BY tag_id';
56  $tag_counters = simple_hash_from_query($query, 'tag_id', 'counter');
57
58  if ( empty($tag_counters) )
59  {
60    return array();
61  }
62
63  $query = '
64SELECT id, name, url_name
65  FROM '.TAGS_TABLE;
66  $result = pwg_query($query);
67  $tags = array();
68  while ($row = mysql_fetch_assoc($result))
69  {
70    $counter = @$tag_counters[ $row['id'] ];
71    if ( $counter )
72    {
73      $row['counter'] = $counter;
74      array_push($tags, $row);
75    }
76  }
77  return $tags;
78}
79
80/**
81 * All tags, even tags associated to no image.
82 *
83 * @return array
84 */
85function get_all_tags()
86{
87  $query = '
88SELECT id,
89       name,
90       url_name
91  FROM '.TAGS_TABLE.'
92;';
93  $result = pwg_query($query);
94  $tags = array();
95  while ($row = mysql_fetch_assoc($result))
96  {
97    array_push($tags, $row);
98  }
99
100  usort($tags, 'name_compare');
101
102  return $tags;
103}
104
105/**
106 * Giving a set of tags with a counter for each one, calculate the display
107 * level of each tag.
108 *
109 * The level of each tag depends on the average count of tags. This
110 * calcylation method avoid having very different levels for tags having
111 * nearly the same count when set are small.
112 *
113 * @param array tags
114 * @return array
115 */
116function add_level_to_tags($tags)
117{
118  global $conf;
119
120  if (count($tags) == 0)
121  {
122    return $tags;
123  }
124
125  $total_count = 0;
126
127  foreach ($tags as $tag)
128  {
129    $total_count+= $tag['counter'];
130  }
131
132  // average count of available tags will determine the level of each tag
133  $tag_average_count = $total_count / count($tags);
134
135  // tag levels threshold calculation: a tag with an average rate must have
136  // the middle level.
137  for ($i = 1; $i < $conf['tags_levels']; $i++)
138  {
139    $threshold_of_level[$i] =
140      2 * $i * $tag_average_count / $conf['tags_levels'];
141  }
142
143  // display sorted tags
144  foreach (array_keys($tags) as $k)
145  {
146    $tags[$k]['level'] = 1;
147
148    // based on threshold, determine current tag level
149    for ($i = $conf['tags_levels'] - 1; $i >= 1; $i--)
150    {
151      if ($tags[$k]['counter'] > $threshold_of_level[$i])
152      {
153        $tags[$k]['level'] = $i + 1;
154        break;
155      }
156    }
157  }
158
159  return $tags;
160}
161
162/**
163 * return the list of image ids corresponding to given tags. AND & OR mode
164 * supported.
165 *
166 * @param array tag ids
167 * @param string mode
168 * @return array
169 */
170function get_image_ids_for_tags($tag_ids, $mode = 'AND')
171{
172  switch ($mode)
173  {
174    case 'AND':
175    {
176      // strategy is to list images associated to each tag
177      $tag_images = array();
178
179      foreach ($tag_ids as $tag_id)
180      {
181        $query = '
182SELECT image_id
183  FROM '.IMAGE_TAG_TABLE.'
184  WHERE tag_id = '.$tag_id.'
185;';
186        $tag_images[$tag_id] = array_from_query($query, 'image_id');
187      }
188
189      // then we calculate the intersection, the images that are associated to
190      // every tags
191      $items = array_shift($tag_images);
192      foreach ($tag_images as $images)
193      {
194        $items = array_intersect($items, $images);
195      }
196
197      return array_unique($items);
198      break;
199    }
200    case 'OR':
201    {
202      $query = '
203SELECT DISTINCT image_id
204  FROM '.IMAGE_TAG_TABLE.'
205  WHERE tag_id IN ('.implode(',', $tag_ids).')
206;';
207      return array_from_query($query, 'image_id');
208      break;
209    }
210    default:
211    {
212      die('get_image_ids_for_tags: unknown mode, only AND & OR are supported');
213    }
214  }
215}
216
217/**
218 * return a list of tags corresponding to given items.
219 *
220 * @param array items
221 * @param array max_tags
222 * @param array excluded_tag_ids
223 * @return array
224 */
225function get_common_tags($items, $max_tags, $excluded_tag_ids=null)
226{
227  if (empty($items))
228  {
229    return array();
230  }
231  $query = '
232SELECT id, name, url_name, count(*) counter
233  FROM '.IMAGE_TAG_TABLE.'
234    INNER JOIN '.TAGS_TABLE.' ON tag_id = id
235  WHERE image_id IN ('.implode(',', $items).')';
236  if (!empty($excluded_tag_ids))
237  {
238    $query.='
239    AND tag_id NOT IN ('.implode(',', $excluded_tag_ids).')';
240  }
241  $query .='
242  GROUP BY tag_id';
243  if ($max_tags>0)
244  {
245    $query .= '
246  ORDER BY counter DESC
247  LIMIT 0,'.$max_tags;
248  }
249
250  $result = pwg_query($query);
251  $tags = array();
252  while($row = mysql_fetch_assoc($result))
253  {
254    array_push($tags, $row);
255  }
256  usort($tags, 'name_compare');
257  return $tags;
258}
259
260/**
261 * return a list of tags corresponding to any of ids, url_names, names
262 *
263 * @param array ids
264 * @param array url_names
265 * @param array names
266 * @return array
267 */
268function find_tags($ids, $url_names=array(), $names=array() )
269{
270  $where_clauses = array();
271  if ( !empty($ids) )
272  {
273    $where_clauses[] = 'id IN ('.implode(',', $ids).')';
274  }
275  if ( !empty($url_names) )
276  {
277    $where_clauses[] =
278      'url_name IN ('.
279      implode(
280        ',',
281        array_map(
282          create_function('$s', 'return "\'".$s."\'";'),
283          $url_names
284          )
285        )
286      .')';
287  }
288  if ( !empty($names) )
289  {
290    $where_clauses[] =
291      'name IN ('.
292      implode(
293        ',',
294        array_map(
295          create_function('$s', 'return "\'".$s."\'";'),
296          $names
297          )
298        )
299      .')';
300  }
301  if (empty($where_clauses))
302  {
303    return array();
304  }
305
306  $query = '
307SELECT id, url_name, name
308  FROM '.TAGS_TABLE.'
309  WHERE '. implode( '
310    OR ', $where_clauses);
311
312  $result = pwg_query($query);
313  $tags = array();
314  while ($row = mysql_fetch_assoc($result))
315  {
316    array_push($tags, $row);
317  }
318  return $tags;
319}
320?>
Note: See TracBrowser for help on using the repository browser.