BMLT Root Server
common_search.inc.php
Go to the documentation of this file.
1 <?php
2 defined('BMLT_EXEC') or die('Cannot Execute Directly'); // Makes sure that this file is in the correct context.
3 
4 /***********************************************************************/
5 /** \file common_search.inc.php
6 
7  \brief This file contains a routine that allows a search to be
8  established with an existing c_comdef_search_manager object.
9 
10  This file is part of the Basic Meeting List Toolbox (BMLT).
11 
12  Find out more at: https://bmlt.app
13 
14  BMLT is free software: you can redistribute it and/or modify
15  it under the terms of the MIT License.
16 
17  BMLT is distributed in the hope that it will be useful,
18  but WITHOUT ANY WARRANTY; without even the implied warranty of
19  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  MIT License for more details.
21 
22  You should have received a copy of the MIT License along with this code.
23  If not, see <https://opensource.org/licenses/MIT>.
24 */
25 
26 /*******************************************************************/
27 /** \brief This function sets up the search manager to do the specified
28  search. It does not actually do the search.
29 */
30 function SetUpSearch(
31  &$in_search_manager, ///< A reference to an instance of c_comdef_search_manager. The search manager to set up.
32  &$in_http_vars
33  // The various HTTP GET and POST parameters.
34  // The values that are important to the search are:
35  // - 'services'
36  // This is an array of positive integers.
37  // This is interpreted as an array of integers. Each integer represents the ID of a Service Body.
38  // A positive integer means that the search will look specifically for meetings that contain that
39  // Service Body ID.
40  // If the integer is negative (preceded by a minus sign -), then the criteria will be to look
41  // for meetings that don't contain that ID.
42  // If no 'services' values are given, then the search will not use the Service Body field as a
43  // search criteria.
44  //
45  // - 'recursive'
46  // If this is set to '1', then the 'services' key will recursively follow Service bodies.
47  //
48  // - 'weekdays'
49  // This is an array of negative or positive nonzero integers (-7 - -1, 1 - 7).
50  // This is interpreted as an array of integers. Each integer represents a weekday (1 -> Sunday, 7 -> Saturday).
51  // A positive integer means that the search will look specifically for meetings that occur on that weekday.
52  // If the integer is negative (preceded by a minus sign -), then the criteria will be to look
53  // for meetings that don't occur on that weekday.
54  // If no 'weekdays' values are given, then the search will not use the weekday field as a
55  // search criteria.
56  //
57  // - 'bmlt_search_type'
58  // This is set to 'advanced' if the search is an advanced one (we need to take more criteria into consideration).
59  //
60  // - 'advanced_search_mode'
61  // This is set if the call was made from the advanced search page.
62  //
63  // - 'advanced_formats'
64  // This is the formats array, but is only counted if the bmlt_search_type is set to 'advanced'.
65  //
66  // - 'advanced_service_bodies'
67  // This is the same, but for Service Bodies.
68  //
69  // - 'advanced_weekdays'
70  // ...and weekdays.
71  //
72  // - 'advanced_radius'
73  // ...and radius (in degrees)
74  //
75  // - advanced_mapmode
76  // If this is true (1), then the Advanced form is using its map.
77  //
78  // - 'advanced_published'
79  // This is a switch to indicate whether or not to display published or unpublished meetings.
80  // It is only viable for logged-in users, and can have these values:
81  // - -1 Search for ONLY unpublished meetings
82  // - 0 Search for published and unpublished meetings.
83  // - 1 Search for ONLY published meetings.
84  //
85  // - 'formats'
86  // This is an array of positive integers.
87  // This is interpreted as an array of integers. Each integer represents a format shared ID.
88  // A format ID means that the search will look specifically for meetings that have that format.
89  // If the format is negative (preceded by a minus sign -), then the criteria will be to look
90  // for meetings that don't have that format.
91  // If no 'formats' values are given, then the search will not use the formats field as a
92  // search criteria.
93  //
94  // - 'formats_comparison_operator'
95  // This is a string used to set the operator used to compare included (positive integer) formats. Valid values
96  // and AND and OR.
97  //
98  // - 'langs'
99  // This is an array of 2-character strings.
100  // This is interpreted as an array of strings. Each string represents a language code, and is a 2-character string.
101  // A language string means that the search will look specifically for meetings that are in that language.
102  // If the language is preceded by a minus sign -, then the criteria will be to look
103  // for meetings that are not in that language.
104  // If no 'langs' values are given, then the search will not use the lang_enum field as a
105  // search criteria.
106  //
107  // The following values specify a start time "window." The meeting must start on, or after StartsAfterH/M, and
108  // can start no later than StartsBeforeH/M
109  //
110  // - 'StartsAfterH'
111  // A positive integer between 0 and 23. The hour of the minimal start time for meetings, in military time.
112  // - 'StartsAfterM'
113  // A positive integer between 0 and 59. The minute of the minimal start time for meetings, in military time.
114  // - 'StartsBeforeH'
115  // A positive integer between 0 and 23. The hour of the maximal start time for meetings, in military time.
116  // - 'StartsBeforeM'
117  // A positive integer between 0 and 59. The minute of the maximal start time for meetings, in military time.
118  //
119  // The following values specify a time duration "window." The meeting can last no longer than MaxDurationH/M,
120  // and no less than MinDurationH/M.
121  //
122  // - 'MinDurationH'
123  // A positive integer. This is the number of hours in the minimal duration.
124  // - 'MinDurationM'
125  // A positive integer. This is the number of minutes in the minimal duration.
126  // - 'MaxDurationH'
127  // A positive integer. This is the number of hours in the maximal duration.
128  // - 'MaxDurationM'
129  // A positive integer. This is the number of minutes in the maximal duration.
130  //
131  // This is how meetings are located. We don't use address lookups. Instead, we geolocate the meetings via the
132  // longitude and latitude fields in each record. If you don't specify a geolocation, then the entire database
133  // is searched. If you do specify one, then only the portion within the radius is searched.
134  //
135  // - 'geo_width'
136  // A floating point number. This is the radius (not diameter) of the search, in MILES (not Kilometers).
137  // If this is negative, then it should be an integer, and that indicates an auto-radius is requested to
138  // find the number of meetings in the integer.
139  //
140  // - 'geo_width_km'
141  // A floating point number. This is the radius (not diameter) of the search, in KILOMETERS (not Miles).
142  // If this is negative, then it should be an integer, and that indicates an auto-radius is requested to
143  // find the number of meetings in the integer.
144  //
145  // - 'long_val'
146  // If one of the three radius specifiers is zero or undefined, this is ignored.
147  // This is a floating point number that specifies the longitude, in degrees, of the center of the search radius.
148  //
149  // - 'lat_val'
150  // If one of the three radius specifiers is zero or undefined, this is ignored.
151  // This is a floating point number that specifies the latitude, in degrees, of the center of the search radius.
152  //
153  // - 'SearchString'
154  // A string. If this is specified, then all the string fields of the meetings specified by the above criteria
155  // will be searched for the string. By default, if the language supports metaphone (sound like search), then
156  // that is used.
157  //
158  // - 'StringSearchIsAnAddress'
159  // A boolean. Nonzero means that the given string should not be checked against any of the fields in the meeting
160  // data. Instead, it is to be considered a submission to the Google Maps geocode, and will be used to determine
161  // a cernter point in a local search.
162  //
163  // - 'SearchStringAll'
164  // If nonzero, then all of the words in the search string will have to be matched for a meetings to qualify.
165  //
166  // - 'SearchStringExact'
167  // If nonzero, metaphone will not be used, and the spelling must be exact.
168  //
169  // - 'SearchStringRadius'
170  // If specified, the radius of the search around the address (ignored if StringSearchIsAnAddress is false).
171  // The units are in whatever the server units are for this language (can be miles or kilometers).
172  // Negative numbers must always be integers, and specify a rough target number of meetings for auto-radius.
173  //
174  // - 'meeting_ids'
175  // An array of positive integers. Each integer is an ID of an individual meeting. If this is set, all other
176  // search criteria are ignored.
177  //
178  // - 'meeting_key'
179  // A string. This is the exact name of the key to match. If this is null (Default), the following three are ignored.
180  // NOTE: As of 1.5, the behavior of this field has changed.
181  // If it is an array, then the string search is done via metaphone, unless meeting_key_match_case is true.
182  // If it is an array, then the search is done on all the fields in the array, assuming they are all text.
183  // Non-string fields are ignored.
184  //
185  // - 'meeting_key_value'
186  // A string. The value to match.
187  // NOTE: As of Version 1.5, this is matched with a metaphone match, as well as the RegEx match.
188  //
189  // - 'meeting_key_match_case'
190  // If true, the case must match. Default is false.
191  // NOTE: As of Version 1.5, setting this to TRUE also stops the metaphone search.
192  //
193  // - 'meeting_key_contains'
194  // If this is true, then the string can have partial matches. Default is false (literal).
195  //
196  // - 'sort_results_by_distance'
197  // If this is true, then, if possible, the search results will be sorted by distance from the radius center.
198  // If this is set, then the 'sort_keys' parameter below will be ignored.
199  //
200  // - 'sort_keys'
201  // This is a comma-separated list of sort keys. The leftmost one will be the top priority, and the rightmost the lowest.
202  // The sort depth will be the number of keys.
203  // The direction will be assumed 'asc', unless 'desc' is one of the keys (it can be anywhere in the list).
204 ) {
205  $search_string = isset($in_http_vars['SearchString']) ? trim($in_http_vars['SearchString']) : '';
206 
207  if ($search_string && !(isset($in_http_vars['StringSearchIsAnAddress']) && $in_http_vars['StringSearchIsAnAddress']) && intval($search_string) && (preg_match('|\d+|', $search_string) || preg_match('(|\d+|,)+', $search_string))) {
208  $temp_ids = explode(',', $search_string);
209 
210  if (is_array($temp_ids) && count($temp_ids)) {
211  $first = true;
212 
213  foreach ($temp_ids as $id) {
214  $id = intval(trim($id));
215 
216  if ($id) {
217  if ($first) {
218  $in_http_vars['meeting_ids'] = null;
219  $first = false;
220  }
221 
222  $in_http_vars['meeting_ids'][] = $id;
223  }
224  }
225  } else {
226  $id = intval($search_string);
227 
228  if ($id) {
229  $in_http_vars['meeting_ids'] = array ( intval($id) );
230  }
231  }
232  }
233 
234  // If we have a meeting ID array, then that defines the entire search. We ignore everything else
235  if (isset($in_http_vars['meeting_ids']) && is_array($in_http_vars['meeting_ids']) && count($in_http_vars['meeting_ids'])) {
236  $in_search_manager->SetMeetingIDArray($in_http_vars['meeting_ids']);
237  } else {
238  if (isset($in_http_vars['sort_results_by_distance'])) {
239  $in_search_manager->SetSortByDistance($in_http_vars['sort_results_by_distance']);
240  } elseif (isset($in_http_vars['sort_keys']) && $in_http_vars['sort_keys']) {
241  $sort_fields = array();
242  $keys = explode(',', $in_http_vars['sort_keys']);
243  $dir = 'asc';
244  foreach ($keys as $key) {
245  if (strtolower(trim($key)) == 'desc') {
246  $dir = 'desc';
247  } else {
249  if ($templates && count($templates)) {
250  $additional = array ();
251 
252  foreach ($templates as $template) {
253  $value = $template['key'];
254  array_push($additional, $value);
255  }
256 
257  $standards = array ( 'weekday_tinyint', 'id_bigint', 'worldid_mixed', 'service_body_bigint', 'lang_enum', 'duration_time', 'start_time', 'longitude', 'latitude' );
258  $templates = array_merge($standards, $additional);
259 
260  if (in_array($key, $templates)) {
261  array_push($sort_fields, $key);
262  }
263  }
264  }
265  }
266 
267  $in_search_manager->SetSort($sort_fields, $dir == 'desc', count($sort_fields));
268  }
269 
270  // The first thing we do is try to resolve any address lookups.
271  if ($search_string && isset($in_http_vars['StringSearchIsAnAddress']) && $in_http_vars['StringSearchIsAnAddress']) {
272  $geo_search = (isset($in_http_vars['geo_width']) && $in_http_vars['geo_width']) ? true : ((isset($in_http_vars['geo_width_km']) && $in_http_vars['geo_width_km']) ? true : false);
273 
274  // We do a geocode to find out if this is an address.
275  if (!$geo_search) {
276  $search_string = preg_replace('|,(\s*?)|', ', ', $search_string); // This works around a bug caused by too-tight commas.
277  $geo = GetGeocodeFromString($search_string, $in_http_vars['advanced_weekdays']);
278  if (is_array($geo) && count($geo)) {
279  $localized_strings = c_comdef_server::GetLocalStrings();
280 
281  $in_http_vars['long_val'] = $geo['longitude'];
282  $in_http_vars['lat_val'] = $geo['latitude'];
283 
284  if (isset($in_http_vars['SearchStringRadius']) && floatval($in_http_vars['SearchStringRadius']) != 0.0) {
285  if (intval($in_http_vars['SearchStringRadius']) < 0) {
286  $geo['radius'] = intval($in_http_vars['SearchStringRadius']);
287  } else {
288  $geo['radius'] = floatval($in_http_vars['SearchStringRadius']);
289  }
290  }
291 
292  if ($localized_strings['dist_units'] == 'mi') {
293  if (isset($in_http_vars['geo_width_km'])) {
294  unset($in_http_vars['geo_width_km']);
295  }
296  $in_http_vars['geo_width'] = $geo['radius'];
297  } else {
298  unset($in_http_vars['geo_width']);
299  $in_http_vars['geo_width_km'] = $geo['radius'];
300  }
301 
302  /* We need to undef these, because they can step on the long/lat. */
303  unset($search_string);
304  unset($in_http_vars['StringSearchIsAnAddress']);
305  unset($in_http_vars['SearchStringRadius']);
306  }
307  }
308  }
309 
310  // First, set up the services.
311  if (isset($in_http_vars['bmlt_search_type']) && ($in_http_vars['bmlt_search_type'] == 'advanced') && isset($in_http_vars['advanced_service_bodies']) && is_array($in_http_vars['advanced_service_bodies']) && count($in_http_vars['advanced_service_bodies'])) {
312  $in_http_vars['services'] = $in_http_vars['advanced_service_bodies'];
313  }
314 
315  if (isset($in_http_vars['services']) && !is_array($in_http_vars['services'])) {
316  $in_http_vars['services'] = array ( $in_http_vars['services'] );
317  }
318 
319  // Look for Service bodies.
320  if (isset($in_http_vars['services']) && is_array($in_http_vars['services']) && count($in_http_vars['services'])) {
321  $services = array();
322 
323  if (isset($in_http_vars['recursive']) && $in_http_vars['recursive']) {
324  foreach ($in_http_vars['services'] as $service) {
325  $nested = GetAllContainedServiceBodyIDs(intval($service));
326 
327  if (isset($nested) && is_array($nested) && count($nested)) {
328  foreach ($nested as $sb_i) {
329  $sb_i = intval($sb_i);
330  $services[$sb_i] = $sb_i;
331  }
332  }
333  }
334  } else {
335  $services = $in_http_vars['services'];
336  }
337 
338  $sb =& $in_search_manager->GetServiceBodies();
339 
340  foreach ($services as $service) {
341  $sb[intval($service)] = 1;
342  }
343  } else {
344  unset($in_http_vars['services']);
345  }
346 
347 
348  if (!( isset($in_http_vars['geo_width_km']) && $in_http_vars['geo_width_km'] )
349  && !( isset($in_http_vars['geo_width']) && $in_http_vars['geo_width'] )
350  && isset($in_http_vars['bmlt_search_type'])
351  && ($in_http_vars['bmlt_search_type'] == 'advanced')
352  && isset($in_http_vars['advanced_radius'])
353  && isset($in_http_vars['advanced_mapmode'])
354  && $in_http_vars['advanced_mapmode']
355  && ( floatval($in_http_vars['advanced_radius'] != 0.0) )
356  && isset($in_http_vars['lat_val'])
357  && isset($in_http_vars['long_val'])
358  && ( (floatval($in_http_vars['lat_val']) != 0.0) || (floatval($in_http_vars['long_val']) != 0.0) )
359  ) {
360  if ($localized_strings['dist_units'] == 'mi') {
361  $in_http_vars['geo_width'] = $in_http_vars['advanced_radius'];
362  unset($in_http_vars['geo_width_km']);
363  } else {
364  $in_http_vars['geo_width_km'] = $in_http_vars['advanced_radius'];
365  unset($in_http_vars['geo_width']);
366  }
367  }
368 
369  // If we aren't doing any geographic searches, then we won't have a search center.
370  if (!( isset($in_http_vars['geo_width']) && $in_http_vars['geo_width'] ) && !( isset($in_http_vars['geo_width_km']) && $in_http_vars['geo_width_km'] )) {
371  unset($in_http_vars['lat_val']);
372  unset($in_http_vars['long_val']);
373  }
374 
375  // Next, set up the weekdays.
376  if (isset($in_http_vars['bmlt_search_type']) && ($in_http_vars['bmlt_search_type'] == 'advanced') && isset($in_http_vars['advanced_weekdays']) && ((is_array($in_http_vars['advanced_weekdays']) && count($in_http_vars['advanced_weekdays'])) || isset($in_http_vars['advanced_weekdays']))) {
377  $in_http_vars['weekdays'] = $in_http_vars['advanced_weekdays'];
378  }
379 
380  if (isset($in_http_vars['weekdays']) && !is_array($in_http_vars['weekdays']) && (intval(abs($in_http_vars['weekdays'])) > 0) && (intval(abs($in_http_vars['weekdays'])) < 8)) {
381  $in_http_vars['weekdays'] = array ( intval($in_http_vars['weekdays']) );
382  }
383 
384  if (isset($in_http_vars['weekdays']) && is_array($in_http_vars['weekdays']) && count($in_http_vars['weekdays'])) {
385  $wd =& $in_search_manager->GetWeekdays();
386  foreach ($in_http_vars['weekdays'] as $weekday) {
387  $wd[abs(intval($weekday))] = intval($weekday) > 0 ? 1 : -1;
388  }
389  } elseif (isset($in_http_vars['weekdays'])) {
390  $wd =& $in_search_manager->GetWeekdays();
391  $wd[abs(intval($in_http_vars['weekdays']))] = intval(intval($in_http_vars['weekdays'])) > 0 ? 1 : -1;
392  }
393 
394  // Next, set up the formats.
395 
396  if (isset($in_http_vars['bmlt_search_type']) && ($in_http_vars['bmlt_search_type'] == 'advanced') && isset($in_http_vars['advanced_formats']) && is_array($in_http_vars['advanced_formats']) && count($in_http_vars['advanced_formats'])) {
397  $in_http_vars['formats'] = $in_http_vars['advanced_formats'];
398  }
399 
400  if (isset($in_http_vars['formats'])) {
401  if (!is_array($in_http_vars['formats'])) {
402  $in_http_vars['formats'] = array ( intval($in_http_vars['formats']) );
403  }
404 
405  $fm =& $in_search_manager->GetFormats();
406  foreach ($in_http_vars['formats'] as $format) {
407  $key = abs(intval($format));
408  $fm[$key] = (intval($format) > 0) ? 1 : -1;
409  }
410  }
411 
412  if (isset($in_http_vars['formats_comparison_operator']) && $in_http_vars['formats_comparison_operator'] == "OR") {
413  $in_search_manager->SetFormatsComparisonOperator("OR");
414  }
415 
416  // Next, set up the languages.
417  if (isset($in_http_vars['langs']) && is_array($in_http_vars['langs']) && count($in_http_vars['langs'])) {
418  $lan =& $in_search_manager->GetLanguages();
419  foreach ($in_http_vars['langs'] as $lng) {
420  $lan[$lng] = 1;
421  }
422  }
423 
424  // Next, set up the advanced published option.
425  if (isset($in_http_vars['advanced_published'])) {
426  $in_search_manager->SetPublished(intval($in_http_vars['advanced_published']));
427  } else {
428  $in_search_manager->SetPublished(1);
429  }
430 
431  // Set the start window.
432  $start_time = null;
433  $end_time = null;
434 
435  // Next, the minimum start time..
436  if (isset($in_http_vars['StartsAfterH']) || isset($in_http_vars['StartsAfterM'])) {
437  $start_hour = min(23, max(0, intval($in_http_vars['StartsAfterH'])));
438  $start_minute = min(59, max(0, intval($in_http_vars['StartsAfterM'])));
439  $start_time = mktime($start_hour, $start_minute);
440  }
441 
442  // Next, the maximum start time..
443  if (isset($in_http_vars['StartsBeforeH']) || isset($in_http_vars['StartsBeforeM'])) {
444  $end_hour = min(23, max(0, intval($in_http_vars['StartsBeforeH'])));
445  $end_minute = min(59, max(0, intval($in_http_vars['StartsBeforeM'])));
446  $end_time = mktime($end_hour, $end_minute);
447  }
448 
449  $in_search_manager->SetStartTime($start_time, $end_time);
450 
451  $end_time = null;
452 
453  // Next, the maximum end time..
454  if (isset($in_http_vars['EndsBeforeH']) || isset($in_http_vars['EndsBeforeM'])) {
455  $end_hour = min(23, max(0, intval($in_http_vars['EndsBeforeH'])));
456  $end_minute = min(59, max(0, intval($in_http_vars['EndsBeforeM'])));
457  $end_time = ($end_hour * 3600) + ($end_minute * 60);
458  }
459 
460  $in_search_manager->SetEndTime($end_time);
461 
462  // Set the duration window.
463  $max_duration_time = null;
464  $min_duration_time = null;
465 
466  // Next, the minimum start time..
467  if (isset($in_http_vars['MaxDurationH']) || isset($in_http_vars['MaxDurationM'])) {
468  $max_duration_hour = min(23, max(0, intval($in_http_vars['MaxDurationH'])));
469  $max_duration_minute = min(59, max(0, intval($in_http_vars['MaxDurationM'])));
470  $max_duration_time = mktime($max_duration_hour, $max_duration_minute);
471  }
472 
473  // Next, the maximum start time..
474  if (isset($in_http_vars['MinDurationH']) || isset($in_http_vars['MinDurationM'])) {
475  $min_duration_hour = min(23, max(0, intval($in_http_vars['MinDurationH'])));
476  $min_duration_minute = min(59, max(0, intval($in_http_vars['MinDurationM'])));
477  $min_duration_time = mktime($min_duration_hour, $min_duration_minute);
478  }
479 
480  $in_search_manager->SetDuration($max_duration_time, $min_duration_time);
481 
482  // Next, we deal with a geolocated search radius.
483 
484  if ((isset($in_http_vars['geo_width']) && ($in_http_vars['geo_width'] != 0))
485  || (isset($in_http_vars['geo_width_km']) && ($in_http_vars['geo_width_km'] != 0) )) {
486  $long = isset($in_http_vars['long_val']) ? floatval($in_http_vars['long_val']) : 0;
487  $lat = isset($in_http_vars['lat_val']) ? floatval($in_http_vars['lat_val']) : 0;
488  $radius_in_miles = 0;
489  $radius_in_km = 0;
491  $radius_auto = $local_strings['number_of_meetings_for_auto'];
492 
493  if (isset($in_http_vars['geo_width']) && ( $in_http_vars['geo_width'] != 0 )) {
494  if ($in_http_vars['geo_width'] < 0) {
495  $radius_auto = 0 - intval($in_http_vars['geo_width']);
496  } else {
497  $radius_in_miles = floatval($in_http_vars['geo_width']);
498  }
499  } elseif (isset($in_http_vars['geo_width_km']) && ( $in_http_vars['geo_width_km'] != 0 )) {
500  if ($in_http_vars['geo_width_km'] < 0) {
501  $radius_auto = 0 - intval($in_http_vars['geo_width_km']);
502  } else {
503  $radius_in_km = floatval($in_http_vars['geo_width_km']);
504  }
505  }
506 
507  if ($radius_in_miles > 0) {
508  $in_search_manager->SetSearchRadiusAndCenterInMiles($radius_in_miles, $long, $lat);
509  } elseif ($radius_in_km > 0) {
510  $in_search_manager->SetSearchRadiusAndCenterInKm($radius_in_km, $long, $lat);
511  } elseif ($radius_auto > 0) {
512  $in_search_manager->SetSearchRadiusAndCenterAuto($radius_auto, $long, $lat);
513  }
514  }
515 
516  if ($search_string && (!isset($in_http_vars['meeting_key']) || !(is_array($in_http_vars['meeting_key']) && count($in_http_vars['meeting_key'])))) {
517  // And last, but not least, a string search:
518  $find_all = (isset($in_http_vars['SearchStringAll']) && $in_http_vars['SearchStringAll']) ? true :false;
519  $literal = (isset($in_http_vars['SearchStringExact']) && $in_http_vars['SearchStringExact']) ? true :false;
520  $in_search_manager->SetSearchString($search_string, $find_all, $literal);
521  }
522 
523  if (isset($in_http_vars['meeting_key']) && $in_http_vars['meeting_key']) {
524  // This is true by default.
525  if (!isset($in_http_vars['meeting_key_contains'])) {
526  $in_http_vars['meeting_key_contains'] = false;
527  }
528 
529  // This is false by default.
530  if (!isset($in_http_vars['meeting_key_match_case'])) {
531  $in_http_vars['meeting_key_match_case'] = false;
532  }
533  $in_search_manager->SetKeyValueSearch($in_http_vars['meeting_key'], $in_http_vars['meeting_key_value'], $in_http_vars['meeting_key_match_case'], $in_http_vars['meeting_key_contains']);
534  }
535  }
536 }
537 
538 /*******************************************************************/
539 /** \brief This gets all the Service bodies, and returns a one-dimensional
540  arry, containing its ID, and the IDs of all the Service bodies
541  that are contained in the array.
542 
543  \returns an array of integers.
544 */
545 function GetAllContainedServiceBodyIDs( $in_parent_id = 0 ///< This is the ID of the top Service body (will not be included in the reponse).
546  )
547 {
548  $in_parent_id = intval($in_parent_id);
549  $ret = array( $in_parent_id );
550 
551  $service_bodies = c_comdef_server::GetServer()->GetServiceBodyArray();
552 
553  foreach ($service_bodies as $service_body) {
554  $sb_id = intval($service_body->GetID());
555  $parent_id = intval($service_body->GetOwnerID());
556 
557  if ($in_parent_id == $parent_id) {
558  $ret2 = GetAllContainedServiceBodyIDs($sb_id);
559  $ret = array_merge($ret, $ret2);
560  }
561  }
562 
563  return $ret;
564 }
565 
566 /*******************************************************************/
567 /** \brief This displays the format keys, along with abbreviations to
568  display when the cursor is over them.
569 
570  \returns a string, containing the HTML rendered by the function, or,
571  if the $lite parameter is set to true, an associative, multidimensional
572  array, containing the information.
573 */
574 function BuildFormats(
575  $in_mtg_obj, ///< A reference to an instance of c_comdef_meeting.
576  $lite = false ///< If this is set to true, then the formats will be returned in an associative array, instead of as HTML. Default is false.
577 ) {
578  $formats = "";
579 
580  $formats_obj = $in_mtg_obj->GetMeetingDataValue('formats');
581 
582  if (is_array($formats_obj) && count($formats_obj)) {
583  foreach ($formats_obj as $format) {
584  if ($format instanceof c_comdef_format) {
585  $key = htmlspecialchars($format->GetKey());
586  $name = c_comdef_htmlspecialchars($format->GetLocalName());
587  $desc = c_comdef_htmlspecialchars($format->GetLocalDescription());
588  if ($lite) {
589  $formats[$key]['name'] = $name;
590  $formats[$key]['desc'] = $desc;
591  } else {
592  $formatspacer = '';
593  if ($formats) {
594  $formatspacer = ' ';
595  }
596 
597  $formats .= "<span class=\"c_comdef_search_results_single_format\"><abbr title=\"$desc\">$formatspacer$key</abbr></span>";
598  }
599  }
600  }
601  }
602 
603  return $formats;
604 }
605 
606 /*******************************************************************/
607 /** \brief Combines the town, borough and neighborhood into one string.
608 
609  \returns a string, containing the HTML rendered by the function.
610 */
611 function BuildTown( $in_mtg_obj ///< A reference to an instance of c_comdef_meeting.
612  )
613 {
614  $location_borough = c_comdef_htmlspecialchars(trim(stripslashes($in_mtg_obj->GetMeetingDataValue('location_city_subsection'))));
615  $location_town = c_comdef_htmlspecialchars(trim(stripslashes($in_mtg_obj->GetMeetingDataValue('location_municipality'))));
616  $location_neighborhood = c_comdef_htmlspecialchars(trim(stripslashes($in_mtg_obj->GetMeetingDataValue('location_neighborhood'))));
617  $location_province = c_comdef_htmlspecialchars(trim(stripslashes($in_mtg_obj->GetMeetingDataValue('location_province'))));
618 
619  if ($location_province) {
620  $location_town .= ', '.$location_province;
621  }
622 
623  if ($location_borough) {
624  $location_town = "<span class=\"c_comdef_search_results_town\">$location_borough</span>, <span class=\"c_comdef_search_results_town\">$location_town</span>";
625  }
626 
627  if ($location_neighborhood) {
628  $location_town = "$location_town <span class=\"c_comdef_search_results_neighborhood\">($location_neighborhood)</span>";
629  }
630 
631  return $location_town;
632 }
633 
634 /*******************************************************************/
635 /** \brief This creates a time string to be displayed for the meeting.
636  The display is done in non-military time, and "midnight" and
637  "noon" are substituted for 12:59:00, 00:00:00 and 12:00:00
638 
639  \returns a string, containing the HTML rendered by the function.
640 */
641 function BuildTime(
642  $in_time, ///< A string. The value of the time field.
643  $in_integer = false ///< If true, the time is returned as an integer (Military time).
644 ) {
645  $localized_strings = c_comdef_server::GetLocalStrings();
646 
647  $time = null;
648 
649  if ($in_integer) {
650  $time = intval(str_replace(':', '', $in_time)) / 100;
651  } else {
652  if (($in_time == "00:00:00") || ($in_time == "23:59:00")) {
653  $time = c_comdef_htmlspecialchars($localized_strings['comdef_server_admin_strings']['meeting_editor_screen_meeting_noon_label']);
654  } elseif ($in_time == "12:00:00") {
655  $time = c_comdef_htmlspecialchars($localized_strings['comdef_server_admin_strings']['meeting_editor_screen_meeting_midnight_label']);
656  } else {
657  $time = c_comdef_htmlspecialchars(date($localized_strings['time_format'], strtotime($in_time)));
658  }
659  }
660 
661  return $time;
662 }
663 
664 /*******************************************************************/
665 /** \brief This combines the location and street address fields.
666 
667  \returns a string, containing the HTML rendered by the function.
668 */
669 function BuildLocation( $in_mtg_obj ///< A reference to an instance of c_comdef_meeting.
670  )
671 {
672  $ret = "";
673 
674  if ($in_mtg_obj instanceof c_comdef_meeting) {
675  $location_text = c_comdef_htmlspecialchars(trim(stripslashes($in_mtg_obj->GetMeetingDataValue('location_text'))));
676  $street = c_comdef_htmlspecialchars(trim(stripslashes($in_mtg_obj->GetMeetingDataValue('location_street'))));
677  $info = c_comdef_htmlspecialchars(trim(stripslashes($in_mtg_obj->GetMeetingDataValue('location_info'))));
678 
679  if ($location_text) {
680  $ret .= $location_text;
681  }
682 
683  if ($street) {
684  if ($ret) {
685  $ret .= ", ";
686  }
687  $ret .= $street;
688  }
689 
690  if ($info) {
691  if ($ret) {
692  $ret .= " ";
693  }
694  $ret .= "($info)";
695  }
696  }
697 
698  return $ret;
699 }
700 
701 /*******************************************************************/
702 /** \brief This function uses the server-level Google Maps API to
703  try to geocode an address from the string passed in. A instance
704  of c_comdef_server needs to have been instantiated by the time
705  this is called.
706 
707  \returns an associative array of two floating-point numbers,
708  representing the longitude and latitude, in degrees, of any
709  geocoded result. Null, if no valid result was returned.
710 */
711 
713  $in_string, ///< The string to be checked.
714  $in_weekday_tinyint_array ///< An array of weekdays in which to filter for.
715 ) {
716  $ret = null;
717  $localized_strings = c_comdef_server::GetLocalStrings();
718 
719  $geo_uri = $localized_strings['comdef_server_admin_strings']['ServerMapsURL'];
720 
721  if ($localized_strings['region_bias']) {
722  $geo_uri .= '&region='.$localized_strings['region_bias'];
723  }
724 
725  if ($localized_strings['google_api_key']) {
726  $geo_uri .= '&key='.$localized_strings['google_api_key'];
727  }
728 
729  // Bit of a kludge. If the string is just a number (a postcode), then we add the region bias directly to it.
730  if (is_numeric($in_string) && $localized_strings['region_bias']) {
731  $in_string .= " ".$localized_strings['region_bias'];
732  }
733 
734  $geo_uri = str_replace('##SEARCH_STRING##', urlencode($in_string), $geo_uri);
735 
736  // We set up a 200-mile bounds, in order to encourage Google to look in the proper place.
737  $m_p_deg = 100 / (111.321 * cos(deg2rad($localized_strings['search_spec_map_center']['latitude'])) * 1.609344); // Degrees for 100 miles.
738  $bounds_ar = strval($localized_strings['search_spec_map_center']['latitude'] - $m_p_deg).",". strval($localized_strings['search_spec_map_center']['longitude'] - $m_p_deg); // Southwest corner
739  $bounds_ar .= "|";
740  $bounds_ar .= strval($localized_strings['search_spec_map_center']['latitude'] + $m_p_deg).",".strval($localized_strings['search_spec_map_center']['longitude'] + $m_p_deg); // Northeast corner
741 
742  $xml = simplexml_load_file($geo_uri);
743 
744  if ($xml->status == 'OK') {
745  $ret['longitude'] = floatval($xml->result->geometry->location->lng);
746  $ret['latitude'] = floatval($xml->result->geometry->location->lat);
747  $radius = c_comdef_server::HuntForRadius($localized_strings['number_of_meetings_for_auto'], $ret['longitude'], $ret['latitude'], $in_weekday_tinyint_array);
748  if ($radius) {
749  // The native units for the radius search is km. We need to convert to miles, if we are in miles.
750  if ($localized_strings['dist_units'] == 'mi') {
751  $radius /= 1.609344;
752  }
753 
754  $ret['radius'] = $radius;
755  } else {
756  $ret = null;
757  }
758  }
759 
760  return $ret;
761 }
static GetLocalStrings($in_lang_enum=null)
This gets the appropriate language files, and puts all the the strings into an associative array...
SetUpSearch(&$in_search_manager, &$in_http_vars)
This function sets up the search manager to do the specified search. It does not actually do the sear...
BuildFormats($in_mtg_obj, $lite=false)
This displays the format keys, along with abbreviations to display when the cursor is over them...
A class to hold a single meeting object.
$local_strings
Definition: index.php:6
$ret
Definition: contact.php:226
GetGeocodeFromString($in_string, $in_weekday_tinyint_array)
This function uses the server-level Google Maps API to try to geocode an address from the string pass...
BuildTown($in_mtg_obj)
Combines the town, borough and neighborhood into one string.
A Class for Format Codes.
BuildTime($in_time, $in_integer=false)
This creates a time string to be displayed for the meeting. The display is done in non-military time...
c_comdef_htmlspecialchars($in_string)
This function creates a displayable string.
BuildLocation($in_mtg_obj)
This combines the location and street address fields.
static HuntForRadius($in_search_result_count, $in_long_in_degrees, $in_lat_in_degrees, $in_weekday_tinyint_array, $in_service_bodies_array=null)
Find the smallest radius that contains at least the given number of meetings. The way this works is t...
static GetDataTableTemplate()
Returns an array that provides a template for the data table values (the optional/additional values)...
defined('BMLT_EXEC') or define('BMLT_EXEC'
Definition: index.php:3
GetAllContainedServiceBodyIDs($in_parent_id=0)
This gets all the Service bodies, and returns a one-dimensional arry, containing its ID...