|
Moodle
2.2.1
http://www.collinsharper.com
|
00001 <?php 00002 00003 // This file is part of Moodle - http://moodle.org/ 00004 // 00005 // Moodle is free software: you can redistribute it and/or modify 00006 // it under the terms of the GNU General Public License as published by 00007 // the Free Software Foundation, either version 3 of the License, or 00008 // (at your option) any later version. 00009 // 00010 // Moodle is distributed in the hope that it will be useful, 00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 // GNU General Public License for more details. 00014 // 00015 // You should have received a copy of the GNU General Public License 00016 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 00017 00030 abstract class base_final_element extends base_atom { 00031 00033 private $attributes; 00034 00036 private $parent; 00037 00044 public function __construct($name, $attributes = null) { 00045 parent::__construct($name); 00046 $this->attributes = array(); 00047 if (!empty($attributes)) { 00048 $this->add_attributes($attributes); 00049 } 00050 $this->parent = null; 00051 } 00052 00056 public function destroy() { 00057 // No need to destroy anything recursively here, direct reset 00058 $this->attributes = array(); 00059 $this->parent = null; 00060 } 00061 00062 protected function set_parent($element) { 00063 if ($this->parent) { 00064 $info = new stdClass(); 00065 $info->currparent= $this->parent->get_name(); 00066 $info->newparent = $element->get_name(); 00067 $info->element = $this->get_name(); 00068 throw new base_element_parent_exception('baseelementhasparent', $info); 00069 } 00070 $this->parent = $element; 00071 } 00072 00073 protected function get_grandparent() { 00074 $parent = $this->parent; 00075 if ($parent instanceof base_nested_element) { 00076 return $parent->get_grandparent(); 00077 } else { 00078 return $this; 00079 } 00080 } 00081 00082 protected function get_grandoptigroupelement_or_grandparent() { 00083 $parent = $this->parent; 00084 if ($parent instanceof base_optigroup) { 00085 return $this; // Have found one parent optigroup, so I (first child of optigroup) am 00086 } else if ($parent instanceof base_nested_element) { 00087 return $parent->get_grandoptigroupelement_or_grandparent(); // Continue searching 00088 } else { 00089 return $this; 00090 } 00091 } 00092 00093 protected function find_element_by_path($path) { 00094 $patharr = explode('/', trim($path, '/')); // Split the path trimming slashes 00095 if (substr($path, 0, 1) == '/') { // Absolute path, go to grandparent and process 00096 if (!$this->get_grandparent() instanceof base_nested_element) { 00097 throw new base_element_struct_exception('baseelementincorrectgrandparent', $patharr[0]); 00098 } else if ($this->get_grandparent()->get_name() !== $patharr[0]) { 00099 throw new base_element_struct_exception('baseelementincorrectgrandparent', $patharr[0]); 00100 } else { 00101 $newpath = implode('/', array_slice($patharr, 1)); // Take out 1st element 00102 return $this->get_grandparent()->find_element_by_path($newpath); // Process as relative in grandparent 00103 } 00104 } else { 00105 if ($patharr[0] == '..') { // Go to parent 00106 if (!$this->get_parent() instanceof base_nested_element) { 00107 throw new base_element_struct_exception('baseelementincorrectparent', $patharr[0]); 00108 } else { 00109 $newpath = implode('/', array_slice($patharr, 1)); // Take out 1st element 00110 return $this->get_parent()->find_element_by_path($newpath); // Process as relative in parent 00111 } 00112 } else if (count($patharr) > 1) { // Go to next child 00113 if (!$this->get_child($patharr[0]) instanceof base_nested_element) { 00114 throw new base_element_struct_exception('baseelementincorrectchild', $patharr[0]); 00115 } else { 00116 $newpath = implode('/', array_slice($patharr, 1)); // Take out 1st element 00117 return $this->get_child($patharr[0])->find_element_by_path($newpath); // Process as relative in parent 00118 } 00119 } else { // Return final element or attribute 00120 if ($this->get_final_element($patharr[0]) instanceof base_final_element) { 00121 return $this->get_final_element($patharr[0]); 00122 } else if ($this->get_attribute($patharr[0]) instanceof base_attribute) { 00123 return $this->get_attribute($patharr[0]); 00124 } else { 00125 throw new base_element_struct_exception('baseelementincorrectfinalorattribute', $patharr[0]); 00126 } 00127 } 00128 } 00129 } 00130 00131 protected function find_first_parent_by_name($name) { 00132 if ($parent = $this->get_parent()) { // If element has parent 00133 $element = $parent->get_final_element($name); // Look for name into parent finals 00134 $attribute = $parent->get_attribute($name); // Look for name into parent attrs 00135 if ($element instanceof base_final_element) { 00136 return $element; 00137 00138 } else if ($attribute instanceof base_attribute) { 00139 return $attribute; 00140 00141 } else { // Not found, go up 1 level and continue searching 00142 return $parent->find_first_parent_by_name($name); 00143 } 00144 } else { // No more parents available, return the original backup::VAR_PARENTID, exception 00145 throw new base_element_struct_exception('cannotfindparentidforelement', $name); 00146 } 00147 } 00148 00149 00151 00152 public function get_attributes() { 00153 return $this->attributes; 00154 } 00155 00156 public function get_attribute($name) { 00157 if (array_key_exists($name, $this->attributes)) { 00158 return $this->attributes[$name]; 00159 } else { 00160 return null; 00161 } 00162 } 00163 00164 public function get_parent() { 00165 return $this->parent; 00166 } 00167 00168 public function get_level() { 00169 return $this->parent == null ? 1 : $this->parent->get_level() + 1; 00170 } 00171 00172 public function add_attributes($attributes) { 00173 if ($attributes instanceof base_attribute || is_string($attributes)) { // Accept 1 attribute, object or string 00174 $attributes = array($attributes); 00175 } 00176 if (is_array($attributes)) { 00177 foreach ($attributes as $attribute) { 00178 if (is_string($attribute)) { // Accept string attributes 00179 $attribute = $this->get_new_attribute($attribute); 00180 } 00181 if (!($attribute instanceof base_attribute)) { 00182 throw new base_element_attribute_exception('baseelementnoattribute', get_class($attribute)); 00183 } 00184 if (array_key_exists($attribute->get_name(), $this->attributes)) { 00185 throw new base_element_attribute_exception('baseelementattributeexists', $attribute->get_name()); 00186 } 00187 $this->attributes[$attribute->get_name()] = $attribute; 00188 } 00189 } else { 00190 throw new base_element_attribute_exception('baseelementattributeincorrect'); 00191 } 00192 } 00193 00194 public function clean_values() { 00195 parent::clean_value(); 00196 if (!empty($this->attributes)) { 00197 foreach ($this->attributes as $attribute) { 00198 $attribute->clean_value(); 00199 } 00200 } 00201 } 00202 00203 public function to_string($showvalue = false) { 00204 // Decide the correct prefix 00205 $prefix = '#'; // default 00206 if ($this->parent instanceof base_optigroup) { 00207 $prefix = '?'; 00208 } else if ($this instanceof base_nested_element) { 00209 $prefix = ''; 00210 } 00211 $indent = str_repeat(' ', $this->get_level()); // Indent output based in level (4cc) 00212 $output = $indent . $prefix . $this->get_name() . ' (level: ' . $this->get_level() . ')'; 00213 if ($showvalue) { 00214 $value = $this->is_set() ? $this->get_value() : 'not set'; 00215 $output .= ' => ' . $value; 00216 } 00217 if (!empty($this->attributes)) { 00218 foreach ($this->attributes as $attribute) { 00219 $output .= PHP_EOL . $indent . ' ' . $attribute->to_string($showvalue); 00220 } 00221 } 00222 return $output; 00223 } 00224 00225 // Implementable API 00226 00231 abstract protected function get_new_attribute($name); 00232 } 00233 00237 class base_element_parent_exception extends base_atom_exception { 00238 00246 public function __construct($errorcode, $a = null, $debuginfo = null) { 00247 parent::__construct($errorcode, $a, $debuginfo); 00248 } 00249 } 00250 00254 class base_element_attribute_exception extends base_atom_exception { 00255 00263 public function __construct($errorcode, $a = null, $debuginfo = null) { 00264 parent::__construct($errorcode, $a, $debuginfo); 00265 } 00266 }