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