X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=lib%2Fschema.php;h=e5def514e31ddbc227ecb2a6afaec272c9c5d2dc;hb=119d0f7dbab40f30170ba263de78d7e9cea984db;hp=8c8f5e9ff514c5f07cf2487ce69f1b3a1a331634;hpb=544c58d263e61e2eda3b2c54a4f0a1a6bbfa4910;p=quix0rs-gnu-social.git diff --git a/lib/schema.php b/lib/schema.php index 8c8f5e9ff5..e5def514e3 100644 --- a/lib/schema.php +++ b/lib/schema.php @@ -47,67 +47,61 @@ if (!defined('STATUSNET')) { class Schema { - static $_single = null; + static $_static = null; protected $conn = null; - protected function __construct() - { - // XXX: there should be an easier way to do this. - $user = new User(); - $this->conn = $user->getDatabaseConnection(); - $user->free(); - unset($user); - } + /** + * Constructor. Only run once for singleton object. + */ - static function get() + protected function __construct($conn = null) { - if (empty(self::$_single)) { - self::$_single = new Schema(); + if (is_null($conn)) { + // XXX: there should be an easier way to do this. + $user = new User(); + $conn = $user->getDatabaseConnection(); + $user->free(); + unset($user); } - return self::$_single; + + $this->conn = $conn; } - public function getTableDef($name) - { - $res =& $this->conn->query('DESCRIBE ' . $name); + /** + * Main public entry point. Use this to get + * the schema object. + * + * @return Schema the Schema object for the connection + */ - if (PEAR::isError($res)) { - throw new Exception($res->getMessage()); + static function get($conn = null) + { + if (is_null($conn)) { + $key = 'default'; + } else { + $key = md5(serialize($conn->dsn)); } - - $td = new TableDef(); - - $td->name = $name; - $td->columns = array(); - - $row = array(); - - while ($res->fetchInto($row, DB_FETCHMODE_ASSOC)) { - - $cd = new ColumnDef(); - - $cd->name = $row['Field']; - - $packed = $row['Type']; - - if (preg_match('/^(\w+)\((\d+)\)$/', $packed, $match)) { - $cd->type = $match[1]; - $cd->size = $match[2]; - } else { - $cd->type = $packed; - } - - $cd->nullable = ($row['Null'] == 'YES') ? true : false; - $cd->key = $row['Key']; - $cd->default = $row['Default']; - $cd->extra = $row['Extra']; - - $td->columns[] = $cd; + + $type = common_config('db', 'type'); + if (empty(self::$_static[$key])) { + $schemaClass = ucfirst($type).'Schema'; + self::$_static[$key] = new $schemaClass($conn); } - - return $td; + return self::$_static[$key]; } + /** + * Gets a ColumnDef object for a single column. + * + * Throws an exception if the table is not found. + * + * @param string $table name of the table + * @param string $column name of the column + * + * @return ColumnDef definition of the column or null + * if not found. + */ + public function getColumnDef($table, $column) { $td = $this->getTableDef($table); @@ -121,12 +115,17 @@ class Schema return null; } - public function getIndexDef($table, $index) - { - return null; - } - - public function createTable($name, $columns, $indices=null) + /** + * Creates a table with the given names and columns. + * + * @param string $name Name of the table + * @param array $columns Array of ColumnDef objects + * for new table. + * + * @return boolean success flag + */ + + public function createTable($name, $columns) { $uniques = array(); $primary = array(); @@ -145,13 +144,13 @@ class Schema $sql .= $this->_columnSql($cd); switch ($cd->key) { - case 'UNI': + case 'UNI': $uniques[] = $cd->name; break; - case 'PRI': + case 'PRI': $primary[] = $cd->name; break; - case 'MUL': + case 'MUL': $indices[] = $cd->name; break; } @@ -171,9 +170,7 @@ class Schema $sql .= "); "; - common_debug($sql); - - $res =& $this->conn->query($sql); + $res = $this->conn->query($sql); if (PEAR::isError($res)) { throw new Exception($res->getMessage()); @@ -182,9 +179,19 @@ class Schema return true; } + /** + * Drops a table from the schema + * + * Throws an exception if the table is not found. + * + * @param string $name Name of the table to drop + * + * @return boolean success flag + */ + public function dropTable($name) { - $res =& $this->conn->query("DROP TABLE $name"); + $res = $this->conn->query("DROP TABLE $name"); if (PEAR::isError($res)) { throw new Exception($res->getMessage()); @@ -193,7 +200,23 @@ class Schema return true; } - public function createIndex($table, $columnNames, $name = null) + /** + * Adds an index to a table. + * + * If no name is provided, a name will be made up based + * on the table name and column names. + * + * Throws an exception on database error, esp. if the table + * does not exist. + * + * @param string $table Name of the table + * @param array $columnNames Name of columns to index + * @param string $name (Optional) name of the index + * + * @return boolean success flag + */ + + public function createIndex($table, $columnNames, $name=null) { if (!is_array($columnNames)) { $columnNames = array($columnNames); @@ -203,7 +226,9 @@ class Schema $name = "$table_".implode("_", $columnNames)."_idx"; } - $res =& $this->conn->query("ALTER TABLE $table ADD INDEX $name (".implode(",", $columnNames).")"); + $res = $this->conn->query("ALTER TABLE $table ". + "ADD INDEX $name (". + implode(",", $columnNames).")"); if (PEAR::isError($res)) { throw new Exception($res->getMessage()); @@ -212,9 +237,18 @@ class Schema return true; } + /** + * Drops a named index from a table. + * + * @param string $table name of the table the index is on. + * @param string $name name of the index + * + * @return boolean success flag + */ + public function dropIndex($table, $name) { - $res =& $this->conn->query("ALTER TABLE $table DROP INDEX $name"); + $res = $this->conn->query("ALTER TABLE $table DROP INDEX $name"); if (PEAR::isError($res)) { throw new Exception($res->getMessage()); @@ -223,11 +257,21 @@ class Schema return true; } + /** + * Adds a column to a table + * + * @param string $table name of the table + * @param ColumnDef $columndef Definition of the new + * column. + * + * @return boolean success flag + */ + public function addColumn($table, $columndef) { $sql = "ALTER TABLE $table ADD COLUMN " . $this->_columnSql($columndef); - $res =& $this->conn->query($sql); + $res = $this->conn->query($sql); if (PEAR::isError($res)) { throw new Exception($res->getMessage()); @@ -236,11 +280,23 @@ class Schema return true; } + /** + * Modifies a column in the schema. + * + * The name must match an existing column and table. + * + * @param string $table name of the table + * @param ColumnDef $columndef new definition of the column. + * + * @return boolean success flag + */ + public function modifyColumn($table, $columndef) { - $sql = "ALTER TABLE $table MODIFY COLUMN " . $this->_columnSql($columndef); + $sql = "ALTER TABLE $table MODIFY COLUMN " . + $this->_columnSql($columndef); - $res =& $this->conn->query($sql); + $res = $this->conn->query($sql); if (PEAR::isError($res)) { throw new Exception($res->getMessage()); @@ -249,11 +305,22 @@ class Schema return true; } + /** + * Drops a column from a table + * + * The name must match an existing column. + * + * @param string $table name of the table + * @param string $columnName name of the column to drop + * + * @return boolean success flag + */ + public function dropColumn($table, $columnName) { $sql = "ALTER TABLE $table DROP COLUMN $columnName"; - $res =& $this->conn->query($sql); + $res = $this->conn->query($sql); if (PEAR::isError($res)) { throw new Exception($res->getMessage()); @@ -262,7 +329,22 @@ class Schema return true; } - public function ensureTable($tableName, $columns, $indices=null) + /** + * Ensures that a table exists with the given + * name and the given column definitions. + * + * If the table does not yet exist, it will + * create the table. If it does exist, it will + * alter the table to match the column definitions. + * + * @param string $tableName name of the table + * @param array $columns array of ColumnDef + * objects for the table + * + * @return boolean success flag + */ + + public function ensureTable($tableName, $columns) { // XXX: DB engine portability -> toilet @@ -270,7 +352,7 @@ class Schema $td = $this->getTableDef($tableName); } catch (Exception $e) { if (preg_match('/no such table/', $e->getMessage())) { - return $this->createTable($tableName, $columns, $indices); + return $this->createTable($tableName, $columns); } else { throw $e; } @@ -281,10 +363,8 @@ class Schema $toadd = array_diff($new, $cur); $todrop = array_diff($cur, $new); - - $same = array_intersect($new, $cur); - - $tomod = array(); + $same = array_intersect($new, $cur); + $tomod = array(); foreach ($same as $m) { $curCol = $this->_byName($td->columns, $m); @@ -307,6 +387,7 @@ class Schema foreach ($toadd as $columnName) { $cd = $this->_byName($columns, $columnName); + $phrase[] = 'ADD COLUMN ' . $this->_columnSql($cd); } @@ -316,12 +397,13 @@ class Schema foreach ($tomod as $columnName) { $cd = $this->_byName($columns, $columnName); + $phrase[] = 'MODIFY COLUMN ' . $this->_columnSql($cd); } $sql = 'ALTER TABLE ' . $tableName . ' ' . implode(', ', $phrase); - $res =& $this->conn->query($sql); + $res = $this->conn->query($sql); if (PEAR::isError($res)) { throw new Exception($res->getMessage()); @@ -330,7 +412,16 @@ class Schema return true; } - function _names($cds) + /** + * Returns the array of names from an array of + * ColumnDef objects. + * + * @param array $cds array of ColumnDef objects + * + * @return array strings for name values + */ + + private function _names($cds) { $names = array(); @@ -341,7 +432,17 @@ class Schema return $names; } - function _byName($cds, $name) + /** + * Get a ColumnDef from an array matching + * name. + * + * @param array $cds Array of ColumnDef objects + * @param string $name Name of the column + * + * @return ColumnDef matching item or null if no match. + */ + + private function _byName($cds, $name) { foreach ($cds as $cd) { if ($cd->name == $name) { @@ -352,7 +453,19 @@ class Schema return null; } - function _columnSql($cd) + /** + * Return the proper SQL for creating or + * altering a column. + * + * Appropriate for use in CREATE TABLE or + * ALTER TABLE statements. + * + * @param ColumnDef $cd column to create + * + * @return string correct SQL for that column + */ + + private function _columnSql($cd) { $sql = "{$cd->name} "; @@ -368,78 +481,20 @@ class Schema $sql .= ($cd->nullable) ? "null " : "not null "; } - return $sql; - } -} - -class TableDef -{ - public $name; - public $columns; -} - -class ColumnDef -{ - public $name; - public $type; - public $size; - public $nullable; - public $key; - public $default; - public $extra; - - function __construct($name=null, $type=null, $size=null, - $nullable=true, $key=null, $default=null, - $extra=null) { - $this->name = strtolower($name); - $this->type = strtolower($type); - $this->size = $size+0; - $this->nullable = $nullable; - $this->key = $key; - $this->default = $default; - $this->extra = $extra; - } - - function equals($other) - { - return ($this->name == $other->name && - $this->_typeMatch($other) && - $this->_defaultMatch($other) && - $this->_nullMatch($other) && - $this->key == $other->key); - } - - function _typeMatch($other) - { - switch ($this->type) { - case 'integer': - case 'int': - return ($other->type == 'integer' || - $other->type == 'int'); - break; - default: - return ($this->type == $other->type && - $this->size == $other->size); + if (!empty($cd->auto_increment)) { + $sql .= " auto_increment "; } - } - function _defaultMatch($other) - { - return ((is_null($this->default) && is_null($other->default)) || - ($this->default == $other->default)); - } + if (!empty($cd->extra)) { + $sql .= "{$cd->extra} "; + } - function _nullMatch($other) - { - return ((!is_null($this->default) && !is_null($other->default) && - $this->default == $other->default) || - ($this->nullable == $other->nullable)); + return $sql; } } -class IndexDef +class SchemaTableMissingException extends Exception { - public $name; - public $table; - public $columns; + // no-op } +