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