Allow reordering the delivery list.
[readifood.git] / lib / functions.php
1 <?php
2
3   function parse_parameters($parameters) {
4     $name = null;
5     $id = null;
6     $args = array();
7
8     if (count($parameters) > 0) {
9       $name = array_shift($parameters);
10
11       /* Recall that we shifted. */
12       if (count($parameters) > 0) {
13         if (is_numeric($parameters[0])) {
14           $id = array_shift($parameters);
15         }
16       }
17
18       $args = $parameters;
19     }
20
21     return array($name, $id, $args);
22   }
23
24   function get_city_by_name($name, $postcode_area = null, $verbose = true) {
25     $q = new CityQuery;
26
27     $m = $q->filterByName(urldecode($name));
28     if (isset($postcode_area)) {
29       $m->filterByPostcodeArea($postcode_area);
30     }
31     $cities = $m->find();
32
33     switch ($m->count()) {
34       case 0:
35         if ($verbose) echo "<p>No such city!</p>\n";
36         return null;
37
38       case 1:
39         return $cities[0];
40
41       default:
42         if ($verbose) echo "<p>Can't identify city uniquely.</p>!\n";
43         return null;
44     }
45   }
46
47   function get_city_by_id($id, $verbose = true) {
48     $q = new CityQuery;
49     $city = $q->findOneById($id);
50
51     if (! $q->count()) {
52       if ($verbose) echo "<p>No such city!</p>\n";
53       return null;
54     }
55
56     return $city;
57   }
58
59   function get_area_by_name($name, $verbose = true) {
60     $q = new AreaQuery;
61     $areas = $q->filterByName(urldecode($name))->find();
62
63     switch ($q->count()) {
64       case 0:
65         if ($verbose) echo "<p>No such area!</p>\n";
66         return null;
67
68       case 1:
69         return $areas[0];
70
71       default:
72         if ($verbose) echo "<p>Can't identify area uniquely.</p>!\n";
73         return null;
74     }
75   }
76
77   function get_area_by_id($id, $verbose = true) {
78     $q = new AreaQuery;
79     $area = $q->findOneById($id);
80
81     if (! $q->count()) {
82       if ($verbose) echo "<p>No such area!</p>\n";
83       return null;
84     }
85
86     return $area;
87   }
88
89   function get_area_city($area) {
90     $q = new CityQuery;
91     return $q->findOneById($area->getCityId());
92   }
93
94   function get_contact_by_name($name, $verbose = true) {
95     $q = new ContactQuery;
96     $contact = $q->filterByDisplayname(urldecode($name))->find();
97
98     switch ($q->count()) {
99       case 0:
100         if ($verbose) echo "<p>No such contact!</p>\n";
101         return null;
102
103       case 1:
104         return $contacts[0];
105
106       default:
107         if ($verbose) echo "<p>Can't identify contact uniquely.</p>!\n";
108         return null;
109     }
110   }
111
112   function get_contact_by_id($id, $verbose = true) {
113     $q = new ContactQuery;
114     $contact = $q->findOneById($id);
115
116     if (! $q->count()) {
117       if ($verbose) echo "<p>No such contact!</p>\n";
118       return null;
119     }
120
121     return $contact;
122   }
123
124   function get_hub_by_name($name, $verbose = true) {
125     $q = new HubQuery;
126     $hubs = $q->filterByDisplayname(urldecode($name))->find();
127
128     switch ($q->count()) {
129       case 0:
130         if ($verbose) echo "<p>No such hub!</p>\n";
131         return null;
132
133       case 1:
134         return $hubs[0];
135
136       default:
137         if ($verbose) echo "<p>Can't identify hub uniquely.</p>!\n";
138         return null;
139     }
140   }
141
142   function get_hub_by_id($id, $verbose = true) {
143     $q = new HubQuery;
144     $hub = $q->findOneById($id);
145
146     if (! $q->count()) {
147       if ($verbose) echo "<p>No such hub!</p>\n";
148       return null;
149     }
150
151     return $hub;
152   }
153
154   function get_donation_by_id($id, $verbose = true) {
155     $q = new DonationQuery;
156     $donation = $q->findOneById($id);
157
158     if (! $q->count()) {
159       if ($verbose) echo "<p>No such donation!</p>\n";
160       return null;
161     }
162
163     return $donation;
164   }
165
166   function get_order_by_id($id, $verbose = true) {
167     $q = new OrderQuery;
168     $order = $q->findOneById($id);
169
170     if (! $q->count()) {
171       if ($verbose) echo "<p>No such order!</p>\n";
172       return null;
173     }
174
175     return $order;
176   }
177
178   function get_order_ids_by_state($state_mask) {
179     $order_ids = array();
180     $dbh = Propel::getConnection();
181     $sth = $dbh->prepare("select * from OrderState o where updated=(select max(updated) from OrderState where order_id=o.order_id) and state & $state_mask");
182     $sth->execute();
183     $order_states = OrderStatePeer::populateObjects($sth);
184     foreach ($order_states as $order_state) $order_ids[] = $order_state->getOrderId();
185     return $order_ids;
186   }
187
188   function get_beneficiary_orders($contact, $state_mask = null) {
189     $q = new OrderQuery;
190     $q->filterByBeneficiaryId($contact->getId());
191     if ($state_mask) $q->filterById(get_order_ids_by_state($state_mask));
192     return $q->orderByDate()->find();
193   }
194
195   function get_requester_orders($contact, $state_mask = null) {
196     $q = new OrderQuery;
197     $q->filterByRequesterId($contact->getId());
198     if ($state_mask) $q->filterById(get_order_ids_by_state($state_mask));
199     return $q->orderByDate()->find();
200   }
201
202   function get_contact_orders($contact, $state_mask = null) {
203     $q = new OrderQuery;
204     $q->filterByBeneficiaryId($contact->getId())->_or()->filterByRequesterId($contact->getId());
205     if ($state_mask) $q->filterById(get_order_ids_by_state($state_mask));
206     return $q->orderByDate()->find();
207   }
208
209   function get_user_by_contact_id($id, $verbose = true) {
210     $q = new UserQuery;
211     $user = $q->findOneByContactId($id);
212
213     if (! $q->count()) {
214       if ($verbose) echo "<p>No such user!</p>\n";
215       return null;
216     }
217
218     return $user;
219   }
220
221   function get_city_displayname($city) {
222     return $city->getName() . ", " . $city->getPostcodeArea();
223   }
224
225   function get_area_displayname($area) {
226     return $area->getName() . " in " . get_city_displayname(CityQuery::create()->findOneById($area->getCityId()));
227   }
228
229   function get_donation_displayname($donation) {
230     return sprintf("%0.2fkg on %s", $donation->getQuantity() / 1000, $donation->getDate());
231   }
232
233   function get_order_parcel_string($order) {
234     global $parcel_sizes, $parcel_contents;
235
236     $parcel_size = null;
237     for ($i = 0 ; $i < count($parcel_sizes); $i++) {
238       if ($order->getParcel() & (1 << $i)) {
239         $parcel_size = $parcel_sizes[$i];
240         break;
241       }
242     }
243
244     $selected = array();
245     for ($i = count($parcel_sizes); $i < count($parcel_contents); $i++) {
246       if ($order->getParcel() & (1 << $i)) $selected[] = $parcel_contents[$i];
247     }
248
249     $ret = implode(": ", array($parcel_size, implode(", ", $selected)));
250     $ret = preg_replace('/^: /', '', $ret);
251     $ret = preg_replace('/: $/', '', $ret);
252
253     return $ret;
254   }
255
256   function get_order_displayname($order) {
257     return sprintf("<span class=\"small\">%s</span> on %s", get_order_parcel_string($order), $order->getDate());
258   }
259
260   function get_order_state_string($order_state = null) {
261     global $states;
262
263     if (is_null($order_state)) return null;
264
265     for ($i = 0; $i < count($states); $i++) {
266       if ($order_state->getState() & (1 << $i)) {
267         return $states[$i];
268       }
269     }
270
271     return "unknown";
272   }
273
274   function get_order_state($order) {
275     $q = new OrderStateQuery();
276     return $q->filterByOrderId($order->getId())->orderByUpdated('desc')->findOne();
277   }
278
279   function get_order_summary($order) {
280     $ret = "Order ";
281     $order_state = get_order_state($order);
282     if ($order_state) $ret = "<strong>" . ucfirst(get_order_state_string($order_state)) . "</strong> order ";
283     $ret .= $order->getStrongLink($order->getId()) . ": " . get_order_displayname($order);
284
285     if (check_admin(1)) $ret .= " " . $order->getDeleteLink();
286
287     /* XXX: Should pull from query. */
288     $q = new ContactQuery;
289     $contact = $q->findOneById($order->getRequesterId());
290     if ($contact) {
291       $ret .= " referred by " . $contact->getLink();
292       $area = get_contact_area($contact);
293       if ($area) $ret .= " in " . $area->getLink();
294     }
295
296     $q = new ContactQuery;
297     $contact = $q->findOneById($order->getBeneficiaryId());
298     if ($contact) {
299       $ret .= " for " . $contact->getLink();
300       $area = get_contact_area($contact);
301       if ($area) $ret .= " in " . $area->getLink();
302     }
303
304     if ($order->getHubId()) {
305       $q = new HubQuery;
306       $hub = $q->findOneById($order->getHubId());
307       if ($hub) $ret .= " to hub " . $hub->getLink();
308       $area = get_hub_area($hub);
309       if ($area) $ret .= " in " . $area->getLink();
310     }
311
312     return $ret;
313   }
314
315   function get_address_area($address) {
316     $q = new AreaQuery;
317     return $q->findOneById($address->getAreaId());
318   }
319
320   function get_address_map_link($address) {
321     $postcode = trim($address->getPostcode());
322     if ($postcode) {
323       # mrt=loc specifies a location search.
324       $map = "maps.google.co.uk/maps?q=" . urlencode($postcode) . "&mrt=loc";
325       $url = "http://$map";
326       # output=embed allows display in an iframe.
327       # iwloc=near hides the popup window for the embedded view.
328       $embed = $GLOBALS['http'] . "://$map&output=embed&iwloc=near";
329       $html = " ";
330       $html .= get_small_link_with_id("map", "Map", $url);
331       $html .= "<script>\n  $(function() {\n";
332       $html .= "    var x = 0;\n";
333       $html .= "    var y = 0;\n";
334       $html .= "    var loaded = false;\n";
335       $html .= "    $(\"#map\").hover(function(e) {\n";
336       $html .= "      x = $(this).outerWidth();\n";
337       $html .= "      y = $(this).outerHeight() / 2;\n";
338       $html .= "      $(\"#popup\").css(\"left\", e.pageX + x).css(\"top\", e.pageY + y);;\n";
339       $html .= "      $(\"#popup\").show();\n";
340       $html .= "      if (! loaded) {\n";
341       $html .= "        $(\"#popup\").html(\"<iframe width='100%' height='100%' src='$embed'></iframe>\");\n";
342       $html .= "        loaded = true;\n";
343       $html .= "      }\n";
344       $html .= "    },function() {\n";
345       $html .= "      $(\"#popup\").hide();\n";
346       $html .= "    })\n";
347       $html .= "  });</script>";
348       return $html;
349     }
350   }
351
352   function get_contact_address($contact) {
353     $q = new AddressQuery;
354     return $q->findOneById($contact->getAddressId());
355   }
356
357   function get_contact_area($contact) {
358     $address = get_contact_address($contact);
359     if (! $address) return null;
360
361     return get_address_area($address);
362   }
363
364   function get_contact_city($contact) {
365     $area = get_contact_area($contact);
366     if (! $area) return null;
367
368     return get_area_city($area);
369   }
370
371   /* Parcel strings are the same so this can work. */
372   function get_contact_parcel_string($contact) {
373     return get_order_parcel_string($contact);
374   }
375
376   /* Hub and Contact are similar enough that this can work. */
377   function get_hub_address($hub) {
378     return get_contact_address($hub);
379   }
380
381   /* Hub and Contact are similar enough that this can work. */
382   function get_hub_area($hub) {
383     return get_contact_area($hub);
384   }
385
386   /* Hub and Contact are similar enough that this can work. */
387   function get_hub_city($hub) {
388     return get_contact_city($hub);
389   }
390
391   function get_area_contacts($area_id = null, $role = null) {
392     $q = new ContactQuery;
393     if (isset($area_id)) $q->useAddressQuery()->filterByAreaId($area_id)->endUse();
394     if (isset($role)) $q->where("role & $role");
395     return $q->orderByDisplayname()->find();
396   }
397
398   function get_area_requesters($area_id = null) {
399     return get_area_contacts($area_id, $GLOBALS['ROLE_REQUESTER']);
400   }
401
402   function get_area_beneficiaries($area_id = null) {
403     return get_area_contacts($area_id, $GLOBALS['ROLE_BENEFICIARY']);
404   }
405
406   function get_area_donors($area_id = null) {
407     return get_area_contacts($area_id, $GLOBALS['ROLE_DONOR']);
408   }
409
410   function get_city_contacts($city_id = null, $role = null) {
411     /* XXX */
412     $area_ids = array();
413     $areas = get_city_areas($city_id);
414     foreach ($areas as $area) $area_ids[] = $area->getId();
415     return get_area_contacts($area_ids, $role);
416   }
417
418   function get_city_requesters($city_id = null) {
419     return get_city_contacts($city_id, $GLOBALS['ROLE_REQUESTER']);
420   }
421
422   function get_city_beneficiaries($city_id = null) {
423     return get_city_contacts($city_id, $GLOBALS['ROLE_BENEFICIARY']);
424   }
425
426   function get_city_donors($city_id = null) {
427     return get_city_contacts($city_id, $GLOBALS['ROLE_DONOR']);
428   }
429
430   function get_city_drivers($city_id = null) {
431     return get_city_contacts($city_id, $GLOBALS['ROLE_DRIVER']);
432   }
433
434   function get_role_string($object, $roles) {
435     $role = $object->getRole();
436
437     $selected = array();
438
439     for ($i =0; $i < count($roles); $i++) {
440       if ($role & (1 << $i)) $selected[] = $roles[$i];
441     }
442
443     return implode(", ", $selected);
444   }
445
446   function get_contact_role_string($contact) {
447     return get_role_string($contact, $GLOBALS['contact_roles']);
448   }
449
450   function get_hub_role_string($hub) {
451     return get_role_string($hub, $GLOBALS['hub_roles']);
452   }
453
454   function show_role_form($role, $roles) {
455     for ($i = 0; $i < count($roles); $i++) {
456       echo " <input type=\"checkbox\" id=\"role_$i\" name=\"role_$i\"";
457       if ($role & (1 << $i)) echo " checked";
458       echo "><label for=\"role_$i\">$roles[$i]</label>\n";
459     }
460   }
461
462   function get_area_hubs($area_id = null) {
463     $q = new HubQuery;
464     if (isset($area_id)) $q->useAddressQuery()->filterByAreaId($area_id)->endUse();
465     return $q->orderByDisplayname()->find();
466   }
467
468   function get_city_areas($city_id = null) {
469     $q = new AreaQuery;
470     $q->join("City")->orderBy("City.Name");
471     if (isset($city_id)) $q->filterByCityId($city_id);
472     return $q->orderByName()->find();
473   }
474
475   function get_city_areas_with_contacts($city_id = null, $role = null) {
476     $q = new AreaQuery;
477     $q->join("City")->orderBy("City.Name");
478     if (isset($city_id)) $q->filterByCityId($city_id);
479     /* XXX */
480     if (isset($role)) $q->useAddressQuery()->join("Contact")->useContactQuery()->where("role & $role")->endUse()->endUse();
481     else $q->useAddressQuery()->join("Contact")->endUse();
482     return $q->orderByName()->distinct()->find();
483   }
484
485   function get_city_areas_with_hubs($city_id = null) {
486     $q = new AreaQuery;
487     $q->join("City")->orderBy("City.Name");
488     if (isset($city_id)) $q->filterByCityId($city_id);
489     $q->useAddressQuery()->join("Hub")->endUse();
490     return $q->orderByName()->distinct()->find();
491   }
492
493   function get_city_hubs($city_id = null) {
494     $q = new HubQuery;
495     if (isset($city_id)) $q->useAddressQuery()->useAreaQuery()->filterByCityId($city_id)->endUse()->endUse();
496     return $q->orderByDisplayname()->find();
497   }
498
499   function iso8601_to_ymd($iso8601) {
500     return split("-", $iso8601);
501   }
502
503   function ymd_to_iso8601($name) {
504     $y = $_POST[$name . "_y"];
505     if (! $y) return null;
506     $m = $_POST[$name . "_m"];
507     if (! $m) $m = 1;
508     $d = $_POST[$name . "_d"];
509     if (! $d) $d = 1;
510     return sprintf("%04d-%02d-%02d", $y, $m, $d);
511   }
512
513   function show_date_form($name, $date = null) {
514     if (! isset($date)) $date = date('Y-m-d', time());
515     datepicker($name, $date);
516   }
517
518   function validate_postcode($postcode, &$outward = null, &$inward = null) {
519     /*
520       Valid postcode formats (BS7666):
521
522         AN NLL
523         ABN NLL
524         ANN NLL
525         ABNN NLL
526         ABND NLL
527         ANC NLL
528
529       Where N is a number; A is a letter not including Q, V, X;
530       B is a letter not including I, J, Z; C is a letter from the set
531       ABCDEFGHJKSTUW; D is a letter from the set ABEHMNPRVWXY;
532       L is a letter from the set ABDEFGHJLNPQRSTUWXYZ.
533
534       The postcode GIR 0AA is also valid.
535     */
536     $outward = $inward = null;
537
538     /* Treat blank as valid for convenience. */
539     $postcode = trim($postcode);
540     if (! $postcode) return true;
541
542     $A = '[ABCDEFGHIJKLMNOPRSTUWYZ]';
543     $B = '[ABCDEFGHKLMNOPQRSTUVWXY]';
544     $C = '[ABCDEFGHJKSTUW]';
545     $D = '[ABEHMNPRVWXY]';
546     $L = '[ABDEFGHJLNPQRSTUWXYZ]';
547     $N = '\d';
548     if (! preg_match("/^($A$N|$A$B$N|$A$N$N|$A$B$N$N|$A$B$N$D|$A$N$C|GIR)\s*($N$L$L)$/", $postcode, $m)) return false;
549     if ($m[1] == "GIR" && $m[2] != "0AA") return false;
550     list($ignored, $outward, $inward) = $m;
551     return true;
552   }
553
554   function format_postcode($postcode, $complain = true) {
555     if (validate_postcode($postcode, $outward, $inward)) {
556       return "$outward $inward";
557     }
558     if ($complain) {
559       echo "<p>Invalid postcode!</p>\n";
560       return null;
561     }
562   }
563
564   function get_small_link_with_id() {
565     /* Args are <id>, <alt text>, <format>, [<stuff> ...] */
566     $args = func_get_args();
567     $id = array_shift($args);
568     if (isset($id)) $id = " id=\"$id\"";
569     $html = htmlspecialchars(array_shift($args));
570     $url = array_shift($args);
571     return vsprintf("<a$id class=\"small noprint\" href=\"$url\">$html</a>\n", $args);
572   }
573
574   function get_small_link() {
575     /* Args are <alt text>, <format>, [<stuff> ...] */
576     $args = func_get_args();
577     array_unshift($args, null);
578     return call_user_func_array("get_small_link_with_id", $args);
579   }
580
581   function small_link() {
582     echo call_user_func_array("get_small_link", func_get_args());
583   }
584
585   include_once("$lib_root/admin.php");
586   include_once("$lib_root/forms.php");
587
588 ?>