MDL-22061 converting profile fields to real plugins with lang packs
[moodle.git] / user / profile / definelib.php
1 <?php
3 class profile_define_base {
5     /**
6      * Prints out the form snippet for creating or editing a profile field
7      * @param   object   instance of the moodleform class
8      */
9     function define_form(&$form) {
10         $form->addElement('header', '_commonsettings', get_string('profilecommonsettings', 'admin'));
11         $this->define_form_common($form);
13         $form->addElement('header', '_specificsettings', get_string('profilespecificsettings', 'admin'));
14         $this->define_form_specific($form);
15     }
17     /**
18      * Prints out the form snippet for the part of creating or
19      * editing a profile field common to all data types
20      * @param   object   instance of the moodleform class
21      */
22     function define_form_common(&$form) {
24         $strrequired = get_string('required');
26         $form->addElement('text', 'shortname', get_string('profileshortname', 'admin'), 'maxlength="100" size="25"');
27         $form->addRule('shortname', $strrequired, 'required', null, 'client');
28         $form->setType('shortname', PARAM_ALPHANUM);
30         $form->addElement('text', 'name', get_string('profilename', 'admin'), 'size="50"');
31         $form->addRule('name', $strrequired, 'required', null, 'client');
32         $form->setType('name', PARAM_MULTILANG);
34         $form->addElement('editor', 'description', get_string('profiledescription', 'admin'), null, null);
35         $form->setHelpButton('description', array('text2', get_string('helptext')));
37         $form->addElement('selectyesno', 'required', get_string('profilerequired', 'admin'));
39         $form->addElement('selectyesno', 'locked', get_string('profilelocked', 'admin'));
41         $form->addElement('selectyesno', 'forceunique', get_string('profileforceunique', 'admin'));
43         $form->addElement('selectyesno', 'signup', get_string('profilesignup', 'admin'));
45         $choices = array();
46         $choices[PROFILE_VISIBLE_NONE]    = get_string('profilevisiblenone', 'admin');
47         $choices[PROFILE_VISIBLE_PRIVATE] = get_string('profilevisibleprivate', 'admin');
48         $choices[PROFILE_VISIBLE_ALL]     = get_string('profilevisibleall', 'admin');
49         $form->addElement('select', 'visible', get_string('profilevisible', 'admin'), $choices);
50         $form->setHelpButton('visible', array('profilevisible', get_string('profilevisible','admin')));
51         $form->setDefault('visible', PROFILE_VISIBLE_ALL);
53         $choices = profile_list_categories();
54         $form->addElement('select', 'categoryid', get_string('profilecategory', 'admin'), $choices);
55     }
57     /**
58      * Prints out the form snippet for the part of creating or
59      * editing a profile field specific to the current data type
60      * @param   object   instance of the moodleform class
61      */
62     function define_form_specific(&$form) {
63         /// do nothing - overwrite if necessary
64     }
66     /**
67      * Validate the data from the add/edit profile field form.
68      * Generally this method should not be overwritten by child
69      * classes.
70      * @param   object   data from the add/edit profile field form
71      * @return  array    associative array of error messages
72      */
73     function define_validate($data, $files) {
75         $data = (object)$data;
76         $err = array();
78         $err += $this->define_validate_common($data, $files);
79         $err += $this->define_validate_specific($data, $files);
81         return $err;
82     }
84     /**
85      * Validate the data from the add/edit profile field form
86      * that is common to all data types. Generally this method
87      * should not be overwritten by child classes.
88      * @param   object   data from the add/edit profile field form
89      * @return  array    associative array of error messages
90      */
91     function define_validate_common($data, $files) {
92         global $USER, $DB;
94         $err = array();
96         /// Check the shortname was not truncated by cleaning
97         if (empty($data->shortname)) {
98             $err['shortname'] = get_string('required');
100         } else {
101         /// Fetch field-record from DB
102             $field = $DB->get_record('user_info_field', array('shortname'=>$data->shortname));
103         /// Check the shortname is unique
104             if ($field and $field->id <> $data->id) {
105                 $err['shortname'] = get_string('profileshortnamenotunique', 'admin');
107         /// Shortname must also be unique compared to the standard user fields
108             } else if (!$field and isset($USER->{$data->shortname})) {
109                 $err['shortname'] = get_string('profileshortnamenotunique', 'admin');
110             }
111         }
113         /// No further checks necessary as the form class will take care of it
114         return $err;
115     }
117     /**
118      * Validate the data from the add/edit profile field form
119      * that is specific to the current data type
120      * @param   object   data from the add/edit profile field form
121      * @return  array    associative array of error messages
122      */
123     function define_validate_specific($data, $files) {
124         /// do nothing - overwrite if necessary
125         return array();
126     }
128     /**
129      * Alter form based on submitted or existing data
130      * @param   object   form
131      */
132     function define_after_data(&$mform) {
133         /// do nothing - overwrite if necessary
134     }
136     /**
137      * Add a new profile field or save changes to current field
138      * @param   object   data from the add/edit profile field form
139      * @return  boolean  status of the insert/update record
140      */
141     function define_save($data) {
142         global $DB;
144         $data = $this->define_save_preprocess($data); /// hook for child classes
146         $old = false;
147         if (!empty($data->id)) {
148             $old = $DB->get_record('user_info_field', array('id'=>(int)$data->id));
149         }
151         /// check to see if the category has changed
152         if (!$old or $old->categoryid != $data->categoryid) {
153             $data->sortorder = $DB->count_records('user_info_field', array('categoryid'=>$data->categoryid)) + 1;
154         }
157         if (empty($data->id)) {
158             unset($data->id);
159             $data->id = $DB->insert_record('user_info_field', $data);
160         } else {
161             $DB->update_record('user_info_field', $data);
162         }
163     }
165     /**
166      * Preprocess data from the add/edit profile field form
167      * before it is saved. This method is a hook for the child
168      * classes to overwrite.
169      * @param   object   data from the add/edit profile field form
170      * @return  object   processed data object
171      */
172     function define_save_preprocess($data) {
173         /// do nothing - overwrite if necessary
174         return $data;
175     }
177     /**
178      * Provides a method by which we can allow the default data in profile_define_*
179      * to use an editor
180      *
181      * This should return an array of editor names (which will need to be formatted/cleaned)
182      *
183      * @return array
184      */
185     function define_editors() {
186         return array();
187     }
192 /**
193  * Reorder the profile fields within a given category starting
194  * at the field at the given startorder
195  */
196 function profile_reorder_fields() {
197     global $DB;
199     if ($categories = $DB->get_records('user_info_category')) {
200         foreach ($categories as $category) {
201             $i = 1;
202             if ($fields = $DB->get_records('user_info_field', array('categoryid'=>$category->id), 'sortorder ASC')) {
203                 foreach ($fields as $field) {
204                     $f = new object();
205                     $f->id = $field->id;
206                     $f->sortorder = $i++;
207                     $DB->update_record('user_info_field', $f);
208                 }
209             }
210         }
211     }
214 /**
215  * Reorder the profile categoriess starting at the category
216  * at the given startorder
217  */
218 function profile_reorder_categories() {
219     global $DB;
221     $i = 1;
222     if ($categories = $DB->get_records('user_info_category', null, 'sortorder ASC')) {
223         foreach ($categories as $cat) {
224             $c = new object();
225             $c->id = $cat->id;
226             $c->sortorder = $i++;
227             $DB->update_record('user_info_category', $c);
228         }
229     }
232 /**
233  * Delete a profile category
234  * @param   integer   id of the category to be deleted
235  * @return  boolean   success of operation
236  */
237 function profile_delete_category($id) {
238     global $DB;
240     /// Retrieve the category
241     if (!$category = $DB->get_record('user_info_category', array('id'=>$id))) {
242         print_error('invalidcategoryid');
243     }
245     if (!$categories = $DB->get_records('user_info_category', null, 'sortorder ASC')) {
246         print_error('nocate', 'debug');
247     }
249     unset($categories[$category->id]);
251     if (!count($categories)) {
252         return; //we can not delete the last category
253     }
255     /// Does the category contain any fields
256     if ($DB->count_records('user_info_field', array('categoryid'=>$category->id))) {
257         if (array_key_exists($category->sortorder-1, $categories)) {
258             $newcategory = $categories[$category->sortorder-1];
259         } else if (array_key_exists($category->sortorder+1, $categories)) {
260             $newcategory = $categories[$category->sortorder+1];
261         } else {
262             $newcategory = reset($categories); // get first category if sortorder broken
263         }
265         $sortorder = $DB->count_records('user_info_field', array('categoryid'=>$newcategory->id)) + 1;
267         if ($fields = $DB->get_records('user_info_field', array('categoryid'=>$category->id), 'sortorder ASC')) {
268             foreach ($fields as $field) {
269                 $f = new object();
270                 $f->id = $field->id;
271                 $f->sortorder = $sortorder++;
272                 $f->categoryid = $newcategory->id;
273                 $DB->update_record('user_info_field', $f);
274                 //echo "<pre>";var_dump($f);echo"</pre>";
275             }
276         }
277     }
279     /// Finally we get to delete the category
280     $DB->delete_records('user_info_category', array('id'=>$category->id));
281     profile_reorder_categories();
282     return true;
286 function profile_delete_field($id) {
287     global $DB;
289     /// Remove any user data associated with this field
290     if (!$DB->delete_records('user_info_data', array('fieldid'=>$id))) {
291         print_error('cannotdeletecustomfield');
292     }
294     /// Try to remove the record from the database
295     $DB->delete_records('user_info_field', array('id'=>$id));
297     /// Reorder the remaining fields in the same category
298     profile_reorder_fields();
301 /**
302  * Change the sortorder of a field
303  * @param   integer   id of the field
304  * @param   string    direction of move
305  * @return  boolean   success of operation
306  */
307 function profile_move_field($id, $move) {
308     global $DB;
310     /// Get the field object
311     if (!$field = $DB->get_record('user_info_field', array('id'=>$id), 'id, sortorder, categoryid')) {
312         return false;
313     }
314     /// Count the number of fields in this category
315     $fieldcount = $DB->count_records('user_info_field', array('categoryid'=>$field->categoryid));
317     /// Calculate the new sortorder
318     if ( ($move == 'up') and ($field->sortorder > 1)) {
319         $neworder = $field->sortorder - 1;
320     } elseif ( ($move == 'down') and ($field->sortorder < $fieldcount)) {
321         $neworder = $field->sortorder + 1;
322     } else {
323         return false;
324     }
326     /// Retrieve the field object that is currently residing in the new position
327     if ($swapfield = $DB->get_record('user_info_field', array('categoryid'=>$field->categoryid, 'sortorder'=>$neworder), 'id, sortorder')) {
329         /// Swap the sortorders
330         $swapfield->sortorder = $field->sortorder;
331         $field->sortorder     = $neworder;
333         /// Update the field records
334         $DB->update_record('user_info_field', $field);
335         $DB->update_record('user_info_field', $swapfield);
336     }
338     profile_reorder_fields();
341 /**
342  * Change the sortorder of a category
343  * @param   integer   id of the category
344  * @param   string    direction of move
345  * @return  boolean   success of operation
346  */
347 function profile_move_category($id, $move) {
348     global $DB;
349     /// Get the category object
350     if (!($category = $DB->get_record('user_info_category', array('id'=>$id), 'id, sortorder'))) {
351         return false;
352     }
354     /// Count the number of categories
355     $categorycount = $DB->count_records('user_info_category');
357     /// Calculate the new sortorder
358     if ( ($move == 'up') and ($category->sortorder > 1)) {
359         $neworder = $category->sortorder - 1;
360     } elseif ( ($move == 'down') and ($category->sortorder < $categorycount)) {
361         $neworder = $category->sortorder + 1;
362     } else {
363         return false;
364     }
366     /// Retrieve the category object that is currently residing in the new position
367     if ($swapcategory = $DB->get_record('user_info_category', array('sortorder'=>$neworder),'id, sortorder')) {
369         /// Swap the sortorders
370         $swapcategory->sortorder = $category->sortorder;
371         $category->sortorder     = $neworder;
373         /// Update the category records
374         if ($DB->update_record('user_info_category', $category) and $DB->update_record('user_info_category', $swapcategory)) {
375             return true;
376         }
377     }
379     return false;
382 /**
383  * Retrieve a list of all the available data types
384  * @return   array   a list of the datatypes suitable to use in a select statement
385  */
386 function profile_list_datatypes() {
387     global $CFG;
389     $datatypes = array();
391     $plugins = get_plugin_list('profilefield');
392     foreach ($plugins as $type=>$unused) {
393         $datatypes[$type] = get_string('pluginname', 'profilefield_'.$type);
394     }
395     asort($datatypes);
397     return $datatypes;
400 /**
401  * Retrieve a list of categories and ids suitable for use in a form
402  * @return   array
403  */
404 function profile_list_categories() {
405     global $DB;
406     if (!$categories = $DB->get_records_menu('user_info_category', NULL, 'sortorder ASC', 'id, name')) {
407         $categories = array();
408     }
409     return $categories;
413 /// Are we adding or editing a cateogory?
414 function profile_edit_category($id, $redirect) {
415     global $CFG, $DB, $OUTPUT;
417     require_once('index_category_form.php');
418     $categoryform = new category_form();
420     if ($category = $DB->get_record('user_info_category', array('id'=>$id))) {
421         $categoryform->set_data($category);
422     }
424     if ($categoryform->is_cancelled()) {
425         redirect($redirect);
426     } else {
427         if ($data = $categoryform->get_data()) {
428             if (empty($data->id)) {
429                 unset($data->id);
430                 $data->sortorder = $DB->count_records('user_info_category') + 1;
431                 $DB->insert_record('user_info_category', $data, false);
432             } else {
433                 $DB->update_record('user_info_category', $data);
434             }
435             profile_reorder_categories();
436             redirect($redirect);
438         }
440         if (empty($id)) {
441             $strheading = get_string('profilecreatenewcategory', 'admin');
442         } else {
443             $strheading = get_string('profileeditcategory', 'admin', format_string($category->name));
444         }
446         /// Print the page
447         echo $OUTPUT->header();
448         echo $OUTPUT->heading($strheading);
449         $categoryform->display();
450         echo $OUTPUT->footer();
451         die;
452     }
456 function profile_edit_field($id, $datatype, $redirect) {
457     global $CFG, $DB, $OUTPUT, $PAGE;
459     if (!$field = $DB->get_record('user_info_field', array('id'=>$id))) {
460         $field = new object();
461         $field->datatype = $datatype;
462         $field->description = '';
463         $field->descriptionformat = FORMAT_HTML;
464         $field->defaultdata = '';
465         $field->defaultdataformat = FORMAT_HTML;
466     }
469     // Clean and prepare description for the editor
470     $field->description = clean_text($field->description, $field->descriptionformat);
471     $field->description = array('text'=>$field->description, 'format'=>$field->descriptionformat, 'itemid'=>0);
473     require_once('index_field_form.php');
474     $fieldform = new field_form(null, $field->datatype);
476     // Convert the data format for
477     if (is_array($fieldform->editors())) {
478         foreach ($fieldform->editors() as $editor) {
479             if (isset($field->$editor)) {
480                 $field->$editor = clean_text($field->$editor, $field->{$editor.'format'});
481                 $field->$editor = array('text'=>$field->$editor, 'format'=>$field->{$editor.'format'}, 'itemid'=>0);
482             }
483         }
484     }
486     $fieldform->set_data($field);
488     if ($fieldform->is_cancelled()) {
489         redirect($redirect);
491     } else {
492         if ($data = $fieldform->get_data()) {
493             require_once($CFG->dirroot.'/user/profile/field/'.$datatype.'/define.class.php');
494             $newfield = 'profile_define_'.$datatype;
495             $formfield = new $newfield();
497             // Collect the description and format back into the proper data structure from the editor
498             // Note: This field will ALWAYS be an editor
499             $data->descriptionformat = $data->description['format'];
500             $data->description = $data->description['text'];
502             // Check whether the default data is an editor, this is (currently) only the
503             // textarea field type
504             if (is_array($data->defaultdata) && array_key_exists('text', $data->defaultdata)) {
505                 // Collect the default data and format back into the proper data structure from the editor
506                 $data->defaultdataformat = $data->defaultdata['format'];
507                 $data->defaultdata = $data->defaultdata['text'];
508             }
510             // Convert the data format for
511             if (is_array($fieldform->editors())) {
512                 foreach ($fieldform->editors() as $editor) {
513                     if (isset($field->$editor)) {
514                         $field->{$editor.'format'} = $field->{$editor}['format'];
515                         $field->$editor = $field->{$editor}['text'];
516                     }
517                 }
518             }
520             $formfield->define_save($data);
521             profile_reorder_fields();
522             profile_reorder_categories();
523             redirect($redirect);
524         }
526         $datatypes = profile_list_datatypes();
528         if (empty($id)) {
529             $strheading = get_string('profilecreatenewfield', 'admin', $datatypes[$datatype]);
530         } else {
531             $strheading = get_string('profileeditfield', 'admin', $field->name);
532         }
534         /// Print the page
535         $PAGE->navbar->add($strheading);
536         echo $OUTPUT->header();
537         echo $OUTPUT->heading($strheading);
538         $fieldform->display();
539         echo $OUTPUT->footer();
540         die;
541     }