Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 3.9.x will end* 10 May 2021 (12 months).
  • Bug fixes for security issues in 3.9.x will end* 8 May 2023 (36 months).
  • PHP version: minimum PHP 7.2.0 Note: minimum PHP version has increased since Moodle 3.8. PHP 7.3.x and 7.4.x are supported too.
   1  <?php
   2  
   3  // This file is part of Moodle - http://moodle.org/
   4  //
   5  // Moodle is free software: you can redistribute it and/or modify
   6  // it under the terms of the GNU General Public License as published by
   7  // the Free Software Foundation, either version 3 of the License, or
   8  // (at your option) any later version.
   9  //
  10  // Moodle is distributed in the hope that it will be useful,
  11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13  // GNU General Public License for more details.
  14  //
  15  // You should have received a copy of the GNU General Public License
  16  // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
  17  
  18  /**
  19   * @package    moodlecore
  20   * @subpackage backup-structure
  21   * @copyright  2010 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
  22   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  23   *
  24   * TODO: Finish phpdocs
  25   */
  26  
  27  /**
  28   * Abstract class representing one optigroup for conditional branching
  29   */
  30  abstract class base_optigroup extends base_nested_element {
  31  
  32      /** @var boolean flag indicating if multiple branches can be processed (true) or no (false) */
  33      private $multiple;
  34  
  35      /**
  36       * Constructor - instantiates one base_optigroup, specifying its basic info
  37       *
  38       * @param string $name name of the element
  39       * @param array $elements base_optigroup_elements of this group
  40       * @param bool $multiple to decide if the group allows multiple branches processing or no
  41       */
  42      public function __construct($name, $elements = null, $multiple = false) {
  43          parent::__construct($name);
  44          $this->multiple = $multiple;
  45          if (!empty($elements)) {
  46              $this->add_children($elements);
  47          }
  48      }
  49  
  50  // Public API starts here
  51  
  52      /**
  53       * Return the level of this element, that will be, the level of the parent (doesn't consume level)
  54       * (note this os only a "cosmetic" effect (to_string) as fact as the real responsible for this
  55       * is the corresponding structure_processor for the final output.
  56       */
  57      public function get_level() {
  58          return $this->get_parent() == null ? 1 : $this->get_parent()->get_level();
  59      }
  60  
  61      public function to_string($showvalue = false) {
  62          $indent = str_repeat('    ', $this->get_level()); // Indent output based in level (4cc)
  63          $output = $indent . '!' . $this->get_name() . ' (level: ' . $this->get_level() . ')';
  64          $children = $this->get_children();
  65          if (!empty($children)) {
  66              foreach ($this->get_children() as $child) {
  67                  $output .= PHP_EOL . $child->to_string($showvalue);
  68              }
  69          }
  70          return $output;
  71      }
  72  
  73  // Forbidden API starts here
  74  
  75      /**
  76       * Adding attributes is forbidden
  77       */
  78      public function add_attributes($attributes) {
  79          throw new base_element_struct_exception('optigroup_not_attributes');
  80      }
  81  
  82      /**
  83       * Instantiating attributes is forbidden
  84       */
  85      protected function get_new_attribute($name) {
  86          throw new base_element_struct_exception('optigroup_not_attributes');
  87      }
  88  
  89      /**
  90       * Adding final elements is forbidden
  91       */
  92      public function add_final_elements($attributes) {
  93          throw new base_element_struct_exception('optigroup_not_final_elements');
  94      }
  95  
  96      /**
  97       * Instantiating final elements is forbidden
  98       */
  99      protected function get_new_final_element($name) {
 100          throw new base_element_struct_exception('optigroup_not_final_elements');
 101      }
 102  
 103  // Protected API starts here
 104  
 105      protected function add_children($elements) {
 106          if ($elements instanceof base_nested_element) { // Accept 1 element, object
 107              $elements = array($elements);
 108          }
 109          if (is_array($elements)) {
 110              foreach ($elements as $element) {
 111                  $this->add_child($element);
 112              }
 113          } else {
 114              throw new base_optigroup_exception('optigroup_elements_incorrect');
 115          }
 116      }
 117  
 118      /**
 119       * Set the parent of the optigroup and, at the same time, process all the
 120       * condition params in all the childs
 121       */
 122      protected function set_parent($element) {
 123          parent::set_parent($element);
 124          // Force condition param calculation in all children
 125          foreach ($this->get_children() as $child) {
 126              $child->set_condition($child->get_condition_param(), $child->get_condition_value());
 127          }
 128      }
 129  
 130      /**
 131       * Recalculate all the used elements in the optigroup, observing
 132       * restrictions and passing the new used to outer level
 133       */
 134      protected function add_used($element) {
 135          $newused = array();
 136          // Iterate over all the element useds, filling $newused and
 137          // observing the multiple setting
 138          foreach ($element->get_used() as $used) {
 139              if (!in_array($used, $this->get_used())) { // it's a new one, add to $newused array
 140                  $newused[] = $used;
 141                  $this->set_used(array_merge($this->get_used(), array($used))); // add to the optigroup used array
 142              } else { // it's an existing one, exception on multiple optigroups
 143                  if ($this->multiple) {
 144                      throw new base_optigroup_exception('multiple_optigroup_duplicate_element', $used);
 145                  }
 146              }
 147          }
 148          // Finally, inform about newused to the next grand(parent/optigroupelement)
 149          if ($newused && $this->get_parent()) {
 150              $element->set_used($newused); // Only about the newused
 151              $grandparent = $this->get_grandoptigroupelement_or_grandparent();
 152              $grandparent->check_and_set_used($element);
 153          }
 154      }
 155  
 156      protected function is_multiple() {
 157          return $this->multiple;
 158      }
 159  }
 160  
 161  /**
 162   * base_optigroup_exception to control all the errors while building the optigroups
 163   *
 164   * This exception will be thrown each time the base_optigroup class detects some
 165   * inconsistency related with the building of the group
 166   */
 167  class base_optigroup_exception extends base_atom_exception {
 168  
 169      /**
 170       * Constructor - instantiates one base_optigroup_exception
 171       *
 172       * @param string $errorcode key for the corresponding error string
 173       * @param object $a extra words and phrases that might be required in the error string
 174       * @param string $debuginfo optional debugging information
 175       */
 176      public function __construct($errorcode, $a = null, $debuginfo = null) {
 177          parent::__construct($errorcode, $a, $debuginfo);
 178      }
 179  }