MDL-32003 fix phpdocs in xmldb abstraction
[moodle.git] / lib / xmldb / xmldb_index.php
blob7b1b26da277a475ce192e76f859b04f993932bb6
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.
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/>.
17 /**
18 * This class represent one XMLDB Index
20 * @package core_xmldb
21 * @copyright 1999 onwards Martin Dougiamas http://dougiamas.com
22 * 2001-3001 Eloy Lafuente (stronk7) http://contiento.com
23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
26 defined('MOODLE_INTERNAL') || die();
29 class xmldb_index extends xmldb_object {
31 /** @var bool is unique? */
32 var $unique;
34 /** @var array index fields */
35 var $fields;
37 /**
38 * Note:
39 * - MySQL: MyISAM has a limit of 1000 bytes for any key including composed, InnoDB has limit 3500 bytes.
41 * @const max length of composed indexes, one utf-8 char is 3 bytes in the worst case
43 const INDEX_COMPOSED_MAX_BYTES = 999;
45 /**
46 * Note:
47 * - MySQL: InnoDB limits size of index on single column to 767bytes (256 chars)
49 * @const single column index length limit, one utf-8 char is 3 bytes in the worst case
51 const INDEX_MAX_BYTES = 765;
53 /**
54 * Creates one new xmldb_index
56 * @param string $name
57 * @param string type XMLDB_INDEX_UNIQUE, XMLDB_INDEX_NOTUNIQUE
58 * @param array fields an array of fieldnames to build the index over
60 function __construct($name, $type=null, $fields=array()) {
61 $this->unique = false;
62 $this->fields = array();
63 parent::__construct($name);
64 $this->set_attributes($type, $fields);
67 /**
68 * Set all the attributes of one xmldb_index
70 * @param string type XMLDB_INDEX_UNIQUE, XMLDB_INDEX_NOTUNIQUE
71 * @param array fields an array of fieldnames to build the index over
73 function set_attributes($type, $fields) {
74 $this->unique = !empty($type) ? true : false;
75 $this->fields = $fields;
78 /**
79 * Get the index unique
80 * @return bool
82 function getUnique() {
83 return $this->unique;
86 /**
87 * Set the index unique
88 * @param bool $unique
90 function setUnique($unique = true) {
91 $this->unique = $unique;
94 /**
95 * Set the index fields
96 * @param array $fields
98 function setFields($fields) {
99 $this->fields = $fields;
103 * Get the index fields
104 * @return array reference to fields array
106 function &getFields() {
107 return $this->fields;
111 * Load data from XML to the index
112 * @param $xmlarr array
113 * @return bool
115 function arr2xmldb_index($xmlarr) {
117 $result = true;
119 // Debug the table
120 // traverse_xmlize($xmlarr); //Debug
121 // print_object ($GLOBALS['traverse_array']); //Debug
122 // $GLOBALS['traverse_array']=""; //Debug
124 // Process key attributes (name, unique, fields, comment, previous, next)
125 if (isset($xmlarr['@']['NAME'])) {
126 $this->name = trim($xmlarr['@']['NAME']);
127 } else {
128 $this->errormsg = 'Missing NAME attribute';
129 $this->debug($this->errormsg);
130 $result = false;
133 if (isset($xmlarr['@']['UNIQUE'])) {
134 $unique = strtolower(trim($xmlarr['@']['UNIQUE']));
135 if ($unique == 'true') {
136 $this->unique = true;
137 } else if ($unique == 'false') {
138 $this->unique = false;
139 } else {
140 $this->errormsg = 'Incorrect UNIQUE attribute (true/false allowed)';
141 $this->debug($this->errormsg);
142 $result = false;
144 } else {
145 $this->errormsg = 'Undefined UNIQUE attribute';
146 $this->debug($this->errormsg);
147 $result = false;
150 if (isset($xmlarr['@']['FIELDS'])) {
151 $fields = strtolower(trim($xmlarr['@']['FIELDS']));
152 if ($fields) {
153 $fieldsarr = explode(',',$fields);
154 if ($fieldsarr) {
155 foreach ($fieldsarr as $key => $element) {
156 $fieldsarr [$key] = trim($element);
158 } else {
159 $this->errormsg = 'Incorrect FIELDS attribute (comma separated of fields)';
160 $this->debug($this->errormsg);
161 $result = false;
163 } else {
164 $this->errormsg = 'Empty FIELDS attribute';
165 $this->debug($this->errormsg);
166 $result = false;
168 } else {
169 $this->errormsg = 'Missing FIELDS attribute';
170 $this->debug($this->errormsg);
171 $result = false;
173 // Finally, set the array of fields
174 $this->fields = $fieldsarr;
176 if (isset($xmlarr['@']['COMMENT'])) {
177 $this->comment = trim($xmlarr['@']['COMMENT']);
180 if (isset($xmlarr['@']['PREVIOUS'])) {
181 $this->previous = trim($xmlarr['@']['PREVIOUS']);
184 if (isset($xmlarr['@']['NEXT'])) {
185 $this->next = trim($xmlarr['@']['NEXT']);
188 // Set some attributes
189 if ($result) {
190 $this->loaded = true;
192 $this->calculateHash();
193 return $result;
197 * This function calculate and set the hash of one xmldb_index
198 * @retur nvoid, changes $this->hash
200 function calculateHash($recursive = false) {
201 if (!$this->loaded) {
202 $this->hash = NULL;
203 } else {
204 $key = $this->unique . implode (', ', $this->fields);
205 $this->hash = md5($key);
210 *This function will output the XML text for one index
211 * @return string
213 function xmlOutput() {
214 $o = '';
215 $o.= ' <INDEX NAME="' . $this->name . '"';
216 if ($this->unique) {
217 $unique = 'true';
218 } else {
219 $unique = 'false';
221 $o.= ' UNIQUE="' . $unique . '"';
222 $o.= ' FIELDS="' . implode(', ', $this->fields) . '"';
223 if ($this->comment) {
224 $o.= ' COMMENT="' . htmlspecialchars($this->comment) . '"';
226 if ($this->previous) {
227 $o.= ' PREVIOUS="' . $this->previous . '"';
229 if ($this->next) {
230 $o.= ' NEXT="' . $this->next . '"';
232 $o.= '/>' . "\n";
234 return $o;
238 * This function will set all the attributes of the xmldb_index object
239 * based on information passed in one ADOindex
240 * @param array
241 * @return void
243 function setFromADOIndex($adoindex) {
245 // Set the unique field
246 $this->unique = false;
247 // Set the fields, converting all them to lowercase
248 $fields = array_flip(array_change_key_case(array_flip($adoindex['columns'])));
249 $this->fields = $fields;
250 // Some more fields
251 $this->loaded = true;
252 $this->changed = true;
256 * Returns the PHP code needed to define one xmldb_index
257 * @return string
259 function getPHP() {
261 $result = '';
263 // The type
264 $unique = $this->getUnique();
265 if (!empty($unique)) {
266 $result .= 'XMLDB_INDEX_UNIQUE, ';
267 } else {
268 $result .= 'XMLDB_INDEX_NOTUNIQUE, ';
270 // The fields
271 $indexfields = $this->getFields();
272 if (!empty($indexfields)) {
273 $result .= 'array(' . "'". implode("', '", $indexfields) . "')";
274 } else {
275 $result .= 'null';
277 // Return result
278 return $result;
282 * Shows info in a readable format
283 * @return string
285 function readableInfo() {
286 $o = '';
287 // unique
288 if ($this->unique) {
289 $o .= 'unique';
290 } else {
291 $o .= 'not unique';
293 // fields
294 $o .= ' (' . implode(', ', $this->fields) . ')';
296 return $o;
300 * Validates the index restrictions.
302 * The error message should not be localised because it is intended for developers,
303 * end users and admins should never see these problems!
305 * @param xmldb_table $xmldb_table optional when object is table
306 * @return string null if ok, error message if problem found
308 function validateDefinition(xmldb_table $xmldb_table=null) {
309 if (!$xmldb_table) {
310 return 'Invalid xmldb_index->validateDefinition() call, $xmldb_table si required.';
313 $total = 0;
314 foreach ($this->getFields() as $fieldname) {
315 if (!$field = $xmldb_table->getField($fieldname)) {
316 // argh, we do not have the fields loaded yet, this should not happen during install
317 continue;
320 switch ($field->getType()) {
321 case XMLDB_TYPE_INTEGER:
322 $total += 8; // big int
323 break;
325 case XMLDB_TYPE_NUMBER:
326 $total += 12; // this is just a guess
327 break;
329 case XMLDB_TYPE_FLOAT:
330 $total += 8; // double precision
331 break;
333 case XMLDB_TYPE_CHAR:
334 if ($field->getLength() > self::INDEX_MAX_BYTES / 3) {
335 return 'Invalid index definition in table {'.$xmldb_table->getName(). '}: XMLDB_TYPE_CHAR field "'.$field->getName().'" can not be indexed because it is too long.'
336 .' Limit is '.(self::INDEX_MAX_BYTES/3).' chars.';
338 $total += ($field->getLength() * 3); // the most complex utf-8 chars have 3 bytes
339 break;
341 case XMLDB_TYPE_TEXT:
342 return 'Invalid index definition in table {'.$xmldb_table->getName(). '}: XMLDB_TYPE_TEXT field "'.$field->getName().'" can not be indexed';
343 break;
345 case XMLDB_TYPE_BINARY:
346 return 'Invalid index definition in table {'.$xmldb_table->getName(). '}: XMLDB_TYPE_BINARY field "'.$field->getName().'" can not be indexed';
347 break;
349 case XMLDB_TYPE_DATETIME:
350 $total += 8; // this is just a guess
351 break;
353 case XMLDB_TYPE_TIMESTAMP:
354 $total += 8; // this is just a guess
355 break;
359 if ($total > self::INDEX_COMPOSED_MAX_BYTES) {
360 return 'Invalid index definition in table {'.$xmldb_table->getName(). '}: the composed index on fields "'.implode(',', $this->getFields()).'" is too long.'
361 .' Limit is '.self::INDEX_COMPOSED_MAX_BYTES.' bytes / '.(self::INDEX_COMPOSED_MAX_BYTES/3).' chars.';
364 return null;