Typo fix
[drupal_tabor_2010.git] / partner / partner.module
blobfe90e80d2f269931fe90ba68b38811582937f448
1 <?php
2 // $Id$
4 /**
5  * @file
6  * Partner management module for Drupal Tábor 2010.
7  */
9 /**
10  * Implementation of hook_perm().
11  */
12 function partner_perm() {
13   return array(
14     'access partner list',
15     'create partner',
16     'edit partner',
17     'delete partner',
18   );
21 /**
22  * Implementation of hook_menu().
23  */
24 function partner_menu() {
25   $items['partner'] = array(
26     'title' => 'List partners',
27     'page callback' => 'partner_page',
28     'access arguments' => array('access partner list'),
29     'type' => MENU_NORMAL_ITEM,
30   );
31   $items['partner/list'] = array(
32     'title' => 'List',
33     'page callback' => 'partner_page',
34     'access arguments' => array('access partner list'),
35     'type' => MENU_DEFAULT_LOCAL_TASK,
36   );
37   $items['partner/add'] = array(
38     'title' => 'Add',
39     'page callback' => 'drupal_get_form',
40     'page arguments' => array('partner_form_edit'),
41     'access arguments' => array('create partner'),
42     'type' => MENU_LOCAL_TASK,
43     'weight' => 5,
44   );
45   $items['partner/%partner_entry'] = array(
46     'title' => 'Edit',
47     'page callback' => 'drupal_get_form',
48     'page arguments' => array('partner_form_edit', 1),
49     'access arguments' => array('edit partner'),
50     'type' => MENU_CALLBACK,
51   );
52   $items['partner/%partner_entry/delete'] = array(
53     'title' => 'Delete',
54     'page callback' => 'drupal_get_form',
55     'page arguments' => array('partner_form_delete', 1),
56     'access arguments' => array('delete partner'),
57     'type' => MENU_CALLBACK,
58   );
59   return $items;
62 /**
63  * Loads a partner.
64  *
65  * @param $pid
66  *   ID of the partner to be loaded.
67  * @return
68  *   Partner object (with all of its addresses), or FALSE if not found.
69  */
70 function partner_entry_load($pid) {
71   if ($partner = db_fetch_object(db_query('SELECT * FROM {partner} WHERE pid = %d', $pid))) {
72     $partner->addresses = array();
73     $result = db_query('SELECT * FROM {address} WHERE pid = %d ORDER BY weight', $pid);
74     while ($address = db_fetch_object($result)) {
75       $partner->addresses[] = $address;
76     }
77   }
78   return $partner;
81 /**
82  * Implementation of hook_theme().
83  */
84 function partner_theme($existing, $type, $theme, $path) {
85   return array(
86     'partner_form_filter' => array(
87       'arguments' => array('form' => NULL),
88     ),
89     'partner_form_edit' => array(
90       'arguments' => array('form' => NULL),
91     ),
92   );
95 /**
96  * Lists the available partners.
97  */
98 function partner_page() {
99   $pagelen = 10;
100   $filter = partner_page_build_filter_query();
101   $output = drupal_get_form('partner_form_filter');
102   $header = array(
103     array('data' => t('Name'), 'field' => 'name'),
104     array('data' => t('Favourite beer'), 'field' => 'favourite'),
105     t('Addresses'),
106   );
107   $can_edit = user_access('edit partner');
108   $can_delete = user_access('delete partner');
109   if ($can_edit || $can_delete) {
110     $header[] = array('data' => t('Operations'), 'colspan' => '2');
111   }
112   $sql = 'SELECT pid, name, favourite, COUNT(aid) AS addresses FROM {partner} LEFT JOIN {address} USING (pid)';
113   $group_by = ' GROUP BY pid';
114   $tablesort = tablesort_sql($header);
115   $result = pager_query($sql . $tablesort, $pagelen);
116   if (!empty($filter['where'])) {
117     $result = pager_query($sql .' WHERE '. $filter['where'] . $group_by . $tablesort, $pagelen, 0, NULL, $filter['args']);
118   }
119   else {
120     $result = pager_query($sql . $group_by . $tablesort, $pagelen);
121   }
122   $rows = array();
123   while ($entry = db_fetch_object($result)) {
124     $row = array(
125       check_plain($entry->name),
126       check_plain($entry->favourite),
127       $entry->addresses,
128     );
129     if ($can_edit) {
130       $row[] = l(t('Edit'), 'partner/'. $entry->pid);
131     }
132     if ($can_delete) {
133       $row[] = l(t('Delete'), 'partner/'. $entry->pid .'/delete');
134     }
135     $rows[] = $row;
136   }
137   if (empty($rows)) {
138     $output .= t('There is no partner (that meets the filter).');
139   }
140   else {
141     $output .= theme('table', $header, $rows);
142     $output .= theme('pager', NULL, $pagelen, 0);
143   }
144   return $output;
148  * Adds a non-existing partner.
150  * @param $partner = NULL
151  *   The partner object (if any) to be edited.
153  * @ingroup forms
154  * @see partner_form_add_validate()
155  * @see partner_form_add_submit()
156  */
157 function partner_form_edit($form_state, $partner = NULL) {
158   $form['pid'] = array(
159     '#type' => 'value',
160     // -1 stands for 'new'.
161     '#value' => empty($partner->pid) ? -1 : $partner->pid,
162   );
163   $form['name'] = array(
164     '#type' => 'textfield',
165     '#title' => t('Name'),
166     '#maxlength' => 100,
167     '#required' => TRUE,
168     '#description' => t('Must be unique.'),
169     '#default_value' => empty($partner->name) ? '' : $partner->name,
170   );
171   $form['favourite'] = array(
172     '#type' => 'textfield',
173     '#title' => t('Favourite beer'),
174     '#size' => 30,
175     '#maxlength' => 100,
176     '#default_value' => empty($partner->favourite) ? '' : $partner->favourite,
177   );
178   // There should be at least one empty line for a new address.
179   $form['addresses']['emptyrows'] = array(
180     '#type' => 'value',
181     '#value' => empty($form_state['values']['addresses']['emptyrows']) ? 1 : $form_state['values']['addresses']['emptyrows'],
182   );
183   // Create the new address rows as needed.
184   for ($i = 1; $i <= $form['addresses']['emptyrows']['#value']; $i++) {
185     $partner->addresses[] = (object) array(
186       // Negative value stands for 'new'.
187       'aid' => -$i,
188       // If the form has been rebuilt (eg. because the 'Add address' button
189       // has been pressed), then dig up the defaults.
190       'zipcode' => empty($form_state['values']['addresses'][-$i]['zipcode']) ? '' : $form_state['values']['addresses'][-$i]['zipcode'],
191       'city' => empty($form_state['values']['addresses'][-$i]['city']) ? '' : $form_state['values']['addresses'][-$i]['city'],
192       'street' => empty($form_state['values']['addresses'][-$i]['street']) ? '' : $form_state['values']['addresses'][-$i]['street'],
193       'weight' => empty($form_state['values']['addresses'][-$i]['weight']) ? 0 : $form_state['values']['addresses'][-$i]['weight'],
194     );
195   }
196   foreach ($partner->addresses as $address) {
197     $form['addresses'][$address->aid]['aid'] = array(
198       '#type' => 'value',
199       '#value' => $address->aid,
200     );
201     $form['addresses'][$address->aid]['zipcode'] = array(
202       '#type' => 'textfield',
203       '#title' => t('Zip code'),
204       '#size' => 10,
205       '#maxlength' => 10,
206       '#default_value' => empty($address->zipcode) ? '' : $address->zipcode,
207     );
208     $form['addresses'][$address->aid]['city'] = array(
209       '#type' => 'textfield',
210       '#title' => t('City'),
211       '#maxlength' => 100,
212       '#default_value' => empty($address->city) ? '' : $address->city,
213     );
214     $form['addresses'][$address->aid]['street'] = array(
215       '#type' => 'textfield',
216       '#title' => t('Street address'),
217       '#maxlength' => 100,
218       '#default_value' => empty($address->street) ? '' : $address->street,
219     );
220     $form['addresses'][$address->aid]['weight'] = array(
221       '#type' => 'weight',
222       '#title' => t('Weight'),
223       '#default_value' => empty($address->weight) ? 0 : $address->weight,
224     );
225     $form['addresses'][$address->aid]['remove'] = array(
226       '#type' => 'checkbox',
227       '#title' => t('Remove'),
228       '#default_value' => empty($form_state['values']['addresses'][$address->aid]['remove']) ? FALSE : $form_state['values']['addresses'][$address->aid]['remove'],
229     );
230   }
231   $form['addresses']['addaddress'] = array(
232     '#type' => 'submit',
233     '#value' => t('Add address'),
234   );
235   $form['addresses']['#tree'] = TRUE;
236   $form['buttons']['submit'] = array(
237     '#type' => 'submit',
238     '#value' => t('Save'),
239   );
240   if ($partner && $partner->pid) {
241     drupal_set_title(t('Edit %name', array('%name' => $partner->name)));
242   }
243   return $form;
247  * Verify that a (new) partner is valid.
249  * @see partner_form_edit()
250  * @see partner_form_edit_submit()
251  */
252 function partner_form_edit_validate($form, &$form_state) {
253   $old_pid = db_result(db_query("SELECT pid FROM {partner} WHERE name = '%s' AND (NOT (pid = %d))", $form_state['values']['name'], $form_state['values']['pid']));
254   if ($old_pid) {
255     form_set_error('name', t('This partner name already exists.'));
256   }
257   if ($form_state['clicked_button']['#value'] == t('Add address')) {
258     $form_state['values']['addresses']['emptyrows']++;
259     $form_state['rebuild'] = TRUE;
260   }
264  * Save a (new) partner to the database.
266  * @see partner_form_edit()
267  * @see partner_form_edit_validate()
268  */
269 function partner_form_edit_submit($form, &$form_state) {
270   $key = array();
271   // If the partner ID is positive, then we UPDATE that partner.
272   if ($form_state['values']['pid'] != -1) {
273     $key[] = 'pid';
274   }
275   // $form_state['values']['pid'] will hold the partner ID, whether it's a new
276   // partner or not.
277   $saved = drupal_write_record('partner', $form_state['values'], $key);
278   switch ($saved) {
279   case SAVED_NEW:
280     watchdog('partner', '%name has been added to the partners.', array('%name' => $form_state['values']['name']), WATCHDOG_NOTICE, l(t('edit'), 'partner/'. $form_state['values']['pid']));
281     drupal_set_message(t('%name has been added to the partners.', array('%name' => $form_state['values']['name'])));
282     break;
283   case SAVED_UPDATED:
284     watchdog('partner', '%name has been updated.', array('%name' => $form_state['values']['name']), WATCHDOG_NOTICE, l(t('edit'), 'partner/'. $form_state['values']['pid']));
285     drupal_set_message(t('%name has been updated.', array('%name' => $form_state['values']['name'])));
286     break;
287   default:
288     drupal_set_message(t('%name could not be saved (name is not unique, probably).', array('%name' => $form_state['values']['name'])), 'warning');
289     break;
290   }
291   // Do not waste time with storing addresses if the partner could not be
292   // stored.
293   if ($saved) {
294     foreach ($form_state['values']['addresses'] as $address) {
295       // Skip the button(s).
296       if (!is_array($address)) {
297         continue;
298       }
299       // Easy removing: if all fields of an already-existing address are
300       // empty, DELETE that address.
301       if (empty($address['zipcode']) && empty($address['city']) && empty($address['street']) && ($address['aid'] > 0)) {
302         db_query('DELETE FROM {address} WHERE aid = %d', $address['aid']);
303       }
304       // Easier removing: if the checkbox of an already-existing address is
305       // ticked, DELETE that address.
306       elseif ($address['remove'] && ($address['aid'] > 0)) {
307         db_query('DELETE FROM {address} WHERE aid = %d', $address['aid']);
308       }
309       else {
310         // Copy the partner ID from the partner record already stored by
311         // drupal_write_record('partner', ...).
312         $address['pid'] = $form_state['values']['pid'];
313         // If the address ID is positive, then we UPDATE that address.
314         if ($address['aid'] > 0) {
315           drupal_write_record('address', $address, 'aid');
316         }
317         // Only INSERT the new address if at least one of its (text)fields is
318         // not empty.
319         elseif (!(empty($address['zipcode']) && empty($address['city']) && empty($address['street']))) {
320           drupal_write_record('address', $address);
321         }
322       }
323     }
324   }
325   $form_state['redirect'] = 'partner';
329  * Confirms deleting a partner.
331  * @see partner_form_delete_submit()
332  */
333 function partner_form_delete($form_state, $partner) {
334   // This data is needed in the submit callback.
335   $form['pid'] = array(
336     '#type' => 'value',
337     '#value' => $partner->pid,
338   );
339   $form['name'] = array(
340     '#type' => 'value',
341     '#value' => $partner->name,
342   );
343   return confirm_form(
344     $form,
345     t('Are you sure you want to delete %name?', array('%name' => $partner->name)),
346     'partner',
347     t('This action cannot be undone.'),
348     t('Delete'),
349     t('Cancel')
350   );
354  * Execute partner deletion.
356  * @see partner_form_delete()
357  */
358 function partner_form_delete_submit($form, &$form_state) {
359   db_query("DELETE FROM {partner} WHERE pid = %d", $form_state['values']['pid']);
360   db_query("DELETE FROM {address} WHERE pid = %d", $form_state['values']['pid']);
361   watchdog('partner', '%name has been deleted.', array('%name' => $form_state['values']['name']));
362   drupal_set_message(t('%name has been deleted.', array('%name' => $form_state['values']['name'])));
363   $form_state['redirect'] = 'partner';
367  * Adds filter capability to partner_page().
369  * @ingroup forms
370  * @see partner_form_filter_validate
371  * @see partner_form_filter_submit
372  */
373 function partner_form_filter() {
374   $session = &$_SESSION['partner_page_filter'];
375   $session = is_array($session) ? $session : array();
376   $filters = partner_page_filters();
377   $form['filters'] = array(
378     '#type' => 'fieldset',
379     '#title' => t('Filter partners'),
380     '#theme' => 'partner_form_filter',
381     '#collapsible' => TRUE,
382     '#collapsed' => empty($session),
383   );
384   foreach($filters as $key => $filter) {
385     $form['filters']['status'][$key] = array(
386       '#title' => $filter['title'],
387       '#type' => $filter['type'],
388     );
389     foreach(array('options', 'maxlength', 'size', 'autocomplete_path', 'description') as $arg) {
390       if(isset($filter[$arg])) {
391         $form['filters']['status'][$key]["#$arg"] = $filter[$arg];
392       }
393     }
394     if(!empty($session[$key])) {
395       $form['filters']['status'][$key]['#default_value'] = $session[$key];
396     }
397   }
398   $form['filters']['buttons']['submit'] = array(
399     '#type' => 'submit',
400     '#value' => t('Filter'),
401   );
402   if(!empty($session)) {
403     $form['filters']['buttons']['reset'] = array(
404       '#type' => 'submit',
405       '#value' => t('Reset')
406     );
407   }
408   return $form;
412  * Validates filtering form for partner_page().
413  */
414 function partner_form_filter_validate($form, &$form_state) {
415   if ($form_state['values']['op'] == t('Filter') && empty($form_state['values']['name']) && empty($form_state['values']['favourite'])) {
416     form_set_error('name', t('You must select something to filter by.'));
417   }
421  * Stores the filtering options for partner_page() into session variables.
422  */
423 function partner_form_filter_submit($form, &$form_state) {
424   $op = $form_state['values']['op'];
425   $filters = partner_page_filters();
426   switch($op) {
427   case t('Filter'):
428     foreach($filters as $name => $filter) {
429       if (isset($form_state['values'][$name])) {
430         $_SESSION['partner_page_filter'][$name] = $form_state['values'][$name];
431       }
432     }
433     break;
434   case t('Reset'):
435     $_SESSION['partner_page_filter'] = array();
436     break;
437   }
438   // Redirect to the list.
439   $form_state['redirect'] = 'partner';
443  * Returns the available filtering options for both partner_page() and
444  * partner_page_build_filter_query().
445  */
446 function partner_page_filters() {
447   $filters = array();
448   $filters['name'] = array(
449     'type' => 'textfield',
450     'title' => t('Name'),
451     'where' => "name LIKE '%%%s%%'",
452     'description' => t('Name should contain this.'),
453     'maxlength' => 100,
454   );
455   $filters['favourite'] = array(
456     'type' => 'textfield',
457     'title' => t('Favourite beer'),
458     'where' => "favourite = '%s'",
459     'size' => 30,
460     'maxlength' => 100,
461     'description' => t('His/her favourite beer.'),
462   );
463   return $filters;
467  * Returns a pair of filter/args array for partner_page(), filled with
468  * values based on session variables, if any.
469  */
470 function partner_page_build_filter_query() {
471   if (empty($_SESSION['partner_page_filter'])) {
472     return;
473   }
474   $filters = partner_page_filters();
475   $where = $args = array();
476   foreach ($_SESSION['partner_page_filter'] as $key => $filter) {
477     $filter_where = array();
478     if (is_array($filter)) {
479       foreach($filter as $value) {
480         if(!empty($value)) {
481           $filter_where[] = $filters[$key]['where'];
482           $args[] = $value;
483         }
484       }
485     }
486     elseif (!empty($filter)) {
487       $filter_where[] = $filters[$key]['where'];
488       $args[] = $filter;
489     }
490     if (!empty($filter_where)) {
491       $where[] = '('. implode(' OR ', $filter_where) .')';
492     }
493   }
494   $where = !empty($where) ? implode(' AND ', $where) : '';
495   return array(
496     'where' => $where,
497     'args' => $args,
498   );
502  * Default theme function for partner_form_filter().
503  */
504 function theme_partner_form_filter($form = NULL) {
505   drupal_add_css(drupal_get_path('module', 'partner') .'/partner.css');
506   $buttons = drupal_render($form['buttons']);
507   return drupal_render($form) .'<div class="partner-page-filter-buttons">'. $buttons .'</div>';
511  * Default theme function for partner_form_edit().
512  */
513 function theme_partner_form_edit($form = NULL) {
514   $buttons = drupal_render($form['buttons']);
515   $header = array(
516     t('Zip code'),
517     t('City'),
518     t('Street'),
519     t('Weight'),
520     t('Remove'),
521   );
522   $rows = array();
523   foreach (element_children($form['addresses']) as $aid) {
524     // Skip the button(s).
525     if (!is_numeric($aid)) {
526       continue;
527     }
528     unset($form['addresses'][$aid]['zipcode']['#title']);
529     unset($form['addresses'][$aid]['city']['#title']);
530     unset($form['addresses'][$aid]['street']['#title']);
531     unset($form['addresses'][$aid]['weight']['#title']);
532     unset($form['addresses'][$aid]['remove']['#title']);
533     $form['addresses'][$aid]['city']['#size'] = 30;
534     $form['addresses'][$aid]['street']['#size'] = 30;
535     $rows[] = array(
536       drupal_render($form['addresses'][$aid]['zipcode']),
537       drupal_render($form['addresses'][$aid]['city']),
538       drupal_render($form['addresses'][$aid]['street']),
539       drupal_render($form['addresses'][$aid]['weight']),
540       drupal_render($form['addresses'][$aid]['remove']),
541     );
542   }
543   $rows[] = array(
544     array(
545       'colspan' => 5,
546       'data' => drupal_render($form['addresses']['addaddress']),
547     ),
548   );
549   $addresses = theme('table', $header, $rows) . drupal_render($form['addresses']);
550   $output = drupal_render($form);
551   $output .= '<div class="partner-page-edit-addresses">'. $addresses .'</div>';
552   $output .= '<div class="partner-page-edit-buttons">'. $buttons .'</div>';
553   return $output;