| [ Index ] |
PHP Cross Reference of Drupal 6 (yi-drupal) |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * @file 4 * Contains class definition for DataTable. 5 */ 6 7 /** 8 * Manages data access and manipulation for a single data table. 9 * Use data_create_table() or data_get_table() to instantiate an object from this class. 10 * 11 * @see data_create_table(). 12 * @see data_get_table(). 13 * 14 * Usage: 15 * 16 * Get an existing table. 17 * 18 * $table = data_get_table('my_table'); 19 * 20 * If the table does not exist, create one. 21 * if (!$table) { 22 * $table = data_create_table('my_table', $schema); 23 * } 24 * 25 * Save some data to it. 26 * $handler = data_get_handler($table->get('name')); 27 * $handler->save($data); 28 * 29 * Remove the data from the table. 30 * $handler->truncate(); 31 * 32 * Remove the table, but not the meta information about the table. 33 * $table->drop(); 34 * 35 */ 36 class DataTable { 37 38 // Class variables. 39 // @todo: change $table_schema to $schema. 40 // @todo: change $name to $id. 41 // Unfortunately drupal_write_record does not escape field names. $table_schema instead of $schema it is. 42 protected $name, $title, $table_schema, $meta, $export_type; 43 44 /** 45 * Instiate a DataTable object. Use this function instead of new DataTable. 46 */ 47 public static function instance($name) { 48 static $tables; 49 if (!isset($tables[$name])) { 50 $tables[$name] = new DataTable($name); 51 } 52 return $tables[$name]; 53 } 54 55 /** 56 * Constructor. Do not call directly, but use DataTable::instance($name) instead. 57 */ 58 protected function __construct($name) { 59 $this->name = $name; 60 61 // Try to load table information. 62 if ($table = _data_load_table($name)) { 63 foreach (array('title', 'name', 'table_schema', 'meta', 'export_type') as $key) { 64 if (isset($table->$key)) { 65 $this->$key = $table->$key; 66 } 67 } 68 } 69 } 70 71 /** 72 * Create a table. 73 * 74 * Do not call directly but use data_create_table() instead. 75 */ 76 public function create($table_schema) { 77 78 // Only create the table if it is not defined as data table AND it does not 79 // physically exist. 80 if (!_data_load_table($this->name, TRUE) && !db_table_exists($this->name)) { 81 82 // Create table. 83 db_create_table($ret, $this->name, $table_schema); 84 if ($ret[0]['success'] != 1) { 85 drupal_set_message(t('Error creating table.'), 'error'); 86 return FALSE; 87 } 88 89 // If schema module is enabled, inspect and read back to make 90 // sure our schema information is up to date. 91 // @todo: this is slow, maybe we need to make this an explicit method 92 // on DataTable. 93 if (module_exists('schema')) { 94 $schema = schema_invoke('inspect'); 95 if (isset($schema[$this->name])) { 96 $table_schema = $schema[$this->name]; 97 } 98 } 99 100 // Set table_schema and export_type. 101 // @todo: rather user _data_table_load() ? 102 $this->table_schema = $table_schema; 103 $this->export_type = EXPORT_IN_DATABASE; 104 105 // Save table information. 106 // Set export_type - needs to be defined so that schema information is being passed on 107 // to Drupal by data_schema_alter(). 108 // @todo: refactor ->update() to ->save() and use ->save(). 109 $table = array( 110 'name' => $this->name, 111 'table_schema' => $this->table_schema, 112 ); 113 drupal_write_record('data_tables', $table); 114 115 // Clear caches. 116 drupal_get_schema($this->name, TRUE); 117 118 // Have views read new views information about table. 119 if (module_exists('views')) { 120 views_invalidate_cache(); 121 } 122 123 // data ui exposes path to a new default view. 124 if (module_exists('data_ui')) { 125 menu_rebuild(); 126 } 127 128 return TRUE; 129 } 130 return FALSE; 131 } 132 133 /** 134 * Let Data manage a table that already exists in the database. 135 * 136 * Uses the $name property of the object to determine which database table to 137 * adopt. 138 * 139 * @return 140 * TRUE if the table was successfully adopted; FALSE if the table was 141 * already known to Data, if the query failed, or if Schema isn't available. 142 */ 143 public function adopt() { 144 if ($this->defined() || !module_exists('schema')) { 145 return FALSE; 146 } 147 148 $schema = schema_invoke('inspect', $this->name); 149 if (isset($schema[$this->name])) { 150 $table = array( 151 'name' => $this->name, 152 'title' => data_natural_name($this->name), 153 'table_schema' => $schema[$this->name], 154 ); 155 if (drupal_write_record('data_tables', $table)) { 156 return TRUE; 157 } 158 } 159 160 return FALSE; 161 } 162 163 /** 164 * Determine whether a table is defined. 165 * 166 * @return 167 * TRUE if the table is defined, FALSE otherwise. 168 * Note: If a table is defined it does not mean that it actually exists in the 169 * database. 170 */ 171 public function defined() { 172 return _data_load_table($this->name) ? TRUE : FALSE; 173 } 174 175 /** 176 * Get a property of the DataTable object. 177 * 178 * @todo: use __get() 179 * 180 * @param $property 181 * One of 'name', 'title', 'table_schema', 'meta'. 182 * @return 183 * The unserialized value of the property. 184 */ 185 public function get($property) { 186 if (in_array($property, array('name', 'title', 'table_schema', 'meta', 'export_type'))) { 187 return $this->$property; 188 } 189 } 190 191 /** 192 * Update table properties. 193 * 194 * @todo: make conditional, rename to save(). 195 * 196 * @param $properties 197 * Array where the key designates a property (one of 'name', 'title', 'table_schema', 'meta') 198 * and the value is the unserialized value that this property should attain. 199 */ 200 public function update($properties) { 201 _data_override($this->name); 202 $properties['name'] = $this->name; 203 if (drupal_write_record('data_tables', $properties, 'name')) { 204 foreach ($properties as $key => $value) { 205 $this->$key = $value; 206 } 207 } 208 } 209 210 /** 211 * Compare this table's schema to schema of table in DB. 212 * Requires schema module. 213 * 214 * @return 215 * 216 */ 217 public function compareSchema() { 218 if (module_exists('schema')) { 219 $this->table_schema['name'] = $this->name; 220 return schema_compare_table($this->table_schema); 221 } 222 } 223 224 /** 225 * Add a field. 226 * 227 * @throws DataException 228 * 229 * @todo: Check wether field name is available, otherwise change. 230 */ 231 public function addField($field, $spec) { 232 233 $ret = array(); 234 db_add_field($ret, $this->name, $field, $spec); 235 236 if ($ret[0]['success']) { 237 $schema = $this->table_schema; 238 $schema['fields'][$field] = $spec; 239 $this->update(array('table_schema' => $schema)); 240 241 // @todo: use clearCaches(). 242 drupal_get_schema($this->name, TRUE); 243 // Invalidate views caches to use new field immediately. 244 if (function_exists('views_invalidate_cache')) { 245 views_invalidate_cache(); 246 } 247 return $field; 248 } 249 throw new DataException(t('Error adding field.')); 250 } 251 252 /** 253 * Add an index to table. 254 * 255 * @todo: support more than one field. 256 */ 257 public function addIndex($field) { 258 $schema = $this->table_schema; 259 if ($schema['fields'][$field]) { 260 $index = data_get_index_definition($field, $schema['fields'][$field]); 261 db_add_index($ret, $this->name, $field, $index); 262 if ($ret[0]['success']) { 263 $schema['indexes'][$field] = $index; 264 $this->update(array('table_schema' => $schema)); 265 drupal_get_schema($this->name, TRUE); 266 return; 267 } 268 } 269 throw new DataException(t('Error adding index.')); 270 } 271 272 /** 273 * Drop an index from a table. 274 * 275 * @throws DataException 276 */ 277 public function dropIndex($field) { 278 $ret = array(); 279 db_drop_index($ret, $this->name, $field); 280 if ($ret[0]['success']) { 281 $schema = $this->table_schema; 282 unset($schema['indexes'][$field]); 283 $this->update(array('table_schema' => $schema)); 284 drupal_get_schema($this->name, TRUE); 285 return; 286 } 287 throw new DataException(t('Error dropping index.')); 288 } 289 290 /** 291 * Add a unique key to a field. 292 * 293 * @throws DataException 294 */ 295 public function addUniqueKey($field) { 296 $schema = $this->table_schema; 297 if ($schema['fields'][$field]) { 298 $ret = array(); 299 $index = data_get_index_definition($field, $schema['fields'][$field]); 300 db_add_unique_key($ret, $this->name, $field, $index); 301 if ($ret[0]['success']) { 302 $schema['unique keys'][$field] = array($field); 303 $this->update(array('table_schema' => $schema)); 304 drupal_get_schema($this->name, TRUE); 305 return; 306 } 307 } 308 throw new DataException(t('Error adding unique key.')); 309 } 310 311 /** 312 * Drop a unique key from a table. 313 * 314 * @throws DataException 315 */ 316 public function dropUniqueKey($field) { 317 $ret = array(); 318 db_drop_unique_key($ret, $this->name, $field); 319 if ($ret[0]['success']) { 320 $schema = $this->table_schema; 321 unset($schema['unique keys'][$field]); 322 $this->update(array('table_schema' => $schema)); 323 drupal_get_schema($this->name, TRUE); 324 return; 325 } 326 throw new DataException(t('Error dropping unique key.')); 327 } 328 329 /** 330 * Change indexes of a table. 331 * 332 * @throws DataException 333 */ 334 public function changeIndex($fields) { 335 $schema = $this->table_schema; 336 337 // @TODO: This array_keys() reduces indexes to single field indexes. 338 // Will need adjustment when multi-field indexes are implemented. 339 $indexes = isset($schema['indexes']) ? array_keys($schema['indexes']) : array(); 340 341 $add = array_diff($fields, $indexes); 342 $drop = array_diff($indexes, $fields); 343 344 foreach ($add as $field) { 345 $this->addIndex($field); 346 } 347 foreach ($drop as $field) { 348 $this->dropIndex($field); 349 } 350 } 351 352 /** 353 * Add a primary key to table. 354 * 355 * @throws DataException 356 */ 357 public function addPrimaryKey($fields) { 358 $ret = array(); 359 $schema = $this->table_schema; 360 foreach ($fields as $field) { 361 if ($schema['fields'][$field]['type'] == 'text') { 362 throw new DataException(t('A text field cannot be made a primary key.')); 363 } 364 } 365 db_add_primary_key($ret, $this->name, $fields); 366 if ($ret[0]['success']) { 367 $schema['primary key'] = $fields; 368 $this->update(array('table_schema' => $schema)); 369 drupal_get_schema($this->name, TRUE); 370 return; 371 } 372 throw new DataException(t('Error creating primary key.')); 373 } 374 375 /** 376 * Drop all primary keys from a table. 377 * 378 * @throws DataException 379 */ 380 public function dropPrimaryKey() { 381 $ret = array(); 382 db_drop_primary_key($ret, $this->name); 383 if ($ret[0]['success']) { 384 $schema = $this->table_schema; 385 $schema['primary key'] = array(); 386 $this->update(array('table_schema' => $schema)); 387 drupal_get_schema($this->name, TRUE); 388 return; 389 } 390 throw new DataException(t('Error dropping primary key.')); 391 } 392 393 /** 394 * Change the primary keys of a table. 395 * 396 * @throws DataException 397 */ 398 public function changePrimaryKey($fields) { 399 $schema = $this->table_schema; 400 if (!empty($schema['primary key'])) { 401 $this->dropPrimaryKey(); 402 } 403 if (!empty($fields)) { 404 $this->addPrimaryKey($fields); 405 } 406 } 407 408 /** 409 * Change a field. 410 * 411 * @throws DataException 412 */ 413 public function changeField($field, $spec) { 414 $ret = array(); 415 // If new type is text, check for PK and index restrictions. 416 if ($spec['type'] == 'text') { 417 if (in_array($field, $this->table_schema['primary key'])) { 418 throw new DataException(t('Cannot make a primary key field a text field.')); 419 } 420 foreach ($this->table_schema['indexes'] as $index_name => $index) { 421 foreach ($index as $index_field) { 422 if (is_array($index_field)) { 423 $index_field = array_shift($index_field); 424 } 425 if ($field == $index_field) { 426 $this->dropIndex($index_field); 427 } 428 } 429 } 430 } 431 db_change_field($ret, $this->name, $field, $field, $spec); 432 if ($ret[0]['success']) { 433 $schema = $this->table_schema; 434 $schema['fields'][$field] = $spec; 435 $this->update(array('table_schema' => $schema)); 436 drupal_get_schema($this->name, TRUE); 437 return; 438 } 439 throw new DataException(t('Cannot change field.')); 440 } 441 442 /** 443 * Delete a field. 444 * 445 * @throws DataException 446 */ 447 public function dropField($field) { 448 $ret = array(); 449 db_drop_field($ret, $this->name, $field); 450 451 if ($ret[0]['success']) { 452 $schema = $this->table_schema; 453 unset($schema['fields'][$field]); 454 $meta = $this->meta; 455 unset($meta['fields'][$field]); 456 $this->update(array('table_schema' => $schema), array('meta' => $meta)); 457 drupal_get_schema($this->name, TRUE); 458 return; 459 } 460 throw new DataException(t('Cannot drop field.')); 461 } 462 463 /** 464 * Drop a table. Does not drop a table if its defined in code. 465 * 466 * @return 467 * TRUE if the table was dropped, FALSE otherwise. 468 */ 469 public function drop() { 470 if ($this->export_type == EXPORT_IN_DATABASE) { 471 if (db_table_exists($this->name)) { 472 db_drop_table($ret, $this->name); 473 } 474 $this->update(array('table_schema' => array())); 475 drupal_get_schema($this->name, TRUE); 476 477 db_query('DELETE FROM {data_tables} WHERE name = "%s"', $this->name); 478 $this->title = ''; 479 $this->table_schema = $this->meta = array(); 480 return TRUE; 481 } 482 return FALSE; 483 } 484 485 /** 486 * Revert a table to its definition in code. 487 * 488 * Does not revert a table if it is not defined in code. 489 * 490 * @return 491 * TRUE if the table was reverted, FALSE otherwise. 492 */ 493 public function revert() { 494 if ($this->export_type & EXPORT_IN_CODE) { 495 db_query('DELETE FROM {data_tables} WHERE name = "%s"', $this->name); 496 return TRUE; 497 } 498 return FALSE; 499 } 500 501 /** 502 * Link this table to another table. Linking a table to another one is 503 * to define how data in these tables should be joined to each other. 504 * 505 * There can be more than one link to the left of a table. However, 506 * for views integration, only the first join created will be used. 507 * 508 * @todo: Get rid of link() language, use setJoin()/removeJoin() instead. 509 */ 510 public function link($left_table, $left_field, $field = NULL, $inner_join = TRUE) { 511 if ($field == NULL) { 512 $field = $left_table; 513 } 514 $this->meta['join'][$left_table] = array( 515 'left_field' => $left_field, 516 'field' => $field, 517 'inner_join' => $inner_join, 518 ); 519 $this->update(array('meta' => $this->meta)); 520 } 521 522 /** 523 * Unlink this table from another table. 524 */ 525 public function unlink($left_table) { 526 unset($this->meta['join'][$left_table]); 527 $this->update(array('meta' => $this->meta)); 528 } 529 530 /** 531 * Convenience method. 532 */ 533 public function handler() { 534 return data_get_handler($this->name); 535 } 536 537 /** 538 * Clear relevant caches. Call after operations that create, delete or modify 539 * tables. 540 */ 541 public static function clearCaches() { 542 // Clear the schema cache. 543 drupal_get_schema(NULL, TRUE); 544 // Have views read new views information about table. 545 if (module_exists('views')) { 546 views_invalidate_cache(); 547 } 548 // data ui exposes path to a new default view. 549 if (module_exists('data_ui')) { 550 menu_rebuild(); 551 } 552 } 553 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated: Mon Jul 9 18:01:44 2012 | Cross-referenced by PHPXref 0.7 |