[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/mod/feedback/classes/ -> complete_form.php (source)

   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/>.
  16  
  17  /**
  18   * Contains class mod_feedback_complete_form
  19   *
  20   * @package   mod_feedback
  21   * @copyright 2016 Marina Glancy
  22   * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  23   */
  24  
  25  defined('MOODLE_INTERNAL') || die();
  26  
  27  /**
  28   * Class mod_feedback_complete_form
  29   *
  30   * @package   mod_feedback
  31   * @copyright 2016 Marina Glancy
  32   * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  33   */
  34  class mod_feedback_complete_form extends moodleform {
  35  
  36      /** @var int */
  37      const MODE_COMPLETE = 1;
  38      /** @var int */
  39      const MODE_PRINT = 2;
  40      /** @var int */
  41      const MODE_EDIT = 3;
  42      /** @var int */
  43      const MODE_VIEW_RESPONSE = 4;
  44      /** @var int */
  45      const MODE_VIEW_TEMPLATE = 5;
  46  
  47      /** @var int */
  48      protected $mode;
  49      /** @var mod_feedback_structure|mod_feedback_completion */
  50      protected $structure;
  51      /** @var mod_feedback_completion */
  52      protected $completion;
  53      /** @var int */
  54      protected $gopage;
  55      /** @var bool */
  56      protected $hasrequired = false;
  57  
  58      /**
  59       * Constructor
  60       *
  61       * @param int $mode
  62       * @param mod_feedback_structure $structure
  63       * @param string $formid CSS id attribute of the form
  64       * @param array $customdata
  65       */
  66      public function __construct($mode, mod_feedback_structure $structure, $formid, $customdata = null) {
  67          $this->mode = $mode;
  68          $this->structure = $structure;
  69          $this->gopage = isset($customdata['gopage']) ? $customdata['gopage'] : 0;
  70          $isanonymous = $this->structure->is_anonymous() ? ' ianonymous' : '';
  71          parent::__construct(null, $customdata, 'POST', '',
  72                  array('id' => $formid, 'class' => 'feedback_form' . $isanonymous), true);
  73      }
  74  
  75      /**
  76       * Form definition
  77       */
  78      public function definition() {
  79          $mform = $this->_form;
  80          $mform->addElement('hidden', 'id', $this->get_cm()->id);
  81          $mform->setType('id', PARAM_INT);
  82          $mform->addElement('hidden', 'courseid', $this->get_current_course_id());
  83          $mform->setType('courseid', PARAM_INT);
  84          $mform->addElement('hidden', 'gopage');
  85          $mform->setType('gopage', PARAM_INT);
  86          $mform->addElement('hidden', 'lastpage');
  87          $mform->setType('lastpage', PARAM_INT);
  88          $mform->addElement('hidden', 'startitempos');
  89          $mform->setType('startitempos', PARAM_INT);
  90          $mform->addElement('hidden', 'lastitempos');
  91          $mform->setType('lastitempos', PARAM_INT);
  92  
  93          if (isloggedin() && !isguestuser() && $this->mode != self::MODE_EDIT && $this->mode != self::MODE_VIEW_TEMPLATE &&
  94                      $this->mode != self::MODE_VIEW_RESPONSE) {
  95              // Output information about the current mode (anonymous or not) in some modes.
  96              if ($this->structure->is_anonymous()) {
  97                  $anonymousmodeinfo = get_string('anonymous', 'feedback');
  98              } else {
  99                  $anonymousmodeinfo = get_string('non_anonymous', 'feedback');
 100              }
 101              $element = $mform->addElement('static', 'anonymousmode', '',
 102                      get_string('mode', 'feedback') . ': ' . $anonymousmodeinfo);
 103              $element->setAttributes($element->getAttributes() + ['class' => 'feedback_mode']);
 104          }
 105  
 106          // Add buttons to go to previous/next pages and submit the feedback.
 107          if ($this->mode == self::MODE_COMPLETE) {
 108              $buttonarray = array();
 109              $buttonarray[] = &$mform->createElement('submit', 'gopreviouspage', get_string('previous_page', 'feedback'));
 110              $buttonarray[] = &$mform->createElement('submit', 'gonextpage', get_string('next_page', 'feedback'),
 111                      array('class' => 'form-submit'));
 112              $buttonarray[] = &$mform->createElement('submit', 'savevalues', get_string('save_entries', 'feedback'),
 113                      array('class' => 'form-submit'));
 114              $buttonarray[] = &$mform->createElement('static', 'buttonsseparator', '', '<br>');
 115              $buttonarray[] = &$mform->createElement('cancel');
 116              $mform->addGroup($buttonarray, 'buttonar', '', array(' '), false);
 117              $mform->closeHeaderBefore('buttonar');
 118          }
 119  
 120          if ($this->mode == self::MODE_COMPLETE) {
 121              $this->definition_complete();
 122          } else {
 123              $this->definition_preview();
 124          }
 125  
 126          // Set data.
 127          $this->set_data(array('gopage' => $this->gopage));
 128      }
 129  
 130      /**
 131       * Called from definition_after_data() in the completion mode
 132       *
 133       * This will add only items from a current page to the feedback and adjust the buttons
 134       */
 135      protected function definition_complete() {
 136          if (!$this->structure instanceof mod_feedback_completion) {
 137              // We should not really be here but just in case.
 138              return;
 139          }
 140          $pages = $this->structure->get_pages();
 141          $gopage = $this->gopage;
 142          $pageitems = $pages[$gopage];
 143          $hasnextpage = $gopage < count($pages) - 1; // Until we complete this page we can not trust get_next_page().
 144          $hasprevpage = $gopage && ($this->structure->get_previous_page($gopage, false) !== null);
 145  
 146          // Add elements.
 147          foreach ($pageitems as $item) {
 148              $itemobj = feedback_get_item_class($item->typ);
 149              $itemobj->complete_form_element($item, $this);
 150          }
 151  
 152          // Remove invalid buttons (for example, no "previous page" if we are on the first page).
 153          if (!$hasprevpage) {
 154              $this->remove_button('gopreviouspage');
 155          }
 156          if (!$hasnextpage) {
 157              $this->remove_button('gonextpage');
 158          }
 159          if ($hasnextpage) {
 160              $this->remove_button('savevalues');
 161          }
 162      }
 163  
 164      /**
 165       * Called from definition_after_data() in all modes except for completion
 166       *
 167       * This will add all items to the form, including pagebreaks as horizontal rules.
 168       */
 169      protected function definition_preview() {
 170          foreach ($this->structure->get_items() as $feedbackitem) {
 171              $itemobj = feedback_get_item_class($feedbackitem->typ);
 172              $itemobj->complete_form_element($feedbackitem, $this);
 173          }
 174      }
 175  
 176      /**
 177       * Removes the button that is not applicable for the current page
 178       *
 179       * @param string $buttonname
 180       */
 181      private function remove_button($buttonname) {
 182          $el = $this->_form->getElement('buttonar');
 183          foreach ($el->_elements as $idx => $button) {
 184              if ($button instanceof MoodleQuickForm_submit && $button->getName() === $buttonname) {
 185                  unset($el->_elements[$idx]);
 186                  return;
 187              }
 188          }
 189      }
 190  
 191      /**
 192       * Returns value for this element that is already stored in temporary or permanent table,
 193       * usually only available when user clicked "Previous page". Null means no value is stored.
 194       *
 195       * @param stdClass $item
 196       * @return string
 197       */
 198      public function get_item_value($item) {
 199          if ($this->structure instanceof mod_feedback_completion) {
 200              return $this->structure->get_item_value($item);
 201          }
 202          return null;
 203      }
 204  
 205      /**
 206       * Can be used by the items to get the course id for which feedback is taken
 207       *
 208       * This function returns 0 for feedbacks that are located inside the courses.
 209       * $this->get_feedback()->course will return the course where feedback is located.
 210       * $this->get_current_course_id() will return the course where user was before taking the feedback
 211       *
 212       * @return int
 213       */
 214      public function get_course_id() {
 215          return $this->structure->get_courseid();
 216      }
 217  
 218      /**
 219       * Record from 'feedback' table corresponding to the current feedback
 220       * @return stdClass
 221       */
 222      public function get_feedback() {
 223          return $this->structure->get_feedback();
 224      }
 225  
 226      /**
 227       * Current feedback mode, see constants on the top of this class
 228       * @return int
 229       */
 230      public function get_mode() {
 231          return $this->mode;
 232      }
 233  
 234      /**
 235       * Returns whether the form is frozen, some items may prefer to change the element
 236       * type in case of frozen form. For example, text or textarea element does not look
 237       * nice when frozen
 238       *
 239       * @return bool
 240       */
 241      public function is_frozen() {
 242          return $this->mode == self::MODE_VIEW_RESPONSE;
 243      }
 244  
 245      /**
 246       * Returns the current course module
 247       * @return cm_info
 248       */
 249      public function get_cm() {
 250          return $this->structure->get_cm();
 251      }
 252  
 253      /**
 254       * Returns the course where user was before taking the feedback.
 255       *
 256       * For feedbacks inside the course it will be the same as $this->get_feedback()->course.
 257       * For feedbacks on the frontpage it will be the same as $this->get_course_id()
 258       *
 259       * @return int
 260       */
 261      public function get_current_course_id() {
 262          return $this->structure->get_courseid() ?: $this->get_feedback()->course;
 263      }
 264  
 265      /**
 266       * CSS class for the item
 267       * @param stdClass $item
 268       * @return string
 269       */
 270      protected function get_suggested_class($item) {
 271          $class = "feedback_itemlist feedback-item-{$item->typ}";
 272          if ($item->dependitem) {
 273              $class .= " feedback_is_dependent";
 274          }
 275          if ($item->typ !== 'pagebreak') {
 276              $itemobj = feedback_get_item_class($item->typ);
 277              if ($itemobj->get_hasvalue()) {
 278                  $class .= " feedback_hasvalue";
 279              }
 280          }
 281          return $class;
 282      }
 283  
 284      /**
 285       * Adds an element to this form - to be used by items in their complete_form_element() method
 286       *
 287       * @param stdClass $item
 288       * @param HTML_QuickForm_element|array $element either completed form element or an array that
 289       *      can be passed as arguments to $this->_form->createElement() function
 290       * @param bool $addrequiredrule automatically add 'required' rule
 291       * @param bool $setdefaultvalue automatically set default value for element
 292       * @return HTML_QuickForm_element
 293       */
 294      public function add_form_element($item, $element, $addrequiredrule = true, $setdefaultvalue = true) {
 295          global $OUTPUT;
 296          // Add element to the form.
 297          if (is_array($element)) {
 298              if ($this->is_frozen() && $element[0] === 'text') {
 299                  // Convert 'text' element to 'static' when freezing for better display.
 300                  $element = ['static', $element[1], $element[2]];
 301              }
 302              $element = call_user_func_array(array($this->_form, 'createElement'), $element);
 303          }
 304          $element = $this->_form->addElement($element);
 305  
 306          // Prepend standard CSS classes to the element classes.
 307          $attributes = $element->getAttributes();
 308          $class = !empty($attributes['class']) ? ' ' . $attributes['class'] : '';
 309          $attributes['class'] = $this->get_suggested_class($item) . $class;
 310          $element->setAttributes($attributes);
 311  
 312          // Add required rule.
 313          if ($item->required && $addrequiredrule) {
 314              $this->_form->addRule($element->getName(), get_string('required'), 'required', null, 'client');
 315          }
 316  
 317          // Set default value.
 318          if ($setdefaultvalue && ($tmpvalue = $this->get_item_value($item))) {
 319              $this->_form->setDefault($element->getName(), $tmpvalue);
 320          }
 321  
 322          // Freeze if needed.
 323          if ($this->is_frozen()) {
 324              $element->freeze();
 325          }
 326  
 327          // Add red asterisks on required fields.
 328          if ($item->required) {
 329              $required = '<img class="req" title="'.get_string('requiredelement', 'form').'" alt="'.
 330                      get_string('requiredelement', 'form').'" src="'.$OUTPUT->pix_url('req') .'" />';
 331              $element->setLabel($element->getLabel() . $required);
 332              $this->hasrequired = true;
 333          }
 334  
 335          // Add different useful stuff to the question name.
 336          $this->add_item_label($item, $element);
 337          $this->add_item_dependencies($item, $element);
 338          $this->add_item_number($item, $element);
 339  
 340          if ($this->mode == self::MODE_EDIT) {
 341              $this->enhance_name_for_edit($item, $element);
 342          }
 343  
 344          return $element;
 345      }
 346  
 347      /**
 348       * Adds a group element to this form - to be used by items in their complete_form_element() method
 349       *
 350       * @param stdClass $item
 351       * @param string $groupinputname name for the form element
 352       * @param string $name question text
 353       * @param array $elements array of arrays that can be passed to $this->_form->createElement()
 354       * @param string $separator separator between group elements
 355       * @param string $class additional CSS classes for the form element
 356       * @return HTML_QuickForm_element
 357       */
 358      public function add_form_group_element($item, $groupinputname, $name, $elements, $separator,
 359              $class = '') {
 360          $objects = array();
 361          foreach ($elements as $element) {
 362              $object = call_user_func_array(array($this->_form, 'createElement'), $element);
 363              $objects[] = $object;
 364          }
 365          $element = $this->add_form_element($item,
 366                  ['group', $groupinputname, $name, $objects, $separator, false],
 367                  false,
 368                  false);
 369          if ($class !== '') {
 370              $attributes = $element->getAttributes();
 371              $attributes['class'] .= ' ' . $class;
 372              $element->setAttributes($attributes);
 373          }
 374          return $element;
 375      }
 376  
 377      /**
 378       * Adds an item number to the question name (if feedback autonumbering is on)
 379       * @param stdClass $item
 380       * @param HTML_QuickForm_element $element
 381       */
 382      protected function add_item_number($item, $element) {
 383          if ($this->get_feedback()->autonumbering && !empty($item->itemnr)) {
 384              $name = $element->getLabel();
 385              $element->setLabel(html_writer::span($item->itemnr. '.', 'itemnr') . ' ' . $name);
 386          }
 387      }
 388  
 389      /**
 390       * Adds an item label to the question name
 391       * @param stdClass $item
 392       * @param HTML_QuickForm_element $element
 393       */
 394      protected function add_item_label($item, $element) {
 395          if (strlen($item->label) && ($this->mode == self::MODE_EDIT || $this->mode == self::MODE_VIEW_TEMPLATE)) {
 396              $name = $element->getLabel();
 397              $name = '('.format_string($item->label).') '.$name;
 398              $element->setLabel($name);
 399          }
 400      }
 401  
 402      /**
 403       * Adds a dependency description to the question name
 404       * @param stdClass $item
 405       * @param HTML_QuickForm_element $element
 406       */
 407      protected function add_item_dependencies($item, $element) {
 408          $allitems = $this->structure->get_items();
 409          if ($item->dependitem && ($this->mode == self::MODE_EDIT || $this->mode == self::MODE_VIEW_TEMPLATE)) {
 410              if (isset($allitems[$item->dependitem])) {
 411                  $dependitem = $allitems[$item->dependitem];
 412                  $name = $element->getLabel();
 413                  $name .= html_writer::span(' ('.format_string($dependitem->label).'-&gt;'.$item->dependvalue.')',
 414                          'feedback_depend');
 415                  $element->setLabel($name);
 416              }
 417          }
 418      }
 419  
 420      /**
 421       * Returns the CSS id attribute that will be assigned by moodleform later to this element
 422       * @param stdClass $item
 423       * @param HTML_QuickForm_element $element
 424       */
 425      protected function guess_element_id($item, $element) {
 426          if (!$id = $element->getAttribute('id')) {
 427              $attributes = $element->getAttributes();
 428              $id = $attributes['id'] = 'feedback_item_' . $item->id;
 429              $element->setAttributes($attributes);
 430          }
 431          if ($element->getType() === 'group') {
 432              return 'fgroup_' . $id;
 433          }
 434          return 'fitem_' . $id;
 435      }
 436  
 437      /**
 438       * Adds editing actions to the question name in the edit mode
 439       * @param stdClass $item
 440       * @param HTML_QuickForm_element $element
 441       */
 442      protected function enhance_name_for_edit($item, $element) {
 443          global $OUTPUT;
 444          $menu = new action_menu();
 445          $menu->set_owner_selector('#' . $this->guess_element_id($item, $element));
 446          $menu->set_constraint('.feedback_form');
 447          $menu->set_alignment(action_menu::TR, action_menu::BR);
 448          $menu->set_menu_trigger(get_string('edit'));
 449          $menu->do_not_enhance();
 450          $menu->prioritise = true;
 451  
 452          $itemobj = feedback_get_item_class($item->typ);
 453          $actions = $itemobj->edit_actions($item, $this->get_feedback(), $this->get_cm());
 454          foreach ($actions as $action) {
 455              $menu->add($action);
 456          }
 457          $editmenu = $OUTPUT->render($menu);
 458  
 459          $name = $element->getLabel();
 460  
 461          $name = html_writer::span('', 'itemdd', array('id' => 'feedback_item_box_' . $item->id)) .
 462                  html_writer::span($name, 'itemname') .
 463                  html_writer::span($editmenu, 'itemactions');
 464          $element->setLabel(html_writer::span($name, 'itemtitle'));
 465      }
 466  
 467      /**
 468       * Sets the default value for form element - alias to $this->_form->setDefault()
 469       * @param HTML_QuickForm_element|string $element
 470       * @param mixed $defaultvalue
 471       */
 472      public function set_element_default($element, $defaultvalue) {
 473          if ($element instanceof HTML_QuickForm_element) {
 474              $element = $element->getName();
 475          }
 476          $this->_form->setDefault($element, $defaultvalue);
 477      }
 478  
 479  
 480      /**
 481       * Sets the default value for form element - wrapper to $this->_form->setType()
 482       * @param HTML_QuickForm_element|string $element
 483       * @param int $type
 484       */
 485      public function set_element_type($element, $type) {
 486          if ($element instanceof HTML_QuickForm_element) {
 487              $element = $element->getName();
 488          }
 489          $this->_form->setType($element, $type);
 490      }
 491  
 492      /**
 493       * Adds a validation rule for the given field - wrapper for $this->_form->addRule()
 494       *
 495       * Do not use for 'required' rule!
 496       * Required * will be added automatically, if additional validation is needed
 497       * use method {@link self::add_validation_rule()}
 498       *
 499       * @param string $element Form element name
 500       * @param string $message Message to display for invalid data
 501       * @param string $type Rule type, use getRegisteredRules() to get types
 502       * @param string $format (optional)Required for extra rule data
 503       * @param string $validation (optional)Where to perform validation: "server", "client"
 504       * @param bool $reset Client-side validation: reset the form element to its original value if there is an error?
 505       * @param bool $force Force the rule to be applied, even if the target form element does not exist
 506       */
 507      public function add_element_rule($element, $message, $type, $format = null, $validation = 'server',
 508              $reset = false, $force = false) {
 509          if ($element instanceof HTML_QuickForm_element) {
 510              $element = $element->getName();
 511          }
 512          $this->_form->addRule($element, $message, $type, $format, $validation, $reset, $force);
 513      }
 514  
 515      /**
 516       * Adds a validation rule to the form
 517       *
 518       * @param callable $callback with arguments ($values, $files)
 519       */
 520      public function add_validation_rule(callable $callback) {
 521          if ($this->mode == self::MODE_COMPLETE) {
 522              $this->_form->addFormRule($callback);
 523          }
 524      }
 525  
 526      /**
 527       * Returns a reference to the element - wrapper for function $this->_form->getElement()
 528       *
 529       * @param string $elementname Element name
 530       * @return HTML_QuickForm_element reference to element
 531       */
 532      public function get_form_element($elementname) {
 533          return $this->_form->getElement($elementname);
 534      }
 535  
 536      /**
 537       * Displays the form
 538       */
 539      public function display() {
 540          global $OUTPUT, $PAGE;
 541          // Finalize the form definition if not yet done.
 542          if (!$this->_definition_finalized) {
 543              $this->_definition_finalized = true;
 544              $this->definition_after_data();
 545          }
 546  
 547          $mform = $this->_form;
 548  
 549          // Add "This form has required fields" text in the bottom of the form.
 550          if (($mform->_required || $this->hasrequired) &&
 551                 ($this->mode == self::MODE_COMPLETE || $this->mode == self::MODE_PRINT || $this->mode == self::MODE_VIEW_TEMPLATE)) {
 552              $element = $mform->addElement('static', 'requiredfields', '',
 553                      get_string('somefieldsrequired', 'form',
 554                              '<img alt="'.get_string('requiredelement', 'form').'" src="'.$OUTPUT->pix_url('req') .'" />'));
 555              $element->setAttributes($element->getAttributes() + ['class' => 'requirednote']);
 556          }
 557  
 558          // Reset _required array so the default red * are not displayed.
 559          $mform->_required = array();
 560  
 561          // Move buttons to the end of the form.
 562          if ($this->mode == self::MODE_COMPLETE) {
 563              $mform->addElement('hidden', '__dummyelement');
 564              $buttons = $mform->removeElement('buttonar', false);
 565              $mform->insertElementBefore($buttons, '__dummyelement');
 566              $mform->removeElement('__dummyelement');
 567          }
 568  
 569          $this->_form->display();
 570  
 571          if ($this->mode == self::MODE_EDIT) {
 572              $PAGE->requires->js_call_amd('mod_feedback/edit', 'setup');
 573          }
 574      }
 575  }


Generated: Thu Aug 11 10:00:09 2016 Cross-referenced by PHPXref 0.7.1