MDL-67264 core_course: Begin set up for Activity chooser
[moodle.git] / webservice / renderer.php
1 <?php
2 // This file is part of Moodle - http://moodle.org/
3 //
4 // Moodle is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // Moodle is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
18 /**
19  * Web service documentation renderer.
20  *
21  * @package    core_webservice
22  * @category   output
23  * @copyright  2009 Jerome Mouneyrac <jerome@moodle.com>
24  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
25  */
26 class core_webservice_renderer extends plugin_renderer_base {
28     /**
29      * Display the authorised user selector
30      *
31      * @param stdClass $options It contains alloweduserselector, potentialuserselector and serviceid
32      * @return string html
33      */
34     public function admin_authorised_user_selector(&$options) {
35         global $CFG;
36         $formcontent = html_writer::empty_tag('input',
37                         array('name' => 'sesskey', 'value' => sesskey(), 'type' => 'hidden'));
39         $table = new html_table();
40         $table->size = array('45%', '10%', '45%');
41         $table->attributes['class'] = 'roleassigntable generaltable generalbox boxaligncenter';
42         $table->summary = '';
43         $table->cellspacing = 0;
44         $table->cellpadding = 0;
46         // LTR/RTL support, for drawing button arrows in the right direction
47         if (right_to_left()) {
48             $addarrow = '▶';
49             $removearrow = '◀';
50         } else {
51             $addarrow = '◀';
52             $removearrow = '▶';
53         }
55         //create the add and remove button
56         $addinput = html_writer::empty_tag('input',
57                         array('name' => 'add', 'id' => 'add', 'type' => 'submit',
58                             'value' => $addarrow . ' ' . get_string('add'),
59                             'title' => get_string('add')));
60         $addbutton = html_writer::tag('div', $addinput, array('id' => 'addcontrols'));
61         $removeinput = html_writer::empty_tag('input',
62                         array('name' => 'remove', 'id' => 'remove', 'type' => 'submit',
63                             'value' => $removearrow . ' ' . get_string('remove'),
64                             'title' => get_string('remove')));
65         $removebutton = html_writer::tag('div', $removeinput, array('id' => 'removecontrols'));
68         //create the three cells
69         $label = html_writer::tag('label', get_string('serviceusers', 'webservice'),
70                         array('for' => 'removeselect'));
71         $label = html_writer::tag('p', $label);
72         $authoriseduserscell = new html_table_cell($label .
73                         $options->alloweduserselector->display(true));
74         $authoriseduserscell->id = 'existingcell';
75         $buttonscell = new html_table_cell($addbutton . html_writer::empty_tag('br') . $removebutton);
76         $buttonscell->id = 'buttonscell';
77         $label = html_writer::tag('label', get_string('potusers', 'webservice'),
78                         array('for' => 'addselect'));
79         $label = html_writer::tag('p', $label);
80         $otheruserscell = new html_table_cell($label .
81                         $options->potentialuserselector->display(true));
82         $otheruserscell->id = 'potentialcell';
84         $cells = array($authoriseduserscell, $buttonscell, $otheruserscell);
85         $row = new html_table_row($cells);
86         $table->data[] = $row;
87         $formcontent .= html_writer::table($table);
89         $formcontent = html_writer::tag('div', $formcontent);
91         $actionurl = new moodle_url('/' . $CFG->admin . '/webservice/service_users.php',
92                         array('id' => $options->serviceid));
93         $html = html_writer::tag('form', $formcontent,
94                         array('id' => 'assignform', 'action' => $actionurl, 'method' => 'post'));
95         return $html;
96     }
98     /**
99      * Display list of authorised users
100      *
101      * @param array $users authorised users
102      * @param int $serviceid service id
103      * @return string $html
104      */
105     public function admin_authorised_user_list($users, $serviceid) {
106         global $CFG;
107         $html = $this->output->box_start('generalbox', 'alloweduserlist');
108         foreach ($users as $user) {
109             $modifiedauthoriseduserurl = new moodle_url('/' . $CFG->admin . '/webservice/service_user_settings.php',
110                             array('userid' => $user->id, 'serviceid' => $serviceid));
111             $html .= html_writer::tag('a', $user->firstname . " "
112                             . $user->lastname . ", " . s($user->email),
113                             array('href' => $modifiedauthoriseduserurl));
114             //add missing capabilities
115             if (!empty($user->missingcapabilities)) {
116                 $html .= html_writer::tag('div',
117                                 get_string('usermissingcaps', 'webservice', $user->missingcapabilities)
118                                 . '&nbsp;' . $this->output->help_icon('missingcaps', 'webservice'),
119                                 array('class' => 'missingcaps', 'id' => 'usermissingcaps'));
120                 $html .= html_writer::empty_tag('br');
121             } else {
122                 $html .= html_writer::empty_tag('br') . html_writer::empty_tag('br');
123             }
124         }
125         $html .= $this->output->box_end();
126         return $html;
127     }
129     /**
130      * Display a confirmation page to remove a function from a service
131      *
132      * @param stdClass $function It needs function id + function name properties.
133      * @param stdClass $service It needs service id + service name properties.
134      * @return string html
135      */
136     public function admin_remove_service_function_confirmation($function, $service) {
137         $optionsyes = array('id' => $service->id, 'action' => 'delete',
138             'confirm' => 1, 'sesskey' => sesskey(), 'fid' => $function->id);
139         $optionsno = array('id' => $service->id);
140         $formcontinue = new single_button(new moodle_url('service_functions.php',
141                                 $optionsyes), get_string('remove'));
142         $formcancel = new single_button(new moodle_url('service_functions.php',
143                                 $optionsno), get_string('cancel'), 'get');
144         return $this->output->confirm(get_string('removefunctionconfirm', 'webservice',
145                         (object) array('service' => $service->name, 'function' => $function->name)),
146                 $formcontinue, $formcancel);
147     }
149     /**
150      * Display a confirmation page to remove a service
151      *
152      * @param stdClass $service It needs service id + service name properties.
153      * @return string html
154      */
155     public function admin_remove_service_confirmation($service) {
156         global $CFG;
157         $optionsyes = array('id' => $service->id, 'action' => 'delete',
158             'confirm' => 1, 'sesskey' => sesskey());
159         $optionsno = array('section' => 'externalservices');
160         $formcontinue = new single_button(new moodle_url('service.php', $optionsyes),
161                         get_string('delete'), 'post');
162         $formcancel = new single_button(
163                         new moodle_url($CFG->wwwroot . "/" . $CFG->admin . "/settings.php", $optionsno),
164                         get_string('cancel'), 'get');
165         return $this->output->confirm(get_string('deleteserviceconfirm', 'webservice', $service->name),
166                 $formcontinue, $formcancel);
167     }
169     /**
170      * Display a confirmation page to delete a token
171      *
172      * @param stdClass $token Required properties: id (token id), firstname (user firstname), lastname (user lastname), name (service name)
173      * @return string html
174      */
175     public function admin_delete_token_confirmation($token) {
176         global $CFG;
177         $optionsyes = array('tokenid' => $token->id, 'action' => 'delete',
178             'confirm' => 1, 'sesskey' => sesskey());
179         $optionsno = array('section' => 'webservicetokens', 'sesskey' => sesskey());
180         $formcontinue = new single_button(
181                         new moodle_url('/' . $CFG->admin . '/webservice/tokens.php', $optionsyes),
182                         get_string('delete'));
183         $formcancel = new single_button(
184                         new moodle_url('/' . $CFG->admin . '/settings.php', $optionsno),
185                         get_string('cancel'), 'get');
186         return $this->output->confirm(get_string('deletetokenconfirm', 'webservice',
187                         (object) array('user' => $token->firstname . " "
188                             . $token->lastname, 'service' => $token->name)),
189                 $formcontinue, $formcancel);
190     }
192     /**
193      * Display a list of functions for a given service
194      * If the service is built-in, do not display remove/add operation (read-only)
195      *
196      * @param array $functions list of functions
197      * @param stdClass $service the given service
198      * @return string the table html + add operation html
199      */
200     public function admin_service_function_list($functions, $service) {
201         global $CFG;
202         if (!empty($functions)) {
203             $table = new html_table();
204             $table->head = array(get_string('function', 'webservice'),
205                 get_string('description'), get_string('requiredcaps', 'webservice'));
206             $table->align = array('left', 'left', 'left');
207             $table->size = array('15%', '40%', '40%');
208             $table->width = '100%';
209             $table->align[] = 'left';
211             //display remove function operation (except for build-in service)
212             if (empty($service->component)) {
213                 $table->head[] = get_string('edit');
214                 $table->align[] = 'center';
215             }
217             $anydeprecated = false;
218             foreach ($functions as $function) {
219                 $function = external_api::external_function_info($function);
221                 if (!empty($function->deprecated)) {
222                     $anydeprecated = true;
223                 }
224                 $requiredcaps = html_writer::tag('div',
225                                 empty($function->capabilities) ? '' : $function->capabilities,
226                                 array('class' => 'functiondesc'));
227                 ;
228                 $description = html_writer::tag('div', $function->description,
229                                 array('class' => 'functiondesc'));
230                 //display remove function operation (except for build-in service)
231                 if (empty($service->component)) {
232                     $removeurl = new moodle_url('/' . $CFG->admin . '/webservice/service_functions.php',
233                                     array('sesskey' => sesskey(), 'fid' => $function->id,
234                                         'id' => $service->id,
235                                         'action' => 'delete'));
236                     $removelink = html_writer::tag('a',
237                                     get_string('removefunction', 'webservice'),
238                                     array('href' => $removeurl));
239                     $table->data[] = array($function->name, $description, $requiredcaps, $removelink);
240                 } else {
241                     $table->data[] = array($function->name, $description, $requiredcaps);
242                 }
243             }
245             $html = html_writer::table($table);
246         } else {
247             $html = get_string('nofunctions', 'webservice') . html_writer::empty_tag('br');
248         }
250         //display add function operation (except for build-in service)
251         if (empty($service->component)) {
253             if (!empty($anydeprecated)) {
254                 debugging('This service uses deprecated functions, replace them by the proposed ones and update your client/s.', DEBUG_DEVELOPER);
255             }
256             $addurl = new moodle_url('/' . $CFG->admin . '/webservice/service_functions.php',
257                             array('sesskey' => sesskey(), 'id' => $service->id, 'action' => 'add'));
258             $html .= html_writer::tag('a', get_string('addfunctions', 'webservice'), array('href' => $addurl));
259         }
261         return $html;
262     }
264     /**
265      * Display Reset token confirmation box
266      *
267      * @param stdClass $token token to reset
268      * @return string html
269      */
270     public function user_reset_token_confirmation($token) {
271         global $CFG;
272         $managetokenurl = $CFG->wwwroot . "/user/managetoken.php?sesskey=" . sesskey();
273         $optionsyes = array('tokenid' => $token->id, 'action' => 'resetwstoken', 'confirm' => 1,
274             'sesskey' => sesskey());
275         $optionsno = array('section' => 'webservicetokens', 'sesskey' => sesskey());
276         $formcontinue = new single_button(new moodle_url($managetokenurl, $optionsyes),
277                         get_string('reset'));
278         $formcancel = new single_button(new moodle_url($managetokenurl, $optionsno),
279                         get_string('cancel'), 'get');
280         $html = $this->output->confirm(get_string('resettokenconfirm', 'webservice',
281                                 (object) array('user' => $token->firstname . " " .
282                                     $token->lastname, 'service' => $token->name)),
283                         $formcontinue, $formcancel);
284         return $html;
285     }
287     /**
288      * Display user tokens with buttons to reset them
289      *
290      * @param stdClass $tokens user tokens
291      * @param int $userid user id
292      * @param bool $documentation if true display a link to the API documentation
293      * @return string html code
294      */
295     public function user_webservice_tokens_box($tokens, $userid, $documentation = false) {
296         global $CFG, $DB;
298         // display strings
299         $stroperation = get_string('operation', 'webservice');
300         $strtoken = get_string('key', 'webservice');
301         $strservice = get_string('service', 'webservice');
302         $strcreator = get_string('tokencreator', 'webservice');
303         $strcontext = get_string('context', 'webservice');
304         $strvaliduntil = get_string('validuntil', 'webservice');
306         $return = $this->output->heading(get_string('securitykeys', 'webservice'), 3, 'main', true);
307         $return .= $this->output->box_start('generalbox webservicestokenui');
309         $return .= get_string('keyshelp', 'webservice');
311         $table = new html_table();
312         $table->head = array($strtoken, $strservice, $strvaliduntil, $strcreator, $stroperation);
313         $table->align = array('left', 'left', 'left', 'center', 'left', 'center');
314         $table->width = '100%';
315         $table->data = array();
317         if ($documentation) {
318             $table->head[] = get_string('doc', 'webservice');
319             $table->align[] = 'center';
320         }
322         if (!empty($tokens)) {
323             foreach ($tokens as $token) {
325                 if ($token->creatorid == $userid) {
326                     $reset = "<a href=\"" . $CFG->wwwroot . "/user/managetoken.php?sesskey="
327                             . sesskey() . "&amp;action=resetwstoken&amp;tokenid=" . $token->id . "\">";
328                     $reset .= get_string('reset') . "</a>";
329                     $creator = $token->firstname . " " . $token->lastname;
330                 } else {
331                     //retrieve administrator name
332                     $admincreator = $DB->get_record('user', array('id'=>$token->creatorid));
333                     $creator = $admincreator->firstname . " " . $admincreator->lastname;
334                     $reset = '';
335                 }
337                 $userprofilurl = new moodle_url('/user/view.php?id=' . $token->creatorid);
338                 $creatoratag = html_writer::start_tag('a', array('href' => $userprofilurl));
339                 $creatoratag .= $creator;
340                 $creatoratag .= html_writer::end_tag('a');
342                 $validuntil = '';
343                 if (!empty($token->validuntil)) {
344                     $validuntil = userdate($token->validuntil, get_string('strftimedatetime', 'langconfig'));
345                 }
347                 $tokenname = $token->name;
348                 if (!$token->enabled) { //that is the (1 token-1ws) related ws is not enabled.
349                     $tokenname = '<span class="dimmed_text">'.$token->name.'</span>';
350                 }
351                 $row = array($token->token, $tokenname, $validuntil, $creatoratag, $reset);
353                 if ($documentation) {
354                     $doclink = new moodle_url('/webservice/wsdoc.php',
355                             array('id' => $token->id, 'sesskey' => sesskey()));
356                     $row[] = html_writer::tag('a', get_string('doc', 'webservice'),
357                             array('href' => $doclink));
358                 }
360                 $table->data[] = $row;
361             }
362             $return .= html_writer::table($table);
363         } else {
364             $return .= get_string('notoken', 'webservice');
365         }
367         $return .= $this->output->box_end();
368         return $return;
369     }
371     /**
372      * Return documentation for a ws description object
373      * ws description object can be 'external_multiple_structure', 'external_single_structure'
374      * or 'external_value'
375      *
376      * Example of documentation for core_group_create_groups function:
377      * list of (
378      *     object {
379      *         courseid int //id of course
380      *         name string //multilang compatible name, course unique
381      *         description string //group description text
382      *         enrolmentkey string //group enrol secret phrase
383      *     }
384      * )
385      *
386      * @param stdClass $params a part of parameter/return description
387      * @return string the html to display
388      */
389     public function detailed_description_html($params) {
390         // retrieve the description of the description object
391         $paramdesc = "";
392         if (!empty($params->desc)) {
393             $paramdesc .= html_writer::start_tag('span', array('style' => "color:#2A33A6"));
394             if ($params->required == VALUE_REQUIRED) {
395                 $required = '';
396             }
397             if ($params->required == VALUE_DEFAULT) {
398                 if ($params->default === null) {
399                     $params->default = "null";
400                 }
401                 $required = html_writer::start_tag('b', array()) .
402                         get_string('default', 'webservice', print_r($params->default, true))
403                         . html_writer::end_tag('b');
404             }
405             if ($params->required == VALUE_OPTIONAL) {
406                 $required = html_writer::start_tag('b', array()) .
407                         get_string('optional', 'webservice') . html_writer::end_tag('b');
408             }
409             $paramdesc .= " " . $required . " ";
410             $paramdesc .= html_writer::start_tag('i', array());
411             $paramdesc .= "//";
413             $paramdesc .= s($params->desc);
415             $paramdesc .= html_writer::end_tag('i');
417             $paramdesc .= html_writer::end_tag('span');
418             $paramdesc .= html_writer::empty_tag('br', array());
419         }
421         // description object is a list
422         if ($params instanceof external_multiple_structure) {
423             return $paramdesc . "list of ( " . html_writer::empty_tag('br', array())
424             . $this->detailed_description_html($params->content) . ")";
425         } else if ($params instanceof external_single_structure) {
426             // description object is an object
427             $singlestructuredesc = $paramdesc . "object {" . html_writer::empty_tag('br', array());
428             foreach ($params->keys as $attributname => $attribut) {
429                 $singlestructuredesc .= html_writer::start_tag('b', array());
430                 $singlestructuredesc .= $attributname;
431                 $singlestructuredesc .= html_writer::end_tag('b');
432                 $singlestructuredesc .= " " .
433                         $this->detailed_description_html($params->keys[$attributname]);
434             }
435             $singlestructuredesc .= "} ";
436             $singlestructuredesc .= html_writer::empty_tag('br', array());
437             return $singlestructuredesc;
438         } else {
439             // description object is a primary type (string, integer)
440             switch ($params->type) {
441                 case PARAM_BOOL: // 0 or 1 only for now
442                 case PARAM_INT:
443                     $type = 'int';
444                     break;
445                 case PARAM_FLOAT;
446                     $type = 'double';
447                     break;
448                 default:
449                     $type = 'string';
450             }
451             return $type . " " . $paramdesc;
452         }
453     }
455     /**
456      * Return a description object in indented xml format (for REST response)
457      * It is indented to be output within <pre> tags
458      *
459      * @param external_description $returndescription the description structure of the web service function returned value
460      * @param string $indentation Indentation in the generated HTML code; should contain only spaces.
461      * @return string the html to diplay
462      */
463     public function description_in_indented_xml_format($returndescription, $indentation = "") {
464         $indentation = $indentation . "    ";
465         $brakeline = <<<EOF
468 EOF;
469         // description object is a list
470         if ($returndescription instanceof external_multiple_structure) {
471             $return = $indentation . "<MULTIPLE>" . $brakeline;
472             $return .= $this->description_in_indented_xml_format($returndescription->content,
473                             $indentation);
474             $return .= $indentation . "</MULTIPLE>" . $brakeline;
475             return $return;
476         } else if ($returndescription instanceof external_single_structure) {
477             // description object is an object
478             $singlestructuredesc = $indentation . "<SINGLE>" . $brakeline;
479             $keyindentation = $indentation . "    ";
480             foreach ($returndescription->keys as $attributname => $attribut) {
481                 $singlestructuredesc .= $keyindentation . "<KEY name=\"" . $attributname . "\">"
482                         . $brakeline .
483                         $this->description_in_indented_xml_format(
484                                 $returndescription->keys[$attributname], $keyindentation) .
485                         $keyindentation . "</KEY>" . $brakeline;
486             }
487             $singlestructuredesc .= $indentation . "</SINGLE>" . $brakeline;
488             return $singlestructuredesc;
489         } else {
490             // description object is a primary type (string, integer)
491             switch ($returndescription->type) {
492                 case PARAM_BOOL: // 0 or 1 only for now
493                 case PARAM_INT:
494                     $type = 'int';
495                     break;
496                 case PARAM_FLOAT;
497                     $type = 'double';
498                     break;
499                 default:
500                     $type = 'string';
501             }
502             return $indentation . "<VALUE>" . $type . "</VALUE>" . $brakeline;
503         }
504     }
506     /**
507      * Create indented XML-RPC  param description
508      *
509      * @param external_description $paramdescription the description structure of the web service function parameters
510      * @param string $indentation Indentation in the generated HTML code; should contain only spaces.
511      * @return string the html to diplay
512      */
513     public function xmlrpc_param_description_html($paramdescription, $indentation = "") {
514         $indentation = $indentation . "    ";
515         $brakeline = <<<EOF
518 EOF;
519         // description object is a list
520         if ($paramdescription instanceof external_multiple_structure) {
521             $return = $brakeline . $indentation . "Array ";
522             $indentation = $indentation . "    ";
523             $return .= $brakeline . $indentation . "(";
524             $return .= $brakeline . $indentation . "[0] =>";
525             $return .= $this->xmlrpc_param_description_html($paramdescription->content, $indentation);
526             $return .= $brakeline . $indentation . ")";
527             return $return;
528         } else if ($paramdescription instanceof external_single_structure) {
529             // description object is an object
530             $singlestructuredesc = $brakeline . $indentation . "Array ";
531             $keyindentation = $indentation . "    ";
532             $singlestructuredesc .= $brakeline . $keyindentation . "(";
533             foreach ($paramdescription->keys as $attributname => $attribut) {
534                 $singlestructuredesc .= $brakeline . $keyindentation . "[" . $attributname . "] =>" .
535                         $this->xmlrpc_param_description_html(
536                                 $paramdescription->keys[$attributname], $keyindentation) .
537                         $keyindentation;
538             }
539             $singlestructuredesc .= $brakeline . $keyindentation . ")";
540             return $singlestructuredesc;
541         } else {
542             // description object is a primary type (string, integer)
543             switch ($paramdescription->type) {
544                 case PARAM_BOOL: // 0 or 1 only for now
545                 case PARAM_INT:
546                     $type = 'int';
547                     break;
548                 case PARAM_FLOAT;
549                     $type = 'double';
550                     break;
551                 default:
552                     $type = 'string';
553             }
554             return " " . $type;
555         }
556     }
558     /**
559      * Return the html of a coloured box with content
560      *
561      * @param string $title - the title of the box
562      * @param string $content - the content to displayed
563      * @param string $rgb - the background color of the box
564      * @return string HTML code
565      */
566     public function colored_box_with_pre_tag($title, $content, $rgb = 'FEEBE5') {
567         //TODO MDL-31192 this tag removes xhtml strict error but cause warning
568         $coloredbox = html_writer::start_tag('div', array());
569         $coloredbox .= html_writer::start_tag('div',
570                         array('style' => "border:solid 1px #DEDEDE;background:#" . $rgb
571                             . ";color:#222222;padding:4px;"));
572         $coloredbox .= html_writer::start_tag('pre', array());
573         $coloredbox .= html_writer::start_tag('b', array());
574         $coloredbox .= $title;
575         $coloredbox .= html_writer::end_tag('b', array());
576         $coloredbox .= html_writer::empty_tag('br', array());
577         $coloredbox .= "\n" . $content . "\n";
578         $coloredbox .= html_writer::end_tag('pre', array());
579         $coloredbox .= html_writer::end_tag('div', array());
580         $coloredbox .= html_writer::end_tag('div', array());
581         return $coloredbox;
582     }
584     /**
585      * Return indented REST param description
586      *
587      * @param external_description $paramdescription the description structure of the web service function parameters
588      * @param string $paramstring parameter
589      * @return string the html to diplay
590      */
591     public function rest_param_description_html($paramdescription, $paramstring) {
592         $brakeline = <<<EOF
595 EOF;
596         // description object is a list
597         if ($paramdescription instanceof external_multiple_structure) {
598             $paramstring = $paramstring . '[0]';
599             $return = $this->rest_param_description_html($paramdescription->content, $paramstring);
600             return $return;
601         } else if ($paramdescription instanceof external_single_structure) {
602             // description object is an object
603             $singlestructuredesc = "";
604             $initialparamstring = $paramstring;
605             foreach ($paramdescription->keys as $attributname => $attribut) {
606                 $paramstring = $initialparamstring . '[' . $attributname . ']';
607                 $singlestructuredesc .= $this->rest_param_description_html(
608                                 $paramdescription->keys[$attributname], $paramstring);
609             }
610             return $singlestructuredesc;
611         } else {
612             // description object is a primary type (string, integer)
613             $paramstring = $paramstring . '=';
614             switch ($paramdescription->type) {
615                 case PARAM_BOOL: // 0 or 1 only for now
616                 case PARAM_INT:
617                     $type = 'int';
618                     break;
619                 case PARAM_FLOAT;
620                     $type = 'double';
621                     break;
622                 default:
623                     $type = 'string';
624             }
625             return $paramstring . " " . $type . $brakeline;
626         }
627     }
629     /**
630      * Displays all the documentation
631      *
632      * @param array $functions external_description of all the web service functions
633      * @param boolean $printableformat true if we want to display the documentation in a printable format
634      * @param array $activatedprotocol the currently enabled protocol
635      * @param array $authparams url parameters (it contains 'tokenid' and sometimes 'print')
636      * @param string $parenturl url of the calling page - needed for the print button url:
637      *               '/admin/documentation.php' or '/webservice/wsdoc.php' (default)
638      * @return string the html to diplay
639      */
640     public function documentation_html($functions, $printableformat, $activatedprotocol,
641             $authparams, $parenturl = '/webservice/wsdoc.php') {
643         $documentationhtml = $this->output->heading(get_string('wsdocapi', 'webservice'));
645         $br = html_writer::empty_tag('br', array());
646         $brakeline = <<<EOF
649 EOF;
650         // Some general information
651         $docinfo = new stdClass();
652         $docurl = new moodle_url('http://docs.moodle.org/dev/Creating_a_web_service_client');
653         $docinfo->doclink = html_writer::tag('a',
654                         get_string('wsclientdoc', 'webservice'), array('href' => $docurl));
655         $documentationhtml .= get_string('wsdocumentationintro', 'webservice', $docinfo);
656         $documentationhtml .= $br . $br;
659         // Print button
660         $authparams['print'] = true;
661         $url = new moodle_url($parenturl, $authparams); // Required
662         $documentationhtml .= $this->output->single_button($url, get_string('print', 'webservice'));
663         $documentationhtml .= $br;
666         // each functions will be displayed into a collapsible region
667         //(opened if printableformat = true)
668         foreach ($functions as $functionname => $description) {
670             if (empty($printableformat)) {
671                 $documentationhtml .= print_collapsible_region_start('',
672                                 'aera_' . $functionname,
673                                 html_writer::start_tag('strong', array())
674                                 . $functionname . html_writer::end_tag('strong'),
675                                 false,
676                                 !$printableformat,
677                                 true);
678             } else {
679                 $documentationhtml .= html_writer::tag('strong', $functionname);
680                 $documentationhtml .= $br;
681             }
683             // function global description
684             $documentationhtml .= $br;
685             $documentationhtml .= html_writer::start_tag('div',
686                             array('style' => 'border:solid 1px #DEDEDE;background:#E2E0E0;
687                         color:#222222;padding:4px;'));
688             $documentationhtml .= s($description->description);
689             $documentationhtml .= html_writer::end_tag('div');
690             $documentationhtml .= $br . $br;
692             // function arguments documentation
693             $documentationhtml .= html_writer::start_tag('span', array('style' => 'color:#EA33A6'));
694             $documentationhtml .= get_string('arguments', 'webservice');
695             $documentationhtml .= html_writer::end_tag('span');
696             $documentationhtml .= $br;
697             foreach ($description->parameters_desc->keys as $paramname => $paramdesc) {
698                 // a argument documentation
699                 $documentationhtml .= html_writer::start_tag('span', array('style' => 'font-size:80%'));
701                 if ($paramdesc->required == VALUE_REQUIRED) {
702                     $required = get_string('required', 'webservice');
703                 }
704                 if ($paramdesc->required == VALUE_DEFAULT) {
705                     if ($paramdesc->default === null) {
706                         $default = "null";
707                     } else {
708                         $default = print_r($paramdesc->default, true);
709                     }
710                     $required = get_string('default', 'webservice', $default);
711                 }
712                 if ($paramdesc->required == VALUE_OPTIONAL) {
713                     $required = get_string('optional', 'webservice');
714                 }
716                 $documentationhtml .= html_writer::start_tag('b', array());
717                 $documentationhtml .= $paramname;
718                 $documentationhtml .= html_writer::end_tag('b');
719                 $documentationhtml .= " (" . $required . ")"; // argument is required or optional ?
720                 $documentationhtml .= $br;
721                 $documentationhtml .= "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"
722                         . s($paramdesc->desc); // Argument description.
723                 $documentationhtml .= $br . $br;
724                 // general structure of the argument
725                 $documentationhtml .= $this->colored_box_with_pre_tag(
726                                 get_string('generalstructure', 'webservice'),
727                                 $this->detailed_description_html($paramdesc),
728                                 'FFF1BC');
729                 // xml-rpc structure of the argument in PHP format
730                 if (!empty($activatedprotocol['xmlrpc'])) {
731                     $documentationhtml .= $this->colored_box_with_pre_tag(
732                                     get_string('phpparam', 'webservice'),
733                                     htmlentities('[' . $paramname . '] =>'
734                                             . $this->xmlrpc_param_description_html($paramdesc)),
735                                     'DFEEE7');
736                 }
737                 // POST format for the REST protocol for the argument
738                 if (!empty($activatedprotocol['rest'])) {
739                     $documentationhtml .= $this->colored_box_with_pre_tag(
740                                     get_string('restparam', 'webservice'),
741                                     htmlentities($this->rest_param_description_html(
742                                                     $paramdesc, $paramname)),
743                                     'FEEBE5');
744                 }
745                 $documentationhtml .= html_writer::end_tag('span');
746             }
747             $documentationhtml .= $br . $br;
750             // function response documentation
751             $documentationhtml .= html_writer::start_tag('span', array('style' => 'color:#EA33A6'));
752             $documentationhtml .= get_string('response', 'webservice');
753             $documentationhtml .= html_writer::end_tag('span');
754             $documentationhtml .= $br;
755             // function response description
756             $documentationhtml .= html_writer::start_tag('span', array('style' => 'font-size:80%'));
757             if (!empty($description->returns_desc->desc)) {
758                 $documentationhtml .= $description->returns_desc->desc;
759                 $documentationhtml .= $br . $br;
760             }
761             if (!empty($description->returns_desc)) {
762                 // general structure of the response
763                 $documentationhtml .= $this->colored_box_with_pre_tag(
764                                 get_string('generalstructure', 'webservice'),
765                                 $this->detailed_description_html($description->returns_desc),
766                                 'FFF1BC');
767                 // xml-rpc structure of the response in PHP format
768                 if (!empty($activatedprotocol['xmlrpc'])) {
769                     $documentationhtml .= $this->colored_box_with_pre_tag(
770                                     get_string('phpresponse', 'webservice'),
771                                     htmlentities($this->xmlrpc_param_description_html(
772                                                     $description->returns_desc)),
773                                     'DFEEE7');
774                 }
775                 // XML response for the REST protocol
776                 if (!empty($activatedprotocol['rest'])) {
777                     $restresponse = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>"
778                             . $brakeline . "<RESPONSE>" . $brakeline;
779                     $restresponse .= $this->description_in_indented_xml_format(
780                                     $description->returns_desc);
781                     $restresponse .="</RESPONSE>" . $brakeline;
782                     $documentationhtml .= $this->colored_box_with_pre_tag(
783                                     get_string('restcode', 'webservice'),
784                                     htmlentities($restresponse),
785                                     'FEEBE5');
786                 }
787             }
788             $documentationhtml .= html_writer::end_tag('span');
789             $documentationhtml .= $br . $br;
791             // function errors documentation for REST protocol
792             if (!empty($activatedprotocol['rest'])) {
793                 $documentationhtml .= html_writer::start_tag('span', array('style' => 'color:#EA33A6'));
794                 $documentationhtml .= get_string('errorcodes', 'webservice');
795                 $documentationhtml .= html_writer::end_tag('span');
796                 $documentationhtml .= $br . $br;
797                 $documentationhtml .= html_writer::start_tag('span', array('style' => 'font-size:80%'));
798                 $errormessage = get_string('invalidparameter', 'debug');
799                 $restexceptiontext = <<<EOF
800 <?xml version="1.0" encoding="UTF-8"?>
801 <EXCEPTION class="invalid_parameter_exception">
802     <MESSAGE>{$errormessage}</MESSAGE>
803     <DEBUGINFO></DEBUGINFO>
804 </EXCEPTION>
805 EOF;
806                 $documentationhtml .= $this->colored_box_with_pre_tag(
807                                 get_string('restexception', 'webservice'),
808                                 htmlentities($restexceptiontext),
809                                 'FEEBE5');
811                 $documentationhtml .= html_writer::end_tag('span');
812             }
813             $documentationhtml .= $br . $br;
815             // Login required info.
816             $documentationhtml .= html_writer::start_tag('span', array('style' => 'color:#EA33A6'));
817             $documentationhtml .= get_string('loginrequired', 'webservice') . $br;
818             $documentationhtml .= html_writer::end_tag('span');
819             $documentationhtml .= $description->loginrequired ? get_string('yes') : get_string('no');
820             $documentationhtml .= $br . $br;
822             // Ajax info.
823             $documentationhtml .= html_writer::start_tag('span', array('style' => 'color:#EA33A6'));
824             $documentationhtml .= get_string('callablefromajax', 'webservice') . $br;
825             $documentationhtml .= html_writer::end_tag('span');
826             $documentationhtml .= $description->allowed_from_ajax ? get_string('yes') : get_string('no');
827             $documentationhtml .= $br . $br;
829             if (empty($printableformat)) {
830                 $documentationhtml .= print_collapsible_region_end(true);
831             }
832         }
834         return $documentationhtml;
835     }