/[drupal]/contributions/modules/profile_map/profile_map.module
ViewVC logotype

Contents of /contributions/modules/profile_map/profile_map.module

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.2 - (show annotations) (download) (as text)
Fri Jul 25 18:29:44 2008 UTC (16 months ago) by gestaltware
Branch: MAIN
CVS Tags: DRUPAL-5--1-1, HEAD
Changes since 1.1: +18 -13 lines
File MIME type: text/x-php
Fix themed handling for optional fields, restrict map to non-hidden fields, move profile_map settings to submenu of profile settings
1 <?php
2 // $Id$
3
4 /**
5 * @file
6 * Enables arbitrary profile fields to be mapped to a fixed data model.
7 */
8
9 define('PROFILE_HIDDEN', 4);
10
11 /**
12 * Implementation of hook_help().
13 */
14 function profile_map_help($section) {
15 switch ($section) {
16 case 'admin/modules#description':
17 return t('Maps profile fields to a fixed data model.');
18
19 case 'admin/help#profile_map':
20 return '
21 <p>
22 Profile Map enables arbitrary profile fields to be mapped to a fixed data model in the $user object so that third-party modules can easily access the profile data. The module provides callbacks when the mapped profile fields are changed, for example, to require a form to be resubmitted on an address change. Profile Map also optionally themes the mapped profile fields to display as a single field on the user page, such as Full Name instead of two separate fields for First and Last names.
23 </p>' .
24 theme('item_list', array(
25 t('Full Name: first, last'),
26 t('Address: street, city, state, postal, country'),
27 t('Phone: country code, area code, number'),
28 t('Messaging: service, userid')
29 ), t('Profile Map categories:')) . '
30 <h3>Developers</h3>
31 <p>Profile Map adds the following data model to the $user object:</p>
32 <pre>
33 stdClass Object (
34 [profile_map] => Array (
35 [name] => Array (
36 [first] => Theodore
37 [last] => Williams
38 [view] => Theodore Williams
39 )
40 [address] => Array (
41 [street] => 4 Yawkey Way
42 [city] => Boston
43 [state] => MA
44 [postal] => 02215
45 [country] => United States
46 [view] => 4 Yawkey Way, Boston, MA 02215
47 )
48 [phone] => Array (
49 [countrycode] =>
50 [areacode] => 999
51 [number] => 999-9999
52 [view] => (999) 999-9999
53 )
54 [messaging] => Array (
55 [service] => AIM
56 [username] => 400clubmember
57 [view] => AIM: 400clubmember
58 )
59 )
60 )
61 </pre>';
62
63 case 'admin/user/profile/profile_map':
64 return t('Profile Map enables arbitrary profile fields to be mapped to a fixed data model in the $user object.',
65 array('!node_types' => l('node types', 'admin/content/types')));
66 }
67 }
68
69 /**
70 * Implementation of hook_menu().
71 */
72 function profile_map_menu($may_cache) {
73 $items = array();
74 if ($may_cache) {
75 $items[] = array(
76 'path' => 'admin/user/profile/profile_map',
77 'title' => 'Profile Map',
78 'description' => t('Maps profile fields to a fixed data model.'),
79 'callback' => 'drupal_get_form',
80 'callback arguments' => 'profile_map_settings',
81 'type' => MENU_NORMAL_ITEM,
82 'access' => user_access('administer site configuration'), //do we *really* need yet another permission??
83 );
84 }
85 return $items;
86 }
87
88 /**
89 * Menu callback
90 *
91 * @return
92 * array of form content.
93 */
94 function profile_map_settings() {
95 $form = array();
96
97 // Get profile fields and group by categories
98 $category = 0;
99 $categories[0] = '<none>';
100 $result = db_query('SELECT p.fid, p.title, p.category FROM {profile_fields} p WHERE p.visibility <> %d ORDER BY p.category, p.weight', PROFILE_HIDDEN);
101 while ($profile = db_fetch_object($result)) {
102 if ($profile->category != $category) {
103 if ($category) {
104 $categories[$category] = $fields;
105 unset($fields);
106 }
107 }
108 $category = $profile->category;
109 $fields[$profile->fid] = $profile->title;
110 }
111 $categories[$category] = $fields;
112
113 // Get previous settings. We could use the standard system_settings_form but
114 // it would be more cumbersome to get the profile map from vars.
115 $result = db_query('SELECT fid, CONCAT_WS("_", category, field) AS field FROM {profile_map}');
116 while ($profile = db_fetch_object($result)) {
117 $map[$profile->field] = $profile->fid;
118 }
119
120 $form['name'] = array('#type' => 'fieldset', '#title' => t('Name profile map'));
121 $form['name']['profile_map_name_first'] = array(
122 '#type' => 'select',
123 '#title' => t('First name'),
124 '#options' => $categories,
125 '#default_value' => $map['name_first'],
126 '#description' => t('Select the profile field that maps to the first name.'),
127 '#multiple' => FALSE,
128 );
129 $form['name']['profile_map_name_last'] = array(
130 '#type' => 'select',
131 '#title' => t('Last name'),
132 '#options' => $categories,
133 '#default_value' => $map['name_last'],
134 '#description' => t('Select the profile field that maps to the last name.'),
135 '#multiple' => FALSE,
136 );
137 $form['name']['profile_map_name_view'] = array(
138 '#type' => 'checkbox',
139 '#title' => t('Replace profile name fields?'),
140 '#default_value' => variable_get('profile_map_name_view', NULL),
141 '#description' => t('Replace individual profile name fields on user page with themed name map.'),
142 );
143 $form['name']['profile_map_name-label_view'] = array(
144 '#type' => 'textfield',
145 '#title' => t('Label for themed name map'),
146 '#default_value' => variable_get('profile_map_name-label_view', t('Full Name')),
147 );
148
149 $form['address'] = array('#type' => 'fieldset', '#title' => t('Address profile map'));
150 $form['address']['profile_map_address_street'] = array(
151 '#type' => 'select',
152 '#title' => t('Street'),
153 '#options' => $categories,
154 '#default_value' => $map['address_street'],
155 '#description' => t('Select the profile field that maps to the address street.'),
156 '#multiple' => FALSE,
157 );
158 $form['address']['profile_map_address_city'] = array(
159 '#type' => 'select',
160 '#title' => t('City'),
161 '#options' => $categories,
162 '#default_value' => $map['address_city'],
163 '#description' => t('Select the profile field that maps to the address city.'),
164 '#multiple' => FALSE,
165 );
166 $form['address']['profile_map_address_state'] = array(
167 '#type' => 'select',
168 '#title' => t('State'),
169 '#options' => $categories,
170 '#default_value' => $map['address_state'],
171 '#description' => t('Select the profile field that maps to the address state.'),
172 '#multiple' => FALSE,
173 );
174 $form['address']['profile_map_address_postal'] = array(
175 '#type' => 'select',
176 '#title' => t('Postal Code'),
177 '#options' => $categories,
178 '#default_value' => $map['address_postal'],
179 '#description' => t('Select the profile field that maps to the address postal code.'),
180 '#multiple' => FALSE,
181 );
182 $form['address']['profile_map_address_country'] = array(
183 '#type' => 'select',
184 '#title' => t('Country'),
185 '#options' => $categories,
186 '#default_value' => $map['address_country'],
187 '#description' => t('Select the profile field that maps to the address postal country.'),
188 '#multiple' => FALSE,
189 );
190 $form['address']['profile_map_address_view'] = array(
191 '#type' => 'checkbox',
192 '#title' => t('Replace profile address fields?'),
193 '#default_value' => variable_get('profile_map_address_view', NULL),
194 '#description' => t('Replace individual profile address fields on user page with themed address map.'),
195 );
196 $form['address']['profile_map_address-label_view'] = array(
197 '#type' => 'textfield',
198 '#title' => t('Label for themed name map'),
199 '#default_value' => variable_get('profile_map_address-label_view', t('Address')),
200 );
201
202 $form['phone'] = array('#type' => 'fieldset', '#title' => t('Telephone profile map'));
203 $form['phone']['profile_map_phone_countrycode'] = array(
204 '#type' => 'select',
205 '#title' => t('Country code'),
206 '#options' => $categories,
207 '#default_value' => $map['phone_countrycode'],
208 '#description' => t('Select the profile field that maps to the phone country code.'),
209 '#multiple' => FALSE,
210 );
211 $form['phone']['profile_map_phone_areacode'] = array(
212 '#type' => 'select',
213 '#title' => t('Area code'),
214 '#options' => $categories,
215 '#default_value' => $map['phone_areacode'],
216 '#description' => t('Select the profile field that maps to the phone area code.'),
217 '#multiple' => FALSE,
218 );
219 $form['phone']['profile_map_phone_number'] = array(
220 '#type' => 'select',
221 '#title' => t('Phone number'),
222 '#options' => $categories,
223 '#default_value' => $map['phone_number'],
224 '#description' => t('Select the profile field that maps to the phone number.'),
225 '#multiple' => FALSE,
226 );
227 $form['phone']['profile_map_phone_view'] = array(
228 '#type' => 'checkbox',
229 '#title' => t('Replace profile phone fields?'),
230 '#default_value' => variable_get('profile_map_phone_view', NULL),
231 '#description' => t('Replace individual profile phone fields on user page with themed phone map.'),
232 );
233 $form['phone']['profile_map_phone-label_view'] = array(
234 '#type' => 'textfield',
235 '#title' => t('Label for themed phone map'),
236 '#default_value' => variable_get('profile_map_phone-label_view', t('Telephone Number')),
237 );
238
239 $form['messaging'] = array('#type' => 'fieldset', '#title' => t('Instant Messaging profile map'));
240 $form['messaging']['profile_map_messaging_service'] = array(
241 '#type' => 'select',
242 '#title' => t('Messaging service'),
243 '#options' => $categories,
244 '#default_value' => $map['messaging_service'],
245 '#description' => t('Select the profile field that maps to the messaging service.'),
246 '#multiple' => FALSE,
247 );
248 $form['messaging']['profile_map_messaging_username'] = array(
249 '#type' => 'select',
250 '#title' => t('Messaging username'),
251 '#options' => $categories,
252 '#default_value' => $map['messaging_username'],
253 '#description' => t('Select the profile field that maps to the messaging username.'),
254 '#multiple' => FALSE,
255 );
256 $form['messaging']['profile_map_messaging_view'] = array(
257 '#type' => 'checkbox',
258 '#title' => t('Replace profile messaging fields?'),
259 '#default_value' => variable_get('profile_map_messaging_view', NULL),
260 '#description' => t('Replace individual profile messaging fields on user page with themed messaging map.'),
261 );
262 $form['messaging']['profile_map_messaging-label_view'] = array(
263 '#type' => 'textfield',
264 '#title' => t('Label for themed messaging map'),
265 '#default_value' => variable_get('profile_map_messaging-label_view', t('Instant Messaging')),
266 );
267
268 $form['submit'] = array('#type' => 'submit', '#value' => 'Save Configuration');
269 return $form;
270 }
271
272 /**
273 * Validate profile map.
274 *
275 * @param $form_id
276 * The unique string identifying the form.
277 * @param $form_values
278 * An array of values mirroring the values returned by the form
279 * when it is submitted by a user.
280 */
281 function profile_map_settings_validate($form_id, $form_values) {
282 $profile_map = $duplicate_map = array();
283 foreach ($form_values as $field => $value) {
284 if (preg_match('/^profile_map_(?<category>\w+)_(?<field>\w+)$/i', $field, $db)) {
285 if ($db['field'] != 'view' && $value) {
286 if (isset($duplicate_map[$value])) {
287 form_set_error($field, t('Profile field cannot be mapped to more than 1 map field.'));
288 form_set_error($duplicate_map[$value], t('Profile field cannot be mapped to more than 1 map field.'));
289 }
290 $duplicate_map[$value] = $field;
291 }
292 }
293 }
294 }
295
296 /**
297 * Save profile map.
298 *
299 * @param $form_id
300 * The unique string identifying the form.
301 * @param $form_values
302 * An array of values mirroring the values returned by the form
303 * when it is submitted by a user.
304 */
305 function profile_map_settings_submit($form_id, $form_values) {
306 $profile_map = array();
307 db_query('DELETE FROM {profile_map} WHERE 1');
308
309 foreach ($form_values as $field => $value) {
310 if (preg_match('/^profile_map_(?<category>\w+)_(?<field>\w+)$/i', $field, $db)) {
311 if ($value && $db['field'] != 'view') {
312 db_query('INSERT INTO {profile_map} (fid, category, field) VALUES (%d, "%s", "%s")', $value, $db['category'], $db['field']);
313 }
314 $profile_map[$db['category']] = $db['category'];
315 }
316 }
317
318 foreach (array_keys($profile_map) as $category) {
319 variable_set('profile_map_' . $category . '_view', $form_values['profile_map_' . $category . '_view']);
320 variable_set('profile_map_' . $category . '-label_view', $form_values['profile_map_' . $category . '-label_view']);
321 }
322 drupal_set_message(t('The configuration options have been saved.'));
323 }
324
325 /**
326 * Implementation of hook_user().
327 */
328 function profile_map_user($type, &$edit, &$account, $category = NULL) {
329 switch ($type) {
330 /**
331 * Monitor profile fields for change and provide callback hook to other modules
332 * for $category ('name', 'address', 'messaging').
333 */
334 case 'submit':
335 $profile_map = array();
336 $edit_fields = array_keys((array)$edit);
337
338 $result = db_query('SELECT m.category, p.name FROM {profile_map} m LEFT JOIN {profile_fields} p USING (fid)');
339 while ($field = db_fetch_object($result)) {
340 if (in_array($field->name, $edit_fields)) {
341 if ($edit[$field->name] != $account->{$field->name}) {
342 $profile_map[$field->category] = $field->category;
343 }
344 }
345 }
346
347 foreach (array_keys($profile_map) as $category) {
348 module_invoke_all('profile_map', $category, $edit, $account);
349 }
350 break;
351
352 /**
353 * Load profile fields into standard profile map category structure
354 */
355 case 'load':
356 if (isset($account->profile_map)) break;
357
358 $profile_map = array();
359 $result = db_query('SELECT m.category, m.field, p.name FROM {profile_map} m LEFT JOIN {profile_fields} p USING (fid) ORDER BY m.category');
360 while ($field = db_fetch_object($result)) {
361 $profile_map[$field->category][$field->field] = $account->{$field->name};
362 }
363
364 foreach (array_keys($profile_map) as $category) {
365 $profile_map[$category]['view'] = theme('profile_map_' . $category, $profile_map[$category]);
366 }
367
368 $account->profile_map = $profile_map;
369 break;
370 }
371 }
372
373
374 /**
375 * Implementation of hook_profile_alter() in user_view.
376 *
377 * Let modules change the returned fields - useful for personal privacy
378 * controls. Since modules communicate changes by reference, we cannot use
379 * module_invoke_all().
380 */
381 function profile_map_profile_alter(&$account, &$fields) {
382 $profile_map_category = $profile_map_fields = $profile_map_fields_keys = array();
383
384 /**
385 * Get profile map category and profile field name and create two arrays:
386 * profile map category => profile category theme setting
387 * profile field => profile map category
388 */
389 $result = db_query('SELECT m.category, p.name FROM {profile_map} m LEFT JOIN {profile_fields} p USING (fid)');
390 while ($field = db_fetch_object($result)) {
391 if (!isset($profile_map_category[$field->category])) {
392 $profile_map_category[$field->category] = variable_get('profile_map_' . $field->category . '_view', NULL);
393 }
394 $profile_map_fields[$field->name] = $field->category;
395 }
396 $profile_map_fields_keys = array_keys($profile_map_fields);
397
398 /**
399 * If there is at least one themed map field, iterate through profile fields.
400 * If there is a match to a mapped field, unset the user field and set the
401 * mapped category to the user category.
402 */
403 if (array_sum($profile_map_category)) { //variable_get = 1
404 foreach ($fields as $user_category => $user_fields) {
405 foreach ($user_fields as $field => $values) {
406 if (in_array($field, $profile_map_fields_keys)) {
407 if ($profile_map_category[$profile_map_fields[$field]]) {
408 $profile_map_category[$profile_map_fields[$field]] = $user_category;
409 unset($fields[$user_category][$field]);
410 }
411 }
412 }
413 }
414
415 /**
416 * Build profile map view array and merge with $fields[$user_category]
417 */
418 foreach (array_reverse($profile_map_category) as $category => $user_category) {
419 if (strlen($account->profile_map[$category]['view'])) {
420 $fields[$user_category] = array_merge(
421 array('profile_map-' . $category => array(
422 'title' => variable_get('profile_map_' . $category . '-label_view', NULL),
423 'value' => $account->profile_map[$category]['view'],
424 'class' => 'profile_map-' . $category
425 )), (array)$fields[$user_category]
426 );
427 }
428 }
429 }
430 }
431
432 /**
433 * Sample profile_map callback handler that writes change to log.
434 */
435 function profile_map_profile_map($category, &$edit, &$account) {
436 watchdog('Profile Map', t('User %user changed %category.', array(
437 '%user' => $account->name,
438 '%category' => $category
439 )));
440 }
441
442 /**
443 * Theme function for name.
444 */
445 function theme_profile_map_name($fields) {
446 return $fields['first'] . ' ' . $fields['last'];
447 }
448
449 /**
450 * Theme function for address.
451 */
452 function theme_profile_map_address($fields) {
453 $street = $fields['street'] ? $fields['street'] . '<br />' : '';
454 $city = $fields['city'] ? $fields['city'] . ', ' : '';
455 $country = in_array($fields['country'], array('', 'US', 'United States')) ? '' : '<br />' . $fields['country'];
456
457 return $street . $city . $fields['state'] . ' ' . $fields['postal'] . $country;
458 }
459
460 /**
461 * Theme function for phone.
462 */
463 function theme_profile_map_phone($fields) {
464 $country = $fields['countrycode'] ? '+' . $fields['countrycode'] : '';
465 $area = $fields['areacode'] ? '(' . $fields['areacode'] . ') ' : '';
466
467 return $country . $area . $fields['number'];
468 }
469
470 /**
471 * Theme function for messaging.
472 */
473 function theme_profile_map_messaging($fields) {
474 return $fields['service'] ?
475 $fields['service'] . ': ' . $fields['username'] :
476 '';
477 }

  ViewVC Help
Powered by ViewVC 1.1.2