]> git.mxchange.org Git - quix0rs-gnu-social.git/blobdiff - lib/schema.php
hooks for commands
[quix0rs-gnu-social.git] / lib / schema.php
index 8c8f5e9ff514c5f07cf2487ce69f1b3a1a331634..e5def514e31ddbc227ecb2a6afaec272c9c5d2dc 100644 (file)
@@ -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
 }
+