[ Index ]

PHP Cross Reference of Drupal 6 (yi-drupal)

title

Body

[close]

/sites/all/modules/data/includes/ -> DataTable.inc (source)

   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  }


Generated: Mon Jul 9 18:01:44 2012 Cross-referenced by PHPXref 0.7