BMLT Root Server
c_comdef_meetings.class.php
Go to the documentation of this file.
1 <?php
2 /***********************************************************************/
3 /** \file c_comdef_meetings.class.php
4  \brief The file for the c_comdef_meetings class.
5 
6  This file is part of the Basic Meeting List Toolbox (BMLT).
7 
8  Find out more at: https://bmlt.app
9 
10  BMLT is free software: you can redistribute it and/or modify
11  it under the terms of the MIT License.
12 
13  BMLT is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  MIT License for more details.
17 
18  You should have received a copy of the MIT License along with this code.
19  If not, see <https://opensource.org/licenses/MIT>.
20 */
21 defined('BMLT_EXEC') or die('Cannot Execute Directly'); // Makes sure that this file is in the correct context.
22 
23 require_once(dirname(__FILE__)."/c_comdef_meeting.class.php");
24 
25 /***********************************************************************/
26 /** \class c_comdef_meetings
27  \brief A class to hold a collection of c_comdef_meeting objects.
28 
29 ***********************************************************************/
30 // phpcs:disable PSR1.Classes.ClassDeclaration.MissingNamespace
31 // phpcs:disable Squiz.Classes.ValidClassName.NotCamelCaps
33 // phpcs:enable PSR1.Classes.ClassDeclaration.MissingNamespace
34 // phpcs:enable Squiz.Classes.ValidClassName.NotCamelCaps
35 {
36  /// A reference to the "parent" object for this instance.
37  private $_local_id_parent_obj = null;
38 
39  /// An array of new c_comdef_meeting objects that comprises the content.
40  private $_meetings_objects = null;
41 
42  /// An array of references to the c_comdef_format objects that are used in this dataset.
43  private $_formats_used = null;
44 
45  /// An array of references to the c_comdef_service_body objects that are used in this dataset.
46  private $_service_bodies_used = null;
47 
48  /// An array of string. This is used during sorting, to indicate which key is being sorted.
49  private $_sort_key = null;
50 
51  /** A string. This is used during sorting, to indicate which direction to take for the sort.
52  It is either:
53  - "asc" -Ascending
54  - "desc" -Descending
55  */
56  private $_sort_dir = null;
57 
58  /// This is true if the meetings have a distance by which they can be sorted, and the sort should be done with it.
59  private $_sort_search_by_distance = false;
60 
61  /*******************************************************************/
62  /** \brief Constructor
63 
64  */
65  public function __construct(
66  $in_parent_obj,
67  $in_meetings_data
68  ) {
69  $this->SetParentObj($in_parent_obj);
70  $this->CreateMeetingObjects($in_meetings_data);
71  }
72 
73  /*******************************************************************/
74  /** \brief Run through the list, and remove meetings that do not show up as "valid."
75 
76  If a user is logged in, they see dead meetings.
77  */
78  // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
79  public function RemoveInvalidMeetings()
80  {
81  // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
83 
84  // Logged-in user sees dead meetings.
85  if (!($cur_user instanceof c_comdef_user)) {
86  $cull_list = array();
87 
88  foreach ($this->_meetings_objects as &$one_meeting) {
89  if ($one_meeting instanceof c_comdef_meeting) {
90  if (!$one_meeting->IsValidMeeting()) {
91  array_push($cull_list, $one_meeting->GetID());
92  }
93  }
94  }
95 
96  foreach ($cull_list as $id) {
97  $this->_meetings_objects[$id] = null;
98  unset($this->_meetings_objects[$id]);
99  }
100  }
101  }
102 
103  /*******************************************************************/
104  /**
105  \brief Uses the Vincenty calculation to estimate a distance between
106  the two given lat/long pairs, then returns true or false as to whether
107  or not the distance between them falls within the given distance (in KM).
108 
109  \returns a Boolean. true, if the points are within the distance given.
110  */
111  // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
112  public static function IsInDistance(
113  $lat1, ///< These four parameters are the given two points long/lat, in degrees.
114  $lon1,
115  $lat2,
116  $lon2,
117  $in_distance_in_KM, ///< The distance they must be within to return true (in Kilometers).
118  &$out_dist_in_KM ///< This is an optional field that allows the calculated distance to be returned (in KM).
119  ) {
120  // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
121  $dist = self::GetDistance($lat1, $lon1, $lat2, $lon2);
122 
123  if (isset($out_dist_in_KM)) {
124  $out_dist_in_KM = $dist;
125  }
126 
127  return ( floatval($dist) <= floatval($in_distance_in_KM) );
128  }
129 
130  /*******************************************************************/
131  /**
132  \brief Uses the Vincenty calculation to estimate a distance between
133  the two given lat/long pairs, then returns true or false as to whether
134  or not the distance between them falls within the given distance (in KM).
135 
136  \returns a Float with the distance, in kilometers.
137  */
138  // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
139  public static function GetDistance(
140  $lat1, ///< These four parameters are the given two points long/lat, in degrees.
141  $lon1,
142  $lat2,
143  $lon2
144  ) {
145  // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
146  $a = 6378137;
147  $b = 6356752.3142;
148  $f = 1/298.257223563; // WGS-84 ellipsiod
149  $L = ($lon2-$lon1)/57.2957795131;
150  $U1 = atan((1.0-$f) * tan($lat1/57.2957795131));
151  $U2 = atan((1.0-$f) * tan($lat2/57.2957795131));
152  $sinU1 = sin($U1);
153  $cosU1 = cos($U1);
154  $sinU2 = sin($U2);
155  $cosU2 = cos($U2);
156 
157  $lambda = $L;
158  $lambdaP = $L;
159  $iterLimit = 100;
160 
161  do {
162  $sinLambda = sin($lambda);
163  $cosLambda = cos($lambda);
164  $sinSigma = sqrt(($cosU2*$sinLambda) * ($cosU2*$sinLambda) + ($cosU1*$sinU2-$sinU1*$cosU2*$cosLambda) * ($cosU1*$sinU2-$sinU1*$cosU2*$cosLambda));
165  if ($sinSigma==0) {
166  return true; // co-incident points
167  }
168  $cosSigma = $sinU1*$sinU2 + ($cosU1*$cosU2*$cosLambda);
169  $sigma = atan2($sinSigma, $cosSigma);
170  $sinAlpha = ($cosU1 * $cosU2 * $sinLambda) / $sinSigma;
171  $cosSqAlpha = 1.0 - $sinAlpha*$sinAlpha;
172  $cos2SigmaM = $cosSigma - 2.0*$sinU1*$sinU2/$cosSqAlpha;
173 // if (isNaN(cos2SigmaM))
174 // {
175 // cos2SigmaM = 0; // equatorial line: cosSqAlpha=0 (ยง6)
176 // }
177  $C = $f/(16.0*$cosSqAlpha*(4.0+$f*(4.0-3.0*$cosSqAlpha)));
178  $lambdaP = $lambda;
179  $lambda = $L + (1.0-$C) * $f * $sinAlpha * ($sigma + $C*$sinSigma*($cos2SigmaM+$C*$cosSigma*(-1.0+2.0*$cos2SigmaM*$cos2SigmaM)));
180  } while (abs($lambda-$lambdaP) > 1e-12 && --$iterLimit>0);
181 
182 // if ($iterLimit==0) return NaN // formula failed to converge
183 
184  $uSq = $cosSqAlpha * ($a*$a - $b*$b) / ($b*$b);
185  $A = 1.0 + $uSq/16384.0*(4096.0+$uSq*(-768.0+$uSq*(320.0-175.0*$uSq)));
186  $B = $uSq/1024.0 * (256.0+$uSq*(-128.0+$uSq*(74.0-47.0*$uSq)));
187  $deltaSigma = $B*$sinSigma*($cos2SigmaM+$B/4.0*($cosSigma*(-1.0+2.0*$cos2SigmaM*$cos2SigmaM)-$B/6.0*$cos2SigmaM*(-3.0+4.0*$sinSigma*$sinSigma)*(-3.0+4.0*$cos2SigmaM*$cos2SigmaM)));
188  $s = $b*$A*($sigma-$deltaSigma);
189 
190  return ( abs(round($s) / 1000.0) );
191  }
192 
193  /*******************************************************************/
194  /** \brief Set the parent object of this instance.
195  */
196  // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
197  public function SetParentObj(
198  $in_parent_obj ///< A reference to the parent object.
199  ) {
200  // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
201  $this->_local_id_parent_obj = null;
202  $this->_local_id_parent_obj = $in_parent_obj;
203  }
204 
205  /*******************************************************************/
206  /** \brief Return a reference to the parent object of this instance.
207 
208  \returns a reference to the parent instance of the object.
209  */
210  // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
211  public function GetParentObj()
212  {
213  // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
214  return $this->_local_id_parent_obj;
215  }
216 
217  /*******************************************************************/
218  /** \brief Create a bunch of meeting objects from the given data.
219  */
220  // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
221  private function CreateMeetingObjects(
222  $in_meetings_data ///< An array of data for one meeting.
223  ) {
224  // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
225  $this->_meetings_objects = null;
226  $this->_formats_used = null;
227  $this->_service_bodies_used = null;
228 
229  foreach ($in_meetings_data as $one_meeting) {
230  if ($one_meeting instanceof c_comdef_meeting) {
231  $id = $one_meeting->GetID();
232  $meeting = $one_meeting;
233  } else {
234  $id = $one_meeting['id_bigint'];
235  $formats = $one_meeting['formats'];
236  $lang = $one_meeting['lang_enum'];
237  // We make a list of references to the objects of the formats used, and index by the shared ID.
238  // This makes it convenient for the user.
239  foreach ($formats as $format_obj) {
240  if ($format_obj instanceof c_comdef_format) {
241  $format_id = $format_obj->GetSharedID();
242  $this->_formats_used[$format_id] = $format_obj;
243  }
244  }
245  $key = $one_meeting['service_body_bigint'];
246 
248 
249  if ($value instanceof c_comdef_service_body) {
250  $this->_service_bodies_used[$key] = $value;
251  }
252 
253  $meeting = new c_comdef_meeting($this, $one_meeting);
254  }
255  $this->_meetings_objects[$id] = $meeting;
256  }
257  }
258 
259  /*******************************************************************/
260  /** \brief Get the number of meetings.
261 
262  \returns an integer, containing the number of meeting objects in the internal meetings object array.
263  */
264  // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
265  public function GetNumMeetings()
266  {
267  // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
268  $ret = 0;
269 
270  if (isset($this->_meetings_objects) && is_array($this->_meetings_objects) && count($this->_meetings_objects)) {
271  $ret = count($this->_meetings_objects);
272  }
273 
274  return $ret;
275  }
276 
277  /*******************************************************************/
278  /** \brief Accessor -Get the meetings array.
279 
280  \returns a reference to the internal meetings object array.
281  */
282  // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
283  public function &GetMeetingObjects()
284  {
285  // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
286  if ($this->GetNumMeetings()) {
287  return $this->_meetings_objects;
288  }
289 
290  return null;
291  }
292 
293  /*******************************************************************/
294  /** \brief Accessor -Get the formats array.
295 
296  \returns a reference to the array that references the c_comdef_format objects used within this dataset.
297  */
298  // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
299  public function &GetFormatsUsed()
300  {
301  // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
302  return $this->_formats_used;
303  }
304 
305  /*******************************************************************/
306  /** \brief Accessor -Get the service bodies array.
307 
308  \returns a reference to the array that references the c_comdef_service_body objects used within this dataset.
309  */
310  // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
311  public function &GetServiceBodiesUsed()
312  {
313  // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
314  return $this->_service_bodies_used;
315  }
316 
317  /*******************************************************************/
318  /** Returns the name of the Meeting Table.
319 
320  \returns the name of the meetings table.
321  */
322  // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
323  public function GetMeetingTableName()
324  {
325  // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
326  $parent_obj = $this->GetParentObj();
327 
328  $name = $parent_obj->GetMeetingTableName();
329 
330  return $name;
331  }
332 
333  /*******************************************************************/
334  /** \brief Removes a meeting by a given ID from the set.
335  */
336  // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
337  public function RemoveMeeting(
338  $in_id ///< Integer: the id_bigint for the meeting to be removed.
339  ) {
340  // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
341  $this->_meetings_objects[$in_id] = null;
342  unset($this->_meetings_objects[$in_id]);
343  }
344 
345  /*******************************************************************/
346  /** \brief Return all the meetings that are within a certain radius of the given location.
347 
348  \returns a new c_comdef_meetings object, containing the subset of meetings
349  that are within the radius. Null if nothing found.
350  */
351  // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
352  public function GetMeetingsByDistance(
353  $in_longitude, ///< Floating-point. The longitude value of the center point.
354  $in_latitude, ///< Floating-point. The latitude value of the center point.
355  $in_radius, ///< Floating-point. The radius from the center
356  $in_radius_is_km = true, ///< Boolean. Set this to false if the radius is in miles (default is true).
357  $in_sort_by_distance = false ///< Boolean. Set this to true to sort the results by distance.
358  ) {
359  // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
360  $ret = null;
361 
362  if (!$in_radius_is_km) {
363  $in_radius *= 1.609344;
364  }
365 
366  $iterating_target = $this->GetMeetingObjects();
367  foreach ($iterating_target as &$meeting) {
368  if ($meeting instanceof c_comdef_meeting) {
369  // Get a reference to the meeting data.
370  $meeting_data = $meeting->GetMeetingData();
371  $lat = $meeting->GetMeetingDataValue('latitude');
372  $long = $meeting->GetMeetingDataValue('longitude');
373 
374  $dist = 0;
375 
376  if (self::IsInDistance($in_latitude, $in_longitude, $lat, $long, $in_radius, $dist)) {
377  $ret[$meeting->GetID()] = $meeting;
378  }
379  }
380  }
381 
382  if (is_array($ret) && count($ret)) {
383  $reto = new c_comdef_meetings($this->GetParentObj(), $ret);
384 
385  if ($reto instanceof c_comdef_meetings) {
386  $reto->SortMeetingObjects($this->_sort_key, $this->_sort_dir, $in_sort_by_distance);
387  }
388 
389  return $reto;
390  } else {
391  return null;
392  }
393  }
394 
395  /*******************************************************************/
396  /** \brief Return all the meetings that have a given key value
397 
398  Use this to filter for meetings within a single key/value.
399 
400  \returns a new c_comdef_meetings object, containing the subset of meetings
401  that contain the search query. Null if nothing found.
402  */
403  // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
404  public function GetMeetingsByKeyValue(
405  $in_key_string_array, ///< This is data item keys (an array of string). These must match exactly.
406  $in_value, ///< This is a string with a literal value to find.
407  $in_contains = false, ///< If this is false, then the entire value must match (Defalt is false).
408  $in_match_case = false
409  // If this is true, then the case must match (Default is false).
410  // NOTE: As of Version 1.5, the behavior has changed. This now refers to
411  // using metaphone or not. If it is true, the the string must match exactly,
412  // including case. However, if it is false, a case-insensitive metaphone search
413  // is done in the native server language.
414  ) {
415  // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
416  $ret = null;
417  $reto = array();
418 
419  if (is_array($in_key_string_array) && count($in_key_string_array)) {
420  if (!$in_match_case) {
421  $in_value = mb_strtolower($in_value, 'UTF-8');
422  }
423  $iterating_target = $this->GetMeetingObjects();
424 
425  foreach ($iterating_target as &$meeting) {
426  // Get a reference to the meeting data.
427  $meeting_data = $meeting->GetMeetingData();
428 
429  // We won't mess with data values that are objects or arrays.
430  if (is_array($meeting_data) && count($meeting_data)) {
431  reset($in_key_string_array);
432  foreach ($in_key_string_array as $key_string) {
433  if (isset($meeting_data[$key_string])) {
434  if (is_array($meeting_data[$key_string]) && isset($meeting_data[$key_string]['value'])) {
435  $value = strval($meeting_data[$key_string]['value']); // Make sure it's a string. We've had problems with non-string fields.
436  } else {
437  $value = strval($meeting_data[$key_string]); // Make sure it's a string. We've had problems with non-string fields.
438  }
439 
440  if (isset($value)) {
441  if (!$in_match_case) {
442  $value = mb_strtolower($value, 'UTF-8');
443  }
444 
445  if ($in_contains) {
446  $preg = preg_quote($in_value);
447  $preg = '|.*'.$preg.'.*|';
448  $match = (1 == preg_match($preg, $value));
449  } else {
450  $match = (0 == strcmp(trim($in_value), trim($value)));
451  }
452 
453  if ($match) {
454  $reto[] = $meeting;
455  } elseif (!$in_match_case) {
456  /*
457  This is all new, as of Version 1.5.
458  If the "match_case" parameter is off, then we do a metaphone search in the local language of the server.
459  */
460  $in_string_comp = SplitIntoMetaphone($in_value, c_comdef_server::GetServer()->GetLocalLang());
461  $comp = SplitIntoMetaphone($value, c_comdef_server::GetServer()->GetLocalLang());
462 
463  $found = false;
464 
465  foreach ($in_string_comp as $test) {
466  if (array_search($test, $comp)) {
467  $found = true;
468  if ($in_contains) {
469  break;
470  }
471  } else {
472  $found = false;
473  if (!$in_contains) {
474  break;
475  }
476  }
477  }
478 
479  if ($found === true) {
480  $reto[] = $meeting;
481  }
482  }
483  }
484  }
485  }
486  }
487  }
488  }
489 
490  if (is_array($reto) && count($reto)) {
491  $ret = new c_comdef_meetings($this->GetParentObj(), $reto);
492 
493  if ($ret instanceof c_comdef_meetings) {
494  $ret->SortMeetingObjects($this->_sort_key, $this->_sort_dir);
495  }
496  }
497 
498  return $ret;
499  }
500 
501  /*******************************************************************/
502  /** \brief Return all the meetings that contain the given string.
503 
504  If the language is English or Spanish, this does a metaphone search of all
505  all the strings in the "en" or "es" formats and weekdays. If it is any other
506  language, then a simple string search is performed.
507 
508  \returns a new c_comdef_meetings object, containing the subset of meetings
509  that contain the search query. Null if nothing found.
510  */
511  // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
512  public function GetMeetingsByString(
513  $in_string, ///< This is the string to search for.
514  $in_lang_enum = null, ///< This is the code for the desired language. If not given, the server localization will be used.
515  $in_all_words_bool = false, ///< If true, then all the words in the given search term need to be found (They could be distributed all around the various components of the meeting record).
516  $in_literal = false ///< If this is set to true, then metaphone-capable languages will not use metaphone, and will literally test the strings. Default is false.
517  ) {
518  // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
519  $ret = null;
520  /// If no language is given, we use the server's native language.
521  if (null == $in_lang_enum) {
522  $in_lang_enum = c_comdef_server::GetServer()->GetLocalLang();
523  }
524 
525  $in_all_words_bool = (isset($in_all_words_bool) && $in_all_words_bool) ? true : false; // Just make sure that there is a value in here.
526  $in_literal = (isset($in_literal) && $in_literal) ? true : false; // Just make sure that there is a value in here.
527 
528  $localized_strings = c_comdef_server::GetLocalStrings();
529 
530  $local_weekdays = $localized_strings['comdef_server_admin_strings']['user_editor_account_type_1'];
531 
532  /// We force the search to happen in lowercase. This is a very basic search.
533  $iterating_target = $this->GetMeetingObjects();
534 
535  if (is_array($iterating_target) && count($iterating_target)) {
536  $count = 0;
537  foreach ($iterating_target as &$meeting) {
538  $count++;
539  if ($meeting instanceof c_comdef_meeting) {
540  // Get a reference to the meeting data.
541  $meeting_data = $meeting->GetMeetingData();
542 
543  /*
544  What we do here, is build up a list of every text field in the meeting record.
545  We resolve the weekday into a localized name, and we grab the localized format
546  text as well.
547 
548  We will then search through all this text for our string[s].
549  */
550  $text_fields = array();
551  foreach ($meeting_data as $key => $value) {
552  // We ignore the values in the main table.
553  switch ($key) {
554  case 'id_bigint':
555  case 'worldid_mixed':
556  case 'start_time':
557  case 'duration_time':
558  case 'time_zone':
559  case 'longitude':
560  case 'latitude':
561  case 'published':
562  case 'email_contact':
563  break;
564 
565  case 'service_body_bigint':
566  $text_fields[$key] = $meeting->GetServiceBodyName();
567  break;
568 
569  case 'lang_enum':
570  $lang_path = dirname(__FILE__)."/../../local_server/server_admin/lang/".$meeting_data['lang_enum']."/name.txt";
571  if (file_exists($lang_path)) {
572  $text_fields[$key] = file_get_contents($lang_path);
573  }
574  break;
575 
576  case 'weekday_tinyint':
577  if (isset($meeting_data['weekday_tinyint'])) {
578  $text_fields[$key] = $local_weekdays[$meeting_data['weekday_tinyint']];
579  }
580  break;
581 
582  case 'formats':
583  $formats_list = c_comdef_server::GetServer()->GetFormatsObj();
584 
585  foreach ($meeting_data[$key] as $key2 => $value) {
586  $the_format_object = $formats_list->GetFormatBySharedIDCodeAndLanguage($key2, $in_lang_enum);
587 
588  if ($the_format_object) {
589  $text_fields["format_$key2"] = $the_format_object->GetLocalName()." ".$the_format_object->GetLocalDescription();
590  }
591  }
592  break;
593 
594  default:
595  if (isset($meeting_data[$key]['value']) && ( null != $meeting_data[$key]['value'] )) {
596  $val = null;
597  $val_key = null;
598  if (!is_float($meeting_data[$key]['value']) && !is_int($meeting_data[$key]['value'])) {
599  if (($meeting_data[$key]['visibility'] != _VISIBILITY_NONE_) || $meeting->UserCanObserve()) {
600  $text_fields[$key] = $meeting_data[$key]['value'];
601  }
602  }
603  }
604  break;
605  }
606  }
607 
608  $found_string = false;
609 
610  if (is_array($text_fields) && count($text_fields)) {
611  $in_string = mb_strtolower(trim($in_string), 'UTF-8');
612  $in_string = preg_replace('|\s+|', ' ', $in_string);
613 
614  if (!$in_literal) {
615  $string_metaphone = SplitIntoMetaphone($in_string, $in_lang_enum);
616  $string_metaphone = implode(' ', $string_metaphone);
617  }
618 
619  foreach ($text_fields as $test_text) {
620  // We will be checking the field text.
621  $test_text = mb_strtolower(trim($test_text), 'UTF-8');
622  $test_text = preg_replace('|\s+|', ' ', $test_text);
623 
624  if ($test_text) {
625  if (isset($string_metaphone)) {
626  $test_metaphone = SplitIntoMetaphone($test_text, $in_lang_enum);
627  $test_metaphone = implode(' ', $test_metaphone);
628  if (mb_strpos($test_metaphone, $string_metaphone, 0, 'UTF-8') !== false) {
629  if (!$ret) {
630  $ret = array ( $meeting );
631  } else {
632  $ret[] = $meeting;
633  }
634 
635  break;
636  }
637  } else {
638  $string_test = preg_split('|\s+|', $in_string);
639 
640  if ($in_all_words_bool) {
641  $test_string = mb_strtolower(trim($test_string), 'UTF-8');
642 
643  if (isset($string_test) && is_array($string_test) && count($string_test)) {
644  $found_string = true;
645 
646  foreach ($string_test as $str) {
647  $str = mb_strtolower(trim($str), 'UTF-8');
648  $found_string = preg_match('|'.preg_quote($str).'|', $test_text);
649 
650  if ($found_string != $in_all_words_bool) {
651  break;
652  }
653  }
654  } else {
655  $test_string = preg_replace('|^[\'\"]*?(.*?)[\'\"]*?$|', '', $in_string);
656  $found_string = preg_match('|'.preg_quote($test_string).'|', $test_text);
657  }
658  }
659 
660  if ($found_string) {
661  if (!$ret) {
662  $ret = array ( $meeting );
663  } else {
664  $ret[] = $meeting;
665  }
666 
667  break;
668  }
669  }
670  }
671  }
672  }
673  }
674  }
675  }
676 
677  $reto = null;
678 
679  if (is_array($ret) && count($ret)) {
680  $reto = new c_comdef_meetings($this->GetParentObj(), $ret);
681 
682  if ($reto instanceof c_comdef_meetings) {
683  $reto->SortMeetingObjects($this->_sort_key, $this->_sort_dir);
684  }
685  }
686 
687  return $reto;
688  }
689 
690  /*******************************************************************/
691  /** \brief Returns an array of all the field keys used by the meetings
692  in this search set.
693 
694  \returns an array of strings, with the key being the same as the value.
695  This reflects
696  */
697  // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
698  public function GetMeetingKeys()
699  {
700  // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
701  $ret = null;
702 
703  $iterating_target = $this->GetMeetingObjects();
704  foreach ($iterating_target as &$meeting) {
705  // Get a reference to the meeting data.
706  $meeting_data = $meeting->GetMeetingData();
707 
708  foreach ($meeting_data as $key => $value) {
709  $ret[$key] = $key;
710  }
711  }
712 
713  return $ret;
714  }
715 
716  /*******************************************************************/
717  /** \brief Sorts the meetings.
718  This will apply a sort, dependent upon the given fields.
719  The given array contains the field names (SQL columns and keys)
720  for the data to be sorted.
721  */
722  // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
723  public function SortMeetingObjects(
724  $in_sort_fields_array,
725  // An array of strings. The array will deliniate the sort order, by field name.
726  // Array element [0] will be the highest priority, and it will descend from there.
727  $in_desc = false, ///< If this is set to true, the sort will be highest to lowest. Default is false.
728  $in_by_distance = false ///< If true, then, after the regular sort, we sort by distance (May be ignored if the meetings don't have a
729  ) {
730  // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
731  $this->_sort_key = null;
732  $my_meeting_data =& $this->GetMeetingObjects();
733 
734  if (is_array($my_meeting_data) && count($my_meeting_data) && is_array($in_sort_fields_array) && count($in_sort_fields_array)) {
735  $this->_sort_key = $in_sort_fields_array;
736  $this->_sort_dir = $in_desc ? "desc" : "asc";
737  usort($my_meeting_data, array ( 'c_comdef_meetings', 'SortKernel' ));
738  }
739 
740  if ($this->_sort_search_by_distance || $in_by_distance) {
741  $this->_sort_search_by_distance = true;
742  usort($my_meeting_data, array ( 'c_comdef_meetings', 'SortDistanceKernel' ));
743  }
744  }
745 
746  /*******************************************************************?
747  /** \brief Accessor -get the sort key.
748 
749  \returns an array of strings. The current sort key.
750  */
751  // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
752  public function GetSortKey()
753  {
754  // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
755  return $this->_sort_key;
756  }
757 
758  /*******************************************************************?
759  /** \brief Accessor -get the sort direction.
760 
761  \returns a string. The current sort direction.
762  It is either:
763  - "asc" -Ascending
764  - "desc" -Descending
765  */
766  // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
767  public function GetSortDir()
768  {
769  // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
770  return $this->_sort_dir;
771  }
772 
773  /*******************************************************************/
774  /** \brief This is the standard PHP sort callback used in the sort
775  loops for distance. This will not be effective if the meetings
776  don't both have _distance_in_km fields.
777  */
778  // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
779  public static function SortDistanceKernel($object_a, $object_b)
780  {
781  // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
782  $ret = 0;
783 
784  if (($object_a instanceof c_comdef_meeting) && ($object_b instanceof c_comdef_meeting) && isset($object_a->_distance_in_km) && isset($object_b->_distance_in_km)) {
785  $ret = ($object_a->_distance_in_km < $object_b->_distance_in_km) ? -1 : 1;
786 
787  if (0 == $ret) {
788  $ret = $this::SortKernel($object_a, $object_b);
789  }
790  }
791 
792  return $ret;
793  }
794 
795  /*******************************************************************/
796  /** \brief This is the standard PHP sort callback used in the sort
797  loops.
798  */
799  // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
800  public static function SortKernel($object_a, $object_b)
801  {
802  // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
803  $ret = 0;
804 
805  if (($object_a instanceof c_comdef_meeting) && ($object_b instanceof c_comdef_meeting)) {
806  $parent = $object_a->GetParentObj(); // This is how we get the sort key.
807  if ($parent instanceof c_comdef_meetings) {
808  $sort_key = $parent->GetSortKey();
809  $sort_dir = $parent->GetSortDir();
810 
811  if (is_array($sort_key) && count($sort_key)) {
812  $meeting_data_a = $object_a->GetMeetingData();
813  $meeting_data_b = $object_b->GetMeetingData();
814 
815  if (is_array($meeting_data_a) && count($meeting_data_a) && is_array($meeting_data_b) && count($meeting_data_b)) {
816  foreach ($sort_key as $s_key) {
817  if ($s_key == 'start_time') {
818  $value_a_arr = explode(":", $meeting_data_a[$s_key]);
819  $value_b_arr = explode(":", $meeting_data_b[$s_key]);
820 
821  $value_a = (intval($value_a_arr[0]) * 100) + intval($value_a_arr[1]);
822  $value_b = (intval($value_b_arr[0]) * 100) + intval($value_b_arr[1]);
823 
824  // Kludge to make midnight higher.
825  if ($value_a == 0) {
826  $value_a = 10000;
827  }
828 
829  if ($value_b == 0) {
830  $value_b = 10000;
831  }
832 
833  if ($value_a == $value_b) {
834  $ret = 0;
835  } elseif ($value_a < $value_b) {
836  $ret = -1;
837  } elseif ($value_a > $value_b) {
838  $ret = 1;
839  }
840  } elseif ($s_key == 'weekday_tinyint') {
841  $local_strings = c_comdef_server::GetLocalStrings();
842 
843  $value_a = intval($meeting_data_a[$s_key]) - ($local_strings['week_starts_on'] - 1);
844  $value_b = intval($meeting_data_b[$s_key]) - ($local_strings['week_starts_on'] - 1);
845 
846  if (1 > $value_a) {
847  $value_a += 7;
848  }
849 
850  if (1 > $value_b) {
851  $value_b += 7;
852  }
853 
854  if ($value_a == $value_b) {
855  $ret = 0;
856  } elseif ($value_a < $value_b) {
857  $ret = -1;
858  } elseif ($value_a > $value_b) {
859  $ret = 1;
860  }
861  } elseif ((($s_key == 'location_municipality') || ($s_key == 'location_city_subsection')) && in_array('location_municipality', $sort_key) && in_array('location_city_subsection', $sort_key)) {
862  if (isset($meeting_data_a['location_city_subsection']) && !isset($meeting_data_b['location_city_subsection'])) {
863  if (isset($meeting_data_b['location_municipality'])) {
864  $value_a = $meeting_data_a['location_city_subsection']['value'];
865  $value_b = $meeting_data_b['location_municipality']['value'];
866  $cmp = strcmp($value_a, $value_b);
867  if (0 > $cmp) {
868  $ret = -1;
869  } elseif (0 < $cmp) {
870  $ret = 1;
871  }
872  } else {
873  $ret = -1;
874  }
875  } elseif (isset($meeting_data_b['location_city_subsection']) && !isset($meeting_data_a['location_city_subsection'])) {
876  if (isset($meeting_data_a['location_municipality'])) {
877  $value_a = $meeting_data_b['location_city_subsection']['value'];
878  $value_b = $meeting_data_a['location_municipality']['value'];
879  $cmp = strcmp($value_a, $value_b);
880  if (0 > $cmp) {
881  $ret = 1;
882  } elseif (0 < $cmp) {
883  $ret = -1;
884  }
885  } else {
886  $ret = 1;
887  }
888  } elseif (isset($meeting_data_a[$s_key]) && is_array($meeting_data_a[$s_key]) && isset($meeting_data_a[$s_key]['value']) && isset($meeting_data_b[$s_key]) && is_array($meeting_data_b[$s_key]) && isset($meeting_data_b[$s_key]['value'])) {
889  $value_a = $meeting_data_a[$s_key]['value'];
890  $value_b = $meeting_data_b[$s_key]['value'];
891  $cmp = strcmp($value_a, $value_b);
892  if (0 > $cmp) {
893  $ret = -1;
894  } elseif (0 < $cmp) {
895  $ret = 1;
896  }
897  } else {
898  $ret = ( isset($meeting_data_a[$s_key]) && !isset($meeting_data_b[$s_key]) ) ? -1 : (( !isset($meeting_data_a[$s_key]) && isset($meeting_data_b[$s_key]) ) ? 1 : 0);
899  }
900  } elseif (isset($meeting_data_a[$s_key]) && isset($meeting_data_b[$s_key])) {
901  // This is if we have an optional field, with a "value" sub array element.
902  if (is_array($meeting_data_a[$s_key]) && isset($meeting_data_a[$s_key]['value'])) {
903  $value_a = $meeting_data_a[$s_key]['value'];
904  } else // If not, we use the actual value of the parameter itself.
905  {
906  $value_a = $meeting_data_a[$s_key];
907  }
908 
909  // We do the same for the next element.
910  if (is_array($meeting_data_b[$s_key]) && isset($meeting_data_b[$s_key]['value'])) {
911  $value_b = $meeting_data_b[$s_key]['value'];
912  } else {
913  $value_b = $meeting_data_b[$s_key];
914  }
915 
916  // If they are strings, we do a binary-safe comparison.
917  if (is_string($value_a)) {
918  if (($value_a && !$value_b) || (isset($value_a) && !isset($value_b))) {
919  $ret = 1;
920  } elseif (($value_b && !$value_a) || (isset($value_b) && !isset($value_a))) {
921  $ret = -1;
922  } else {
923  $cmp = strcmp($value_a, $value_b);
924  if (0 > $cmp) {
925  $ret = -1;
926  } elseif (0 < $cmp) {
927  $ret = 1;
928  }
929  }
930  } else // Otherwise, we do a simple comparison.
931  {
932  if ($value_a < $value_b) {
933  $ret = -1;
934  } elseif ($value_a > $value_b) {
935  $ret = 1;
936  }
937  }
938  } else {
939  $ret = ( isset($meeting_data_a[$s_key]) && !isset($meeting_data_b[$s_key]) ) ? -1 : (( !isset($meeting_data_a[$s_key]) && isset($meeting_data_b[$s_key]) ) ? 1 : 0);
940  }
941 
942  if ($ret != 0) {
943  if ($sort_dir == "desc") {
944  $ret = -$ret;
945  }
946  break;
947  }
948  }
949  }
950  }
951  }
952  }
953 
954  return $ret;
955  }
956 }
static GetLocalStrings($in_lang_enum=null)
This gets the appropriate language files, and puts all the the strings into an associative array...
SortMeetingObjects($in_sort_fields_array, $in_desc=false, $in_by_distance=false)
Sorts the meetings. This will apply a sort, dependent upon the given fields. The given array contains...
A Class for Service Body Objects.
static GetDistance($lat1, $lon1, $lat2, $lon2)
Uses the Vincenty calculation to estimate a distance between the two given lat/long pairs...
A class to hold a single meeting object.
& GetMeetingObjects()
Accessor -Get the meetings array.
& GetServiceBodiesUsed()
Accessor -Get the service bodies array.
This class handles BMLT users. One instance is created for each user on the server.
$ret
Definition: contact.php:226
GetMeetingsByKeyValue($in_key_string_array, $in_value, $in_contains=false, $in_match_case=false)
Return all the meetings that have a given key value.
GetMeetingsByDistance($in_longitude, $in_latitude, $in_radius, $in_radius_is_km=true, $in_sort_by_distance=false)
Return all the meetings that are within a certain radius of the given location.
RemoveInvalidMeetings()
Run through the list, and remove meetings that do not show up as "valid.".
__construct($in_parent_obj, $in_meetings_data)
Constructor.
A Class for Format Codes.
static IsInDistance($lat1, $lon1, $lat2, $lon2, $in_distance_in_KM, &$out_dist_in_KM)
Uses the Vincenty calculation to estimate a distance between the two given lat/long pairs...
SplitIntoMetaphone($in_string, $in_lang_enum=null, $in_literal=false)
Converts a string into an array of metaphone entities.
Simply declares an interface for having a "container" object.
GetMeetingKeys()
Returns an array of all the field keys used by the meetings in this search set.
static GetServiceBodyByIDObj($in_service_body_id_bigint)
Get the object for a single service body, given an ID.
GetParentObj()
Return a reference to the parent object of this instance.
function e
GetNumMeetings()
Get the number of meetings.
const _VISIBILITY_NONE_
SetParentObj($in_parent_obj)
Set the parent object of this instance.
defined('BMLT_EXEC') or define('BMLT_EXEC'
Definition: index.php:3
A class to hold a collection of c_comdef_meeting objects.
static GetCurrentUserObj($in_is_ajax=false)
Get the current logged-in user, as a c_comdef_user instance.
& GetFormatsUsed()
Accessor -Get the formats array.
RemoveMeeting($in_id)
Removes a meeting by a given ID from the set.
CreateMeetingObjects($in_meetings_data)
Create a bunch of meeting objects from the given data.
GetMeetingsByString($in_string, $in_lang_enum=null, $in_all_words_bool=false, $in_literal=false)
Return all the meetings that contain the given string.