DataTable.inc

Contains class definition for DataTable.

Classes

Namesort descending Description
DataTable Manages data access and manipulation for a single data table. Use data_create_table() or data_get_table() to instantiate an object from this class.

File

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

Error

×

Error message

  • Warning: Cannot modify header information - headers already sent by (output started at /var/www/html/elmsln_community/api.elmsln.org/includes/common.inc:2791) in drupal_send_headers() (line 1499 of /var/www/html/elmsln_community/api.elmsln.org/includes/bootstrap.inc).
  • Error: Call to undefined function apc_delete() in DrupalAPCCache->clear() (line 289 of /var/www/html/elmsln_community/api.elmsln.org/sites/all/modules/apc/drupal_apc_cache.inc).
The website encountered an unexpected error. Please try again later.