From: Jan Schneider Date: Mon, 7 Sep 2009 08:25:15 +0000 (+0200) Subject: Abstract -> Base X-Git-Url: https://git.internetallee.de/?a=commitdiff_plain;h=5950629d8f5cd7784c57609509449b176f73aa0a;p=horde.git Abstract -> Base --- diff --git a/framework/Db/lib/Horde/Db/Adapter/Abstract/Column.php b/framework/Db/lib/Horde/Db/Adapter/Abstract/Column.php deleted file mode 100644 index 4536f3034..000000000 --- a/framework/Db/lib/Horde/Db/Adapter/Abstract/Column.php +++ /dev/null @@ -1,359 +0,0 @@ - - * @author Derek DeVries - * @author Chuck Hagenbuch - * @license http://opensource.org/licenses/bsd-license.php - * @category Horde - * @package Horde_Db - * @subpackage Adapter - */ - -/** - * @author Mike Naberezny - * @author Derek DeVries - * @author Chuck Hagenbuch - * @license http://opensource.org/licenses/bsd-license.php - * @category Horde - * @package Horde_Db - * @subpackage Adapter - */ -class Horde_Db_Adapter_Abstract_Column -{ - protected $_name; - protected $_type; - protected $_null; - protected $_limit; - protected $_precision; - protected $_scale; - protected $_default; - protected $_sqlType; - protected $_isText; - protected $_isNumber; - - - /*########################################################################## - # Construct/Destruct - ##########################################################################*/ - - /** - * Construct - * - * @param string $name The column's name, such as supplier_id in supplier_id int(11). - * @param string $default The type-casted default value, such as +new+ in sales_stage varchar(20) default 'new'. - * @param string $sqlType Only used to extract the column's length, if necessary. For example +60+ in company_name varchar(60). - * @param boolean $null Determines if this column allows +NULL+ values. - */ - public function __construct($name, $default, $sqlType = null, $null = true) - { - $this->_name = $name; - $this->_sqlType = $sqlType; - $this->_null = $null; - $this->_limit = $this->_extractLimit($sqlType); - $this->_precision = $this->_extractPrecision($sqlType); - $this->_scale = $this->_extractScale($sqlType); - $this->_type = $this->_simplifiedType($sqlType); - $this->_default = $this->extractDefault($default); - - $this->_isText = $this->_type == 'text' || $this->_type == 'string'; - $this->_isNumber = $this->_type == 'float' || $this->_type == 'integer' || $this->_type == 'decimal'; - } - - /** - * @return boolean - */ - public function isText() - { - return $this->_isText; - } - - /** - * @return boolean - */ - public function isNumber() - { - return $this->_isNumber; - } - - /** - * Casts value (which is a String) to an appropriate instance. - */ - public function typeCast($value) - { - if ($value === null) return null; - - switch ($this->_type) { - case 'string': - case 'text': - return $value; - case 'integer': - return strlen($value) ? (int)$value : null; - case 'float': - return strlen($value) ? (float)$value : null; - case 'decimal': - return $this->valueToDecimal($value); - case 'datetime': - case 'timestamp': - return $this->stringToTime($value); - case 'time': - return $this->stringToDummyTime($value); - case 'date': - return $this->stringToDate($value); - case 'binary': - return $this->binaryToString($value); - case 'boolean': - return $this->valueToBoolean($value); - default: - return $value; - } - } - - public function extractDefault($default) - { - return $this->typeCast($default); - } - - - /*########################################################################## - # Accessor - ##########################################################################*/ - - /** - * @return string - */ - public function getName() - { - return $this->_name; - } - - /** - * @return string - */ - public function getDefault() - { - return $this->_default; - } - - /** - * @return string - */ - public function getType() - { - return $this->_type; - } - - /** - * @return int - */ - public function getLimit() - { - return $this->_limit; - } - - /** - * @return int - */ - public function precision() - { - return $this->_precision; - } - - /** - * @return int - */ - public function scale() - { - return $this->_scale; - } - - /** - * @return boolean - */ - public function isNull() - { - return $this->_null; - } - - /** - * @return string - */ - public function getSqlType() - { - return $this->_sqlType; - } - - - /*########################################################################## - # Type Juggling - ##########################################################################*/ - - /** - * Used to convert from Strings to BLOBs - * - * @return string - */ - public function stringToBinary($value) - { - return $value; - } - - /** - * Used to convert from BLOBs to Strings - * - * @return string - */ - public function binaryToString($value) - { - return $value; - } - - /** - * @param string $string - * @return Horde_Date - */ - public function stringToDate($string) - { - if (empty($string) || - // preserve '0000-00-00' (http://bugs.php.net/bug.php?id=45647) - preg_replace('/[^\d]/', '', $string) == 0) { - return null; - } - - $d = new Horde_Date($string); - $d->setDefaultFormat('Y-m-d'); - - return $d; - } - - /** - * @param string $string - * @return Horde_Date - */ - public function stringToTime($string) - { - if (empty($string) || - // preserve '0000-00-00 00:00:00' (http://bugs.php.net/bug.php?id=45647) - preg_replace('/[^\d]/', '', $string) == 0) { - return null; - } - - return new Horde_Date($string); - } - - /** - * @TODO Return a Horde_Date object instead? - * - * @param string $string - * @return Horde_Date - */ - public function stringToDummyTime($value) - { - if (empty($string)) { - return null; - } - return $this->stringToTime('2000-01-01 ' . $string); - } - - /** - * @param mixed $value - * @return boolean - */ - public function valueToBoolean($value) - { - if ($value === true || $value === false) { - return $value; - } - - $value = strtolower($value); - return $value == 'true' || $value == 't' || $value == '1'; - } - - /** - * @param mixed $value - * @return decimal - */ - public function valueToDecimal($value) - { - return (float)$value; - } - - - /*########################################################################## - # Protected - ##########################################################################*/ - - /** - * @param string $sqlType - * @return int - */ - protected function _extractLimit($sqlType) - { - if (preg_match("/\((.*)\)/", $sqlType, $matches)) { - return (int)$matches[1]; - } - return null; - } - - /** - * @param string $sqlType - * @return int - */ - protected function _extractPrecision($sqlType) - { - if (preg_match("/^(numeric|decimal|number)\((\d+)(,\d+)?\)/i", $sqlType, $matches)) { - return (int)$matches[2]; - } - return null; - } - - /** - * @param string $sqlType - * @return int - */ - protected function _extractScale($sqlType) - { - switch (true) { - case preg_match("/^(numeric|decimal|number)\((\d+)\)/i", $sqlType): - return 0; - case preg_match("/^(numeric|decimal|number)\((\d+)(,(\d+))\)/i", - $sqlType, $match): - return (int)$match[4]; - } - } - - /** - * @param string $fieldType - * @return string - */ - protected function _simplifiedType($fieldType) - { - switch (true) { - case preg_match('/int/i', $fieldType): - return 'integer'; - case preg_match('/float|double/i', $fieldType): - return 'float'; - case preg_match('/decimal|numeric|number/i', $fieldType): - return $this->_scale == 0 ? 'integer' : 'decimal'; - case preg_match('/datetime/i', $fieldType): - return 'datetime'; - case preg_match('/timestamp/i', $fieldType): - return 'timestamp'; - case preg_match('/time/i', $fieldType): - return 'time'; - case preg_match('/date/i', $fieldType): - return 'date'; - case preg_match('/clob|text/i', $fieldType): - return 'text'; - case preg_match('/blob|binary/i', $fieldType): - return 'binary'; - case preg_match('/char|string/i', $fieldType): - return 'string'; - case preg_match('/boolean/i', $fieldType): - return 'boolean'; - } - } - -} diff --git a/framework/Db/lib/Horde/Db/Adapter/Abstract/ColumnDefinition.php b/framework/Db/lib/Horde/Db/Adapter/Abstract/ColumnDefinition.php deleted file mode 100644 index f53b116bb..000000000 --- a/framework/Db/lib/Horde/Db/Adapter/Abstract/ColumnDefinition.php +++ /dev/null @@ -1,227 +0,0 @@ - - * @author Derek DeVries - * @author Chuck Hagenbuch - * @license http://opensource.org/licenses/bsd-license.php - * @category Horde - * @package Horde_Db - * @subpackage Adapter - */ - -/** - * @author Mike Naberezny - * @author Derek DeVries - * @author Chuck Hagenbuch - * @license http://opensource.org/licenses/bsd-license.php - * @category Horde - * @package Horde_Db - * @subpackage Adapter - */ -class Horde_Db_Adapter_Abstract_ColumnDefinition -{ - protected $_base = null; - protected $_name = null; - protected $_type = null; - protected $_limit = null; - protected $_precision = null; - protected $_scale = null; - protected $_default = null; - protected $_null = null; - - /** - * Construct - */ - public function __construct($base, $name, $type, $limit=null, - $precision=null, $scale=null, $default=null, $null=null) - { - // protected - $this->_base = $base; - - // public - $this->_name = $name; - $this->_type = $type; - $this->_limit = $limit; - $this->_precision = $precision; - $this->_scale = $scale; - $this->_default = $default; - $this->_null = $null; - } - - /*########################################################################## - # Public - ##########################################################################*/ - - /** - * @return string - */ - public function toSql() - { - $sql = $this->_base->quoteColumnName($this->_name).' '; - try { - $sql .= $this->_base->typeToSql($this->_type, $this->_limit, - $this->_precision, $this->_scale); - } catch (Exception $e) { - $sql .= $this->_type; - } - return $this->_addColumnOptions($sql, array('null' => $this->_null, - 'default' => $this->_default)); - } - - /** - * @return string - */ - public function __toString() - { - return $this->toSql(); - } - - - /*########################################################################## - # Accessor - ##########################################################################*/ - - /** - * @return string - */ - public function getName() - { - return $this->_name; - } - - /** - * @return string - */ - public function getDefault() - { - return $this->_default; - } - - /** - * @return string - */ - public function getType() - { - return $this->_type; - } - - /** - * @return string - */ - public function getSqlType() - { - try { - return $this->_base->typeToSql($this->_type, $this->_limit, $this->_precision, $this->_scale); - } catch (Exception $e) { - return $this->_type; - } - } - - /** - * @return int - */ - public function getLimit() - { - return $this->_limit; - } - - /** - * @return int - */ - public function precision() - { - return $this->_precision; - } - - /** - * @return int - */ - public function scale() - { - return $this->_scale; - } - - /** - * @return boolean - */ - public function isNull() - { - return $this->_null; - } - - /** - * @param string - */ - public function setName($name) - { - $this->_name = $name; - } - - /** - * @param string - */ - public function setDefault($default) - { - $this->_default = $default; - } - - /** - * @param string - */ - public function setType($type) - { - $this->_type = $type; - } - - /** - * @param int - */ - public function setLimit($limit) - { - $this->_limit = $limit; - } - - /** - * @param int - */ - public function setPrecision($precision) - { - $this->_precision = $precision; - } - - /** - * @param int - */ - public function setScale($scale) - { - $this->_scale = $scale; - } - - /** - * @param boolean - */ - public function setNull($null) - { - $this->_null = $null; - } - - - /*########################################################################## - # Schema Statements - ##########################################################################*/ - - /** - * @param string $sql - * @param array $options - */ - protected function _addColumnOptions($sql, $options) - { - return $this->_base->addColumnOptions($sql, - array_merge($options, array('column' => $this)) - ); - } - -} diff --git a/framework/Db/lib/Horde/Db/Adapter/Abstract/Index.php b/framework/Db/lib/Horde/Db/Adapter/Abstract/Index.php deleted file mode 100644 index 9407b2e8f..000000000 --- a/framework/Db/lib/Horde/Db/Adapter/Abstract/Index.php +++ /dev/null @@ -1,83 +0,0 @@ - - * @author Derek DeVries - * @author Chuck Hagenbuch - * @license http://opensource.org/licenses/bsd-license.php - * @category Horde - * @package Horde_Db - * @subpackage Adapter - */ - -/** - * @author Mike Naberezny - * @author Derek DeVries - * @author Chuck Hagenbuch - * @license http://opensource.org/licenses/bsd-license.php - * @category Horde - * @package Horde_Db - * @subpackage Adapter - */ -class Horde_Db_Adapter_Abstract_Index -{ - public $table; - public $name; - public $unique; - public $primary; - public $columns; - - - /*########################################################################## - # Construct/Destruct - ##########################################################################*/ - - /** - * Construct - * - * @param string $table The table the index is on - * @param string $name The index's name - * @param boolean $primary Is this a primary key? - * @param boolean $unique Is this a unique index? - * @param array $columns The columns this index covers - */ - public function __construct($table, $name, $primary, $unique, $columns) - { - $this->table = $table; - $this->name = $name; - $this->primary = $primary; - $this->unique = $unique; - $this->columns = $columns; - } - - - /*########################################################################## - # Accessor - ##########################################################################*/ - - /** - * @return string - */ - public function getName() - { - return $this->name; - } - - - /*########################################################################## - # Casting - ##########################################################################*/ - - /** - * Comma-separated list of the columns in the primary key - * - * @return string - */ - public function __toString() - { - return implode(',', $this->columns); - } - -} diff --git a/framework/Db/lib/Horde/Db/Adapter/Abstract/Schema.php b/framework/Db/lib/Horde/Db/Adapter/Abstract/Schema.php deleted file mode 100644 index 0bb5d5cae..000000000 --- a/framework/Db/lib/Horde/Db/Adapter/Abstract/Schema.php +++ /dev/null @@ -1,749 +0,0 @@ - - * @author Derek DeVries - * @author Chuck Hagenbuch - * @license http://opensource.org/licenses/bsd-license.php - * @category Horde - * @package Horde_Db - * @subpackage Adapter - */ - -/** - * @author Mike Naberezny - * @author Derek DeVries - * @author Chuck Hagenbuch - * @license http://opensource.org/licenses/bsd-license.php - * @category Horde - * @package Horde_Db - * @subpackage Adapter - */ -abstract class Horde_Db_Adapter_Abstract_Schema -{ - /** - * @var Cache object - */ - protected $_cache = null; - - /** - * @var Logger - */ - protected $_logger = null; - - /** - * @var Horde_Db_Adapter_Abstract - */ - protected $_adapter = null; - - /** - * @var array - */ - protected $_adapterMethods = array(); - - - /*########################################################################## - # Construct/Destruct - ##########################################################################*/ - - /** - * @param Horde_Db_Adapter_Abstract $adapter - * @param array $config - */ - public function __construct($adapter, $config = array()) - { - $this->_adapter = $adapter; - $this->_adapterMethods = array_flip(get_class_methods($adapter)); - - $this->_cache = isset($config['cache']) ? $config['cache'] : new Horde_Support_Stub; - $this->_logger = isset($config['logger']) ? $config['logger'] : new Horde_Support_Stub; - } - - - /*########################################################################## - # Object composition - ##########################################################################*/ - - /** - * Delegate calls to the adapter object. - * - * @param string $method - * @param array $args - */ - public function __call($method, $args) - { - if (isset($this->_adapterMethods[$method])) { - return call_user_func_array(array($this->_adapter, $method), $args); - } - - throw new BadMethodCallException('Call to undeclared method "'.$method.'"'); - } - - - /*########################################################################## - # Quoting - ##########################################################################*/ - - /** - * Quotes the column value to help prevent - * {SQL injection attacks}[http://en.wikipedia.org/wiki/SQL_injection]. - * - * @param string $value - * @param string $column - * @return string - */ - public function quote($value, $column=null) - { - if (is_object($value) && is_callable(array($value, 'quotedId'))) { - return $value->quotedId(); - } - - $type = isset($column) ? $column->getType() : null; - - if (is_null($value)) { - return 'NULL'; - } elseif ($value === true) { - return $type == 'integer' ? '1' : $this->quoteTrue(); - } elseif ($value === false) { - return $type == 'integer' ? '0' : $this->quoteFalse(); - } elseif (is_int($value) || is_float($value)) { - return $value; - /*@TODO - else - if value.acts_like?(:date) || value.acts_like?(:time) - "'#{quoted_date(value)}'" - else - "#{quoted_string_prefix}'#{quote_string(value.to_yaml)}'" - end - */ - } elseif ($value instanceof DateTime || $value instanceof Horde_Date) { - return $this->_adapter->quoteString($type == 'integer' - ? $value->format('U') - : $value->format('Y-m-d H:i:s')); - } else { - /*@TODO - when String, ActiveSupport::Multibyte::Chars - value = value.to_s - if column && column.type == :binary && column.class.respond_to?(:string_to_binary) - "#{quoted_string_prefix}'#{quote_string(column.class.string_to_binary(value))}'" # ' (for ruby-mode) - elsif column && [:integer, :float].include?(column.type) - value = column.type == :integer ? value.to_i : value.to_f - value.to_s - else - "#{quoted_string_prefix}'#{quote_string(value)}'" # ' (for ruby-mode) - end - */ - return $this->_adapter->quoteString($value); - } - } - - /** - * Quotes a string, escaping any ' (single quote) and \ (backslash) - * characters.. - * - * @param string $string - * @return string - */ - public function quoteString($string) - { - return "'".str_replace(array('\\', '\''), array('\\\\', '\\\''), $string)."'"; - } - - /** - * Returns a quoted form of the column name. This is highly adapter - * specific. - * - * @param string $name - * @return string - */ - abstract public function quoteColumnName($name); - - /** - * Returns a quoted form of the table name. Defaults to column name quoting. - * - * @param string $name - * @return string - */ - public function quoteTableName($name) - { - return $this->quoteColumnName($name); - } - - /** - * @return string - */ - public function quoteTrue() - { - return "'t'"; - } - - /** - * @return string - */ - public function quoteFalse() - { - return "'f'"; - } - - /** - * @return string - */ - public function quoteDate($value) - { - return $this->_adapter->quoteString((string)$value); - } - - /** - * @return string - */ - public function quotedStringPrefix() - { - return ''; - } - - - /*########################################################################## - # Schema Statements - ##########################################################################*/ - - /** - * Returns a Hash of mappings from the abstract data types to the native - * database types. See TableDefinition#column for details on the recognized - * abstract data types. - * - * @return array - */ - public function nativeDatabaseTypes() - { - return array(); - } - - /** - * This is the maximum length a table alias can be - * - * @return int - */ - public function tableAliasLength() - { - return 255; - } - - /** - * Truncates a table alias according to the limits of the current adapter. - * - * @param string $tableName - * @return string - */ - public function tableAliasFor($tableName) - { - $alias = substr($tableName, 0, $this->tableAliasLength()); - return str_replace('.', '_', $alias); - } - - /** - * @param string $name - * @return array - */ - abstract public function tables($name = null); - - /** - * Get a Horde_Db_Adapter_Abstract_Table object for the table. - * - * @param string $tableName - * @param string $name - * - * @return Horde_Db_Adapter_Abstract_Table - */ - public function table($tableName, $name = null) - { - return $this->componentFactory('Table', array( - $tableName, - $this->primaryKey($tableName), - $this->columns($tableName, $name), - $this->indexes($tableName, $name), - )); - } - - /** - * Return a table's primary key - */ - abstract public function primaryKey($tableName, $name = null); - - /** - * Returns an array of indexes for the given table. - * - * @param string $tableName - * @param string $name - * @return array - */ - abstract public function indexes($tableName, $name = null); - - /** - * Returns an array of Horde_Db_Adapter_Abstract_Column objects for the - * table specified by +table_name+. See the concrete implementation for - * details on the expected parameter values. - * - * @param string $tableName - * @param string $name - * @return array - */ - abstract public function columns($tableName, $name = null); - - /** - * Creates a new table - * There are two ways to work with #create_table. You can use the block - * form or the regular form, like this: - * - * === Block form - * # create_table() yields a TableDefinition instance - * create_table(:suppliers) do |t| - * t.column :name, :string, :limit => 60 - * # Other fields here - * end - * - * === Regular form - * create_table(:suppliers) - * add_column(:suppliers, :name, :string, {:limit => 60}) - * - * The +options+ hash can include the following keys: - * [:id] - * Set to true or false to add/not add a primary key column - * automatically. Defaults to true. - * [:primary_key] - * The name of the primary key, if one is to be added automatically. - * Defaults to +id+. - * [:options] - * Any extra options you want appended to the table definition. - * [:temporary] - * Make a temporary table. - * [:force] - * Set to true or false to drop the table before creating it. - * Defaults to false. - * - * ===== Examples - * ====== Add a backend specific option to the generated SQL (MySQL) - * create_table(:suppliers, :options => 'ENGINE=InnoDB DEFAULT CHARSET=utf8') - * generates: - * CREATE TABLE suppliers ( - * id int(11) DEFAULT NULL auto_increment PRIMARY KEY - * ) ENGINE=InnoDB DEFAULT CHARSET=utf8 - * - * ====== Rename the primary key column - * create_table(:objects, :primary_key => 'guid') do |t| - * t.column :name, :string, :limit => 80 - * end - * generates: - * CREATE TABLE objects ( - * guid int(11) DEFAULT NULL auto_increment PRIMARY KEY, - * name varchar(80) - * ) - * - * ====== Do not add a primary key column - * create_table(:categories_suppliers, :id => false) do |t| - * t.column :category_id, :integer - * t.column :supplier_id, :integer - * end - * generates: - * CREATE TABLE categories_suppliers_join ( - * category_id int, - * supplier_id int - * ) - * - * See also TableDefinition#column for details on how to create columns. - * - * @param string $name - * @param array $options - */ - public function createTable($name, $options=array()) - { - $pk = isset($options['primaryKey']) && $options['primaryKey'] === false ? false : 'id'; - $tableDefinition = - $this->componentFactory('TableDefinition', array($name, $this, $options)); - if ($pk != false) { - $tableDefinition->primaryKey($pk); - } - return $tableDefinition; - } - - /** - * Execute table creation - * - * @param string $name - * @param array $options - */ - public function endTable($name, $options=array()) - { - if ($name instanceof Horde_Db_Adapter_Abstract_TableDefinition) { - $tableDefinition = $name; - $options = array_merge($tableDefinition->getOptions(), $options); - } else { - $tableDefinition = $this->createTable($name, $options); - } - - // drop previous - if (isset($options['force'])) { - $this->dropTable($tableDefinition->getName(), $options); - } - - $temp = !empty($options['temporary']) ? 'TEMPORARY' : null; - $opts = !empty($options['options']) ? $options['options'] : null; - - $sql = "CREATE $temp TABLE ".$this->quoteTableName($tableDefinition->getName())." (\n". - $tableDefinition->toSql()."\n". - ") $opts"; - return $this->execute($sql); - } - - /** - * Renames a table. - * ===== Example - * rename_table('octopuses', 'octopi') - * - * @param string $name - * @param string $newName - */ - abstract public function renameTable($name, $newName); - - /** - * Drops a table from the database. - * - * @param string $name - */ - public function dropTable($name) - { - $this->_clearTableCache($name); - return $this->execute('DROP TABLE ' . $this->quoteTableName($name)); - } - - /** - * Adds a new column to the named table. - * See TableDefinition#column for details of the options you can use. - * - * @param string $tableName - * @param string $columnName - * @param string $type - * @param array $options - */ - public function addColumn($tableName, $columnName, $type, $options=array()) - { - $this->_clearTableCache($tableName); - - $limit = isset($options['limit']) ? $options['limit'] : null; - $precision = isset($options['precision']) ? $options['precision'] : null; - $scale = isset($options['scale']) ? $options['scale'] : null; - - $sql = 'ALTER TABLE ' . $this->quoteTableName($tableName) . - ' ADD '.$this->quoteColumnName($columnName) . - ' '.$this->typeToSql($type, $limit, $precision, $scale); - $sql = $this->addColumnOptions($sql, $options); - return $this->execute($sql); - } - - /** - * Removes the column from the table definition. - * ===== Examples - * remove_column(:suppliers, :qualification) - * - * @param string $tableName - * @param string $columnName - */ - public function removeColumn($tableName, $columnName) - { - $this->_clearTableCache($tableName); - - $sql = 'ALTER TABLE ' . $this->quoteTableName($tableName).' DROP '.$this->quoteColumnName($columnName); - return $this->execute($sql); - } - - /** - * Changes the column's definition according to the new options. - * See TableDefinition#column for details of the options you can use. - * ===== Examples - * change_column(:suppliers, :name, :string, :limit => 80) - * change_column(:accounts, :description, :text) - * - * @param string $tableName - * @param string $columnName - * @param string $type - * @param array $options - */ - abstract public function changeColumn($tableName, $columnName, $type, $options=array()); - - /** - * Sets a new default value for a column. If you want to set the default - * value to +NULL+, you are out of luck. You need to - * DatabaseStatements#execute the apppropriate SQL statement yourself. - * ===== Examples - * change_column_default(:suppliers, :qualification, 'new') - * change_column_default(:accounts, :authorized, 1) - * - * @param string $tableName - * @param string $columnName - * @param string $default - */ - abstract public function changeColumnDefault($tableName, $columnName, $default); - - /** - * Renames a column. - * ===== Example - * rename_column(:suppliers, :description, :name) - * - * @param string $tableName - * @param string $columnName - * @param string $newColumnName - */ - abstract public function renameColumn($tableName, $columnName, $newColumnName); - - /** - * Adds a new index to the table. +column_name+ can be a single Symbol, or - * an Array of Symbols. - * - * The index will be named after the table and the first column names, - * unless you pass +:name+ as an option. - * - * When creating an index on multiple columns, the first column is used as a name - * for the index. For example, when you specify an index on two columns - * [+:first+, +:last+], the DBMS creates an index for both columns as well as an - * index for the first colum +:first+. Using just the first name for this index - * makes sense, because you will never have to create a singular index with this - * name. - * - * ===== Examples - * ====== Creating a simple index - * add_index(:suppliers, :name) - * generates - * CREATE INDEX suppliers_name_index ON suppliers(name) - * - * ====== Creating a unique index - * add_index(:accounts, [:branch_id, :party_id], :unique => true) - * generates - * CREATE UNIQUE INDEX accounts_branch_id_index ON accounts(branch_id, party_id) - * - * ====== Creating a named index - * add_index(:accounts, [:branch_id, :party_id], :unique => true, :name => 'by_branch_party') - * generates - * CREATE UNIQUE INDEX by_branch_party ON accounts(branch_id, party_id) - * - * @param string $tableName - * @param string $columnName - * @param array $options - */ - public function addIndex($tableName, $columnName, $options=array()) - { - $this->_clearTableCache($tableName); - - $columnNames = (array)($columnName); - $indexName = $this->indexName($tableName, array('column' => $columnNames)); - - $indexType = !empty($options['unique']) ? "UNIQUE" : null; - $indexName = !empty($options['name']) ? $options['name'] : $indexName; - - foreach ($columnNames as $colName) { - $quotedCols[] = $this->quoteColumnName($colName); - } - $quotedColumnNames = implode(', ', $quotedCols); - $sql = "CREATE $indexType INDEX ".$this->quoteColumnName($indexName). - 'ON '.$this->quoteTableName($tableName) . " ($quotedColumnNames)"; - return $this->execute($sql); - } - - /** - * Remove the given index from the table. - * - * Remove the suppliers_name_index in the suppliers table (legacy support, use the second or third forms). - * remove_index :suppliers, :name - * Remove the index named accounts_branch_id in the accounts table. - * remove_index :accounts, :column => :branch_id - * Remove the index named by_branch_party in the accounts table. - * remove_index :accounts, :name => :by_branch_party - * - * You can remove an index on multiple columns by specifying the first column. - * add_index :accounts, [:username, :password] - * remove_index :accounts, :username - * - * @param string $tableName - * @param array $options - */ - public function removeIndex($tableName, $options=array()) - { - $this->_clearTableCache($tableName); - - $index = $this->indexName($tableName, $options); - $sql = "DROP INDEX ".$this->quoteColumnName($index).' ON ' . $this->quoteTableName($tableName); - return $this->execute($sql); - } - - /** - * Get the name of the index - * - * @param string $tableName - * @param array $options - */ - public function indexName($tableName, $options=array()) - { - if (!is_array($options)) { - $options = array('column' => $options); - } - - if (isset($options['column'])) { - $columns = (array)$options['column']; - return "index_{$tableName}_on_".implode('_and_', $columns); - - } elseif (isset($options['name'])) { - return $options['name']; - - } else { - throw new Horde_Db_Exception('You must specify the index name'); - } - } - - /** - * Returns a string of CREATE TABLE SQL statement(s) for recreating the - * entire structure of the database. - * - * @param string $table - * @return string - */ - abstract public function structureDump($table = null); - - /** - * Recreate the given db - * - * @param string $name - */ - public function recreateDatabase($name) - { - $this->dropDatabase($name); - return $this->createDatabase($name); - } - - /** - * Create the given db - * - * @param string $name - */ - abstract public function createDatabase($name); - - /** - * Drop the given db - * - * @param string $name - */ - abstract public function dropDatabase($name); - - /** - * Get the name of the current db - * - * @return string - */ - abstract public function currentDatabase(); - - /** - * Should not be called normally, but this operation is non-destructive. - * The migrations module handles this automatically. - */ - public function initializeSchemaInformation() - { - try { - $this->execute("CREATE TABLE schema_info (". - " version ".$this->typeToSql('integer'). - ")"); - return $this->execute("INSERT INTO schema_info (version) VALUES (0)"); - } catch (Exception $e) {} - } - - /** - * The sql for this column type - * - * @param string $type - * @param string $limit - */ - public function typeToSql($type, $limit=null, $precision=null, $scale=null) - { - $natives = $this->nativeDatabaseTypes(); - $native = isset($natives[$type]) ? $natives[$type] : null; - if (empty($native)) { return $type; } - - $sql = is_array($native) ? $native['name'] : $native; - if ($type == 'decimal') { - $nativePrec = isset($native['precision']) ? $native['precision'] : null; - $nativeScale = isset($native['scale']) ? $native['scale'] : null; - - $precision = !empty($precision) ? $precision : $nativePrec; - $scale = !empty($scale) ? $scale : $nativeScale; - if ($precision) { - $sql .= $scale ? "($precision, $scale)" : "($precision)"; - } - } else { - $nativeLimit = is_array($native) ? $native['limit'] : null; - if ($limit = !empty($limit) ? $limit : $nativeLimit) { - $sql .= "($limit)"; - } - } - return $sql; - } - - /** - * Add default/null options to column sql - * - * @param string $sql - * @param array $options - */ - public function addColumnOptions($sql, $options) - { - if (isset($options['null']) && $options['null'] === false) { - $sql .= ' NOT NULL'; - } - if (isset($options['default'])) { - $default = $options['default']; - $column = isset($options['column']) ? $options['column'] : null; - $sql .= ' DEFAULT '.$this->quote($default, $column); - } - return $sql; - } - - /** - * SELECT DISTINCT clause for a given set of columns and a given - * ORDER BY clause. Both PostgreSQL and Oracle override this for - * custom DISTINCT syntax. - * - * $connection->distinct("posts.id", "posts.created_at desc") - * - * @param string $columns - * @param string $orderBy - */ - public function distinct($columns, $orderBy=null) - { - return "DISTINCT $columns"; - } - - /** - * ORDER BY clause for the passed order option. - * PostgreSQL overrides this due to its stricter standards compliance. - * - * @param string $sql - * @param array $options - * @return string - */ - public function addOrderByForAssocLimiting($sql, $options) - { - return $sql.'ORDER BY '.$options['order']; - } - - - /*########################################################################## - # Protected - ##########################################################################*/ - - /** - * We need to clear cache for tables when altering them at all - */ - protected function _clearTableCache($tableName) - { - $this->_cache->set("tables/columns/$tableName", null); - $this->_cache->set("tables/indexes/$tableName", null); - } - -} diff --git a/framework/Db/lib/Horde/Db/Adapter/Abstract/Table.php b/framework/Db/lib/Horde/Db/Adapter/Abstract/Table.php deleted file mode 100644 index 177c35810..000000000 --- a/framework/Db/lib/Horde/Db/Adapter/Abstract/Table.php +++ /dev/null @@ -1,123 +0,0 @@ - - * @author Derek DeVries - * @author Chuck Hagenbuch - * @license http://opensource.org/licenses/bsd-license.php - * @category Horde - * @package Horde_Db - * @subpackage Adapter - */ - -/** - * @author Mike Naberezny - * @author Derek DeVries - * @author Chuck Hagenbuch - * @license http://opensource.org/licenses/bsd-license.php - * @category Horde - * @package Horde_Db - * @subpackage Adapter - */ -class Horde_Db_Adapter_Abstract_Table -{ - protected $_name; - protected $_primaryKey; - protected $_columns; - protected $_indexes; - - - /*########################################################################## - # Construct/Destruct - ##########################################################################*/ - - /** - * Construct - * - * @param string $name The table's name, such as supplier_id in supplier_id int(11). - */ - public function __construct($name, $primaryKey, $columns, $indexes) - { - $this->_name = $name; - $this->_primaryKey = $primaryKey; - $this->_columns = $columns; - $this->_indexes = $indexes; - } - - - /*########################################################################## - # Accessor - ##########################################################################*/ - - /** - * @return string - */ - public function getName() - { - return $this->_name; - } - - /** - * @return mixed - */ - public function getPrimaryKey() - { - return $this->_primaryKey; - } - - /** - * @return array - */ - public function getColumns() - { - return $this->_columns; - } - - /** - * @return Horde_Db_Adapter_Abstract_Column - */ - public function getColumn($column) - { - return isset($this->_columns[$column]) ? $this->_columns[$column] : null; - } - - /** - * @return array - */ - public function getColumnNames() - { - $names = array(); - foreach ($this->_columns as $column) { - $names[] = $column->getName(); - } - return $names; - } - - /** - * @return array - */ - public function getIndexes() - { - return $this->_indexes; - } - - /** - * @return array - */ - public function getIndexNames() - { - $names = array(); - foreach ($this->_indexes as $index) { - $names[] = $index->getName(); - } - return $names; - } - - - /*########################################################################## - # Protected - ##########################################################################*/ - -} diff --git a/framework/Db/lib/Horde/Db/Adapter/Abstract/TableDefinition.php b/framework/Db/lib/Horde/Db/Adapter/Abstract/TableDefinition.php deleted file mode 100644 index 0eff9fad7..000000000 --- a/framework/Db/lib/Horde/Db/Adapter/Abstract/TableDefinition.php +++ /dev/null @@ -1,235 +0,0 @@ - - * @author Derek DeVries - * @author Chuck Hagenbuch - * @license http://opensource.org/licenses/bsd-license.php - * @category Horde - * @package Horde_Db - * @subpackage Adapter - */ - -/** - * @author Mike Naberezny - * @author Derek DeVries - * @author Chuck Hagenbuch - * @license http://opensource.org/licenses/bsd-license.php - * @category Horde - * @package Horde_Db - * @subpackage Adapter - */ -class Horde_Db_Adapter_Abstract_TableDefinition implements ArrayAccess -{ - protected $_name = null; - protected $_base = null; - protected $_options = null; - protected $_columns = null; - - /** - * Class Constructor - * - * @param string $name - * @param Horde_Db_Adapter_Abstract_Schema $base - * @param array $options - */ - public function __construct($name, $base, $options=array()) - { - $this->_name = $name; - $this->_base = $base; - $this->_options = $options; - $this->_columns = array(); - } - - /** - * @return string - */ - public function getName() - { - return $this->_name; - } - - /** - * @return array - */ - public function getOptions() - { - return $this->_options; - } - - /** - * @param string $name - */ - public function primaryKey($name) - { - $natives = $this->_native(); - $this->column($name, $natives['primaryKey']); - } - - /** - * Instantiates a new column for the table. - * The +type+ parameter must be one of the following values: - * :primary_key, :string, :text, - * :integer, :float, :datetime, - * :timestamp, :time, :date, - * :binary, :boolean. - * - * Available options are (none of these exists by default): - * * :limit: - * Requests a maximum column length (:string, :text, - * :binary or :integer columns only) - * * :default: - * The column's default value. You cannot explicitely set the default - * value to +NULL+. Simply leave off this option if you want a +NULL+ - * default value. - * * :null: - * Allows or disallows +NULL+ values in the column. This option could - * have been named :null_allowed. - * - * This method returns self. - * - * ===== Examples - * # Assuming def is an instance of TableDefinition - * def.column(:granted, :boolean) - * #=> granted BOOLEAN - * - * def.column(:picture, :binary, :limit => 2.megabytes) - * #=> picture BLOB(2097152) - * - * def.column(:sales_stage, :string, :limit => 20, :default => 'new', :null => false) - * #=> sales_stage VARCHAR(20) DEFAULT 'new' NOT NULL - * - * @return TableDefinition - */ - public function column($name, $type, $options=array()) - { - if ($this[$name]) { - $column = $this[$name]; - } else { - $column = $this->_base->componentFactory('ColumnDefinition', array( - $this->_base, $name, $type)); - } - - $natives = $this->_native(); - $opt = $options; - - if (isset($opt['limit']) || isset($natives[$type])) { - $nativeLimit = isset($natives[$type]['limit']) ? $natives[$type]['limit'] : null; - $column->setLimit(isset($opt['limit']) ? $opt['limit'] : $nativeLimit); - } - - $column->setPrecision(isset($opt['precision']) ? $opt['precision'] : null); - $column->setScale(isset($opt['scale']) ? $opt['scale'] : null); - $column->setDefault(isset($opt['default']) ? $opt['default'] : null); - $column->setNull(isset($opt['null']) ? $opt['null'] : null); - - $this[$name] ? $this[$name] = $column : $this->_columns[] = $column; - return $this; - } - - /** - * Wrap up table creation block & create the table - */ - public function end() - { - return $this->_base->endTable($this); - } - - /** - * Returns a String whose contents are the column definitions - * concatenated together. This string can then be pre and appended to - * to generate the final SQL to create the table. - * - * @return string - */ - public function toSql() - { - $cols = array(); - foreach ($this->_columns as $col) { $cols[] = $col->toSql(); } - - return " ".implode(", \n ", $cols); - } - - - /*########################################################################## - # ArrayAccess - ##########################################################################*/ - - /** - * ArrayAccess: Check if the given offset exists - * - * @param int $offset - * @return boolean - */ - public function offsetExists($offset) - { - foreach ($this->_columns as $column) { - if ($column->getName() == $offset) return true; - } - return false; - } - - /** - * ArrayAccess: Return the value for the given offset. - * - * @param int $offset - * @return object {@link {@Horde_Db_Adapter_Abstract_ColumnDefinition} - */ - public function offsetGet($offset) - { - if (!$this->offsetExists($offset)) { - return null; - } - - foreach ($this->_columns as $column) { - if ($column->getName() == $offset) { - return $column; - } - } - } - - /** - * ArrayAccess: Set value for given offset - * - * @param int $offset - * @param mixed $value - */ - public function offsetSet($offset, $value) - { - foreach ($this->_columns as $key=>$column) { - if ($column->getName() == $offset) { - $this->_columns[$key] = $value; - } - } - } - - /** - * ArrayAccess: remove element - * - * @param int $offset - */ - public function offsetUnset($offset) - { - foreach ($this->_columns as $key=>$column) { - if ($column->getName() == $offset) { - unset($this->_columns[$key]); - } - } - } - - - /*########################################################################## - # Protected - ##########################################################################*/ - - /** - * Get the types - */ - protected function _native() - { - return $this->_base->nativeDatabaseTypes(); - } - -} diff --git a/framework/Db/lib/Horde/Db/Adapter/Base.php b/framework/Db/lib/Horde/Db/Adapter/Base.php index bdd6f1eff..1d05a681c 100644 --- a/framework/Db/lib/Horde/Db/Adapter/Base.php +++ b/framework/Db/lib/Horde/Db/Adapter/Base.php @@ -65,7 +65,7 @@ abstract class Horde_Db_Adapter_Base protected $_logger = null; /** - * @var Horde_Db_Adapter_Abstract_Schema + * @var Horde_Db_Adapter_Base_Schema */ protected $_schema = null; @@ -154,7 +154,7 @@ abstract class Horde_Db_Adapter_Base if (class_exists($class)) { $class = new ReflectionClass($class); } else { - $class = new ReflectionClass('Horde_Db_Adapter_Abstract_' . $component); + $class = new ReflectionClass('Horde_Db_Adapter_Base_' . $component); } return $class->newInstanceArgs($args); @@ -193,7 +193,7 @@ abstract class Horde_Db_Adapter_Base */ public function adapterName() { - return 'Abstract'; + return 'Base'; } /** diff --git a/framework/Db/lib/Horde/Db/Adapter/Base/Column.php b/framework/Db/lib/Horde/Db/Adapter/Base/Column.php new file mode 100644 index 000000000..f2f0c515d --- /dev/null +++ b/framework/Db/lib/Horde/Db/Adapter/Base/Column.php @@ -0,0 +1,359 @@ + + * @author Derek DeVries + * @author Chuck Hagenbuch + * @license http://opensource.org/licenses/bsd-license.php + * @category Horde + * @package Horde_Db + * @subpackage Adapter + */ + +/** + * @author Mike Naberezny + * @author Derek DeVries + * @author Chuck Hagenbuch + * @license http://opensource.org/licenses/bsd-license.php + * @category Horde + * @package Horde_Db + * @subpackage Adapter + */ +class Horde_Db_Adapter_Base_Column +{ + protected $_name; + protected $_type; + protected $_null; + protected $_limit; + protected $_precision; + protected $_scale; + protected $_default; + protected $_sqlType; + protected $_isText; + protected $_isNumber; + + + /*########################################################################## + # Construct/Destruct + ##########################################################################*/ + + /** + * Construct + * + * @param string $name The column's name, such as supplier_id in supplier_id int(11). + * @param string $default The type-casted default value, such as +new+ in sales_stage varchar(20) default 'new'. + * @param string $sqlType Only used to extract the column's length, if necessary. For example +60+ in company_name varchar(60). + * @param boolean $null Determines if this column allows +NULL+ values. + */ + public function __construct($name, $default, $sqlType = null, $null = true) + { + $this->_name = $name; + $this->_sqlType = $sqlType; + $this->_null = $null; + $this->_limit = $this->_extractLimit($sqlType); + $this->_precision = $this->_extractPrecision($sqlType); + $this->_scale = $this->_extractScale($sqlType); + $this->_type = $this->_simplifiedType($sqlType); + $this->_default = $this->extractDefault($default); + + $this->_isText = $this->_type == 'text' || $this->_type == 'string'; + $this->_isNumber = $this->_type == 'float' || $this->_type == 'integer' || $this->_type == 'decimal'; + } + + /** + * @return boolean + */ + public function isText() + { + return $this->_isText; + } + + /** + * @return boolean + */ + public function isNumber() + { + return $this->_isNumber; + } + + /** + * Casts value (which is a String) to an appropriate instance. + */ + public function typeCast($value) + { + if ($value === null) return null; + + switch ($this->_type) { + case 'string': + case 'text': + return $value; + case 'integer': + return strlen($value) ? (int)$value : null; + case 'float': + return strlen($value) ? (float)$value : null; + case 'decimal': + return $this->valueToDecimal($value); + case 'datetime': + case 'timestamp': + return $this->stringToTime($value); + case 'time': + return $this->stringToDummyTime($value); + case 'date': + return $this->stringToDate($value); + case 'binary': + return $this->binaryToString($value); + case 'boolean': + return $this->valueToBoolean($value); + default: + return $value; + } + } + + public function extractDefault($default) + { + return $this->typeCast($default); + } + + + /*########################################################################## + # Accessor + ##########################################################################*/ + + /** + * @return string + */ + public function getName() + { + return $this->_name; + } + + /** + * @return string + */ + public function getDefault() + { + return $this->_default; + } + + /** + * @return string + */ + public function getType() + { + return $this->_type; + } + + /** + * @return int + */ + public function getLimit() + { + return $this->_limit; + } + + /** + * @return int + */ + public function precision() + { + return $this->_precision; + } + + /** + * @return int + */ + public function scale() + { + return $this->_scale; + } + + /** + * @return boolean + */ + public function isNull() + { + return $this->_null; + } + + /** + * @return string + */ + public function getSqlType() + { + return $this->_sqlType; + } + + + /*########################################################################## + # Type Juggling + ##########################################################################*/ + + /** + * Used to convert from Strings to BLOBs + * + * @return string + */ + public function stringToBinary($value) + { + return $value; + } + + /** + * Used to convert from BLOBs to Strings + * + * @return string + */ + public function binaryToString($value) + { + return $value; + } + + /** + * @param string $string + * @return Horde_Date + */ + public function stringToDate($string) + { + if (empty($string) || + // preserve '0000-00-00' (http://bugs.php.net/bug.php?id=45647) + preg_replace('/[^\d]/', '', $string) == 0) { + return null; + } + + $d = new Horde_Date($string); + $d->setDefaultFormat('Y-m-d'); + + return $d; + } + + /** + * @param string $string + * @return Horde_Date + */ + public function stringToTime($string) + { + if (empty($string) || + // preserve '0000-00-00 00:00:00' (http://bugs.php.net/bug.php?id=45647) + preg_replace('/[^\d]/', '', $string) == 0) { + return null; + } + + return new Horde_Date($string); + } + + /** + * @TODO Return a Horde_Date object instead? + * + * @param string $string + * @return Horde_Date + */ + public function stringToDummyTime($value) + { + if (empty($string)) { + return null; + } + return $this->stringToTime('2000-01-01 ' . $string); + } + + /** + * @param mixed $value + * @return boolean + */ + public function valueToBoolean($value) + { + if ($value === true || $value === false) { + return $value; + } + + $value = strtolower($value); + return $value == 'true' || $value == 't' || $value == '1'; + } + + /** + * @param mixed $value + * @return decimal + */ + public function valueToDecimal($value) + { + return (float)$value; + } + + + /*########################################################################## + # Protected + ##########################################################################*/ + + /** + * @param string $sqlType + * @return int + */ + protected function _extractLimit($sqlType) + { + if (preg_match("/\((.*)\)/", $sqlType, $matches)) { + return (int)$matches[1]; + } + return null; + } + + /** + * @param string $sqlType + * @return int + */ + protected function _extractPrecision($sqlType) + { + if (preg_match("/^(numeric|decimal|number)\((\d+)(,\d+)?\)/i", $sqlType, $matches)) { + return (int)$matches[2]; + } + return null; + } + + /** + * @param string $sqlType + * @return int + */ + protected function _extractScale($sqlType) + { + switch (true) { + case preg_match("/^(numeric|decimal|number)\((\d+)\)/i", $sqlType): + return 0; + case preg_match("/^(numeric|decimal|number)\((\d+)(,(\d+))\)/i", + $sqlType, $match): + return (int)$match[4]; + } + } + + /** + * @param string $fieldType + * @return string + */ + protected function _simplifiedType($fieldType) + { + switch (true) { + case preg_match('/int/i', $fieldType): + return 'integer'; + case preg_match('/float|double/i', $fieldType): + return 'float'; + case preg_match('/decimal|numeric|number/i', $fieldType): + return $this->_scale == 0 ? 'integer' : 'decimal'; + case preg_match('/datetime/i', $fieldType): + return 'datetime'; + case preg_match('/timestamp/i', $fieldType): + return 'timestamp'; + case preg_match('/time/i', $fieldType): + return 'time'; + case preg_match('/date/i', $fieldType): + return 'date'; + case preg_match('/clob|text/i', $fieldType): + return 'text'; + case preg_match('/blob|binary/i', $fieldType): + return 'binary'; + case preg_match('/char|string/i', $fieldType): + return 'string'; + case preg_match('/boolean/i', $fieldType): + return 'boolean'; + } + } + +} diff --git a/framework/Db/lib/Horde/Db/Adapter/Base/ColumnDefinition.php b/framework/Db/lib/Horde/Db/Adapter/Base/ColumnDefinition.php new file mode 100644 index 000000000..c8f493d07 --- /dev/null +++ b/framework/Db/lib/Horde/Db/Adapter/Base/ColumnDefinition.php @@ -0,0 +1,227 @@ + + * @author Derek DeVries + * @author Chuck Hagenbuch + * @license http://opensource.org/licenses/bsd-license.php + * @category Horde + * @package Horde_Db + * @subpackage Adapter + */ + +/** + * @author Mike Naberezny + * @author Derek DeVries + * @author Chuck Hagenbuch + * @license http://opensource.org/licenses/bsd-license.php + * @category Horde + * @package Horde_Db + * @subpackage Adapter + */ +class Horde_Db_Adapter_Base_ColumnDefinition +{ + protected $_base = null; + protected $_name = null; + protected $_type = null; + protected $_limit = null; + protected $_precision = null; + protected $_scale = null; + protected $_default = null; + protected $_null = null; + + /** + * Construct + */ + public function __construct($base, $name, $type, $limit=null, + $precision=null, $scale=null, $default=null, $null=null) + { + // protected + $this->_base = $base; + + // public + $this->_name = $name; + $this->_type = $type; + $this->_limit = $limit; + $this->_precision = $precision; + $this->_scale = $scale; + $this->_default = $default; + $this->_null = $null; + } + + /*########################################################################## + # Public + ##########################################################################*/ + + /** + * @return string + */ + public function toSql() + { + $sql = $this->_base->quoteColumnName($this->_name).' '; + try { + $sql .= $this->_base->typeToSql($this->_type, $this->_limit, + $this->_precision, $this->_scale); + } catch (Exception $e) { + $sql .= $this->_type; + } + return $this->_addColumnOptions($sql, array('null' => $this->_null, + 'default' => $this->_default)); + } + + /** + * @return string + */ + public function __toString() + { + return $this->toSql(); + } + + + /*########################################################################## + # Accessor + ##########################################################################*/ + + /** + * @return string + */ + public function getName() + { + return $this->_name; + } + + /** + * @return string + */ + public function getDefault() + { + return $this->_default; + } + + /** + * @return string + */ + public function getType() + { + return $this->_type; + } + + /** + * @return string + */ + public function getSqlType() + { + try { + return $this->_base->typeToSql($this->_type, $this->_limit, $this->_precision, $this->_scale); + } catch (Exception $e) { + return $this->_type; + } + } + + /** + * @return int + */ + public function getLimit() + { + return $this->_limit; + } + + /** + * @return int + */ + public function precision() + { + return $this->_precision; + } + + /** + * @return int + */ + public function scale() + { + return $this->_scale; + } + + /** + * @return boolean + */ + public function isNull() + { + return $this->_null; + } + + /** + * @param string + */ + public function setName($name) + { + $this->_name = $name; + } + + /** + * @param string + */ + public function setDefault($default) + { + $this->_default = $default; + } + + /** + * @param string + */ + public function setType($type) + { + $this->_type = $type; + } + + /** + * @param int + */ + public function setLimit($limit) + { + $this->_limit = $limit; + } + + /** + * @param int + */ + public function setPrecision($precision) + { + $this->_precision = $precision; + } + + /** + * @param int + */ + public function setScale($scale) + { + $this->_scale = $scale; + } + + /** + * @param boolean + */ + public function setNull($null) + { + $this->_null = $null; + } + + + /*########################################################################## + # Schema Statements + ##########################################################################*/ + + /** + * @param string $sql + * @param array $options + */ + protected function _addColumnOptions($sql, $options) + { + return $this->_base->addColumnOptions($sql, + array_merge($options, array('column' => $this)) + ); + } + +} diff --git a/framework/Db/lib/Horde/Db/Adapter/Base/Index.php b/framework/Db/lib/Horde/Db/Adapter/Base/Index.php new file mode 100644 index 000000000..0509ece56 --- /dev/null +++ b/framework/Db/lib/Horde/Db/Adapter/Base/Index.php @@ -0,0 +1,83 @@ + + * @author Derek DeVries + * @author Chuck Hagenbuch + * @license http://opensource.org/licenses/bsd-license.php + * @category Horde + * @package Horde_Db + * @subpackage Adapter + */ + +/** + * @author Mike Naberezny + * @author Derek DeVries + * @author Chuck Hagenbuch + * @license http://opensource.org/licenses/bsd-license.php + * @category Horde + * @package Horde_Db + * @subpackage Adapter + */ +class Horde_Db_Adapter_Base_Index +{ + public $table; + public $name; + public $unique; + public $primary; + public $columns; + + + /*########################################################################## + # Construct/Destruct + ##########################################################################*/ + + /** + * Construct + * + * @param string $table The table the index is on + * @param string $name The index's name + * @param boolean $primary Is this a primary key? + * @param boolean $unique Is this a unique index? + * @param array $columns The columns this index covers + */ + public function __construct($table, $name, $primary, $unique, $columns) + { + $this->table = $table; + $this->name = $name; + $this->primary = $primary; + $this->unique = $unique; + $this->columns = $columns; + } + + + /*########################################################################## + # Accessor + ##########################################################################*/ + + /** + * @return string + */ + public function getName() + { + return $this->name; + } + + + /*########################################################################## + # Casting + ##########################################################################*/ + + /** + * Comma-separated list of the columns in the primary key + * + * @return string + */ + public function __toString() + { + return implode(',', $this->columns); + } + +} diff --git a/framework/Db/lib/Horde/Db/Adapter/Base/Schema.php b/framework/Db/lib/Horde/Db/Adapter/Base/Schema.php new file mode 100644 index 000000000..7c47fc9f5 --- /dev/null +++ b/framework/Db/lib/Horde/Db/Adapter/Base/Schema.php @@ -0,0 +1,749 @@ + + * @author Derek DeVries + * @author Chuck Hagenbuch + * @license http://opensource.org/licenses/bsd-license.php + * @category Horde + * @package Horde_Db + * @subpackage Adapter + */ + +/** + * @author Mike Naberezny + * @author Derek DeVries + * @author Chuck Hagenbuch + * @license http://opensource.org/licenses/bsd-license.php + * @category Horde + * @package Horde_Db + * @subpackage Adapter + */ +abstract class Horde_Db_Adapter_Base_Schema +{ + /** + * @var Cache object + */ + protected $_cache = null; + + /** + * @var Logger + */ + protected $_logger = null; + + /** + * @var Horde_Db_Adapter_Base + */ + protected $_adapter = null; + + /** + * @var array + */ + protected $_adapterMethods = array(); + + + /*########################################################################## + # Construct/Destruct + ##########################################################################*/ + + /** + * @param Horde_Db_Adapter_Base $adapter + * @param array $config + */ + public function __construct($adapter, $config = array()) + { + $this->_adapter = $adapter; + $this->_adapterMethods = array_flip(get_class_methods($adapter)); + + $this->_cache = isset($config['cache']) ? $config['cache'] : new Horde_Support_Stub; + $this->_logger = isset($config['logger']) ? $config['logger'] : new Horde_Support_Stub; + } + + + /*########################################################################## + # Object composition + ##########################################################################*/ + + /** + * Delegate calls to the adapter object. + * + * @param string $method + * @param array $args + */ + public function __call($method, $args) + { + if (isset($this->_adapterMethods[$method])) { + return call_user_func_array(array($this->_adapter, $method), $args); + } + + throw new BadMethodCallException('Call to undeclared method "'.$method.'"'); + } + + + /*########################################################################## + # Quoting + ##########################################################################*/ + + /** + * Quotes the column value to help prevent + * {SQL injection attacks}[http://en.wikipedia.org/wiki/SQL_injection]. + * + * @param string $value + * @param string $column + * @return string + */ + public function quote($value, $column=null) + { + if (is_object($value) && is_callable(array($value, 'quotedId'))) { + return $value->quotedId(); + } + + $type = isset($column) ? $column->getType() : null; + + if (is_null($value)) { + return 'NULL'; + } elseif ($value === true) { + return $type == 'integer' ? '1' : $this->quoteTrue(); + } elseif ($value === false) { + return $type == 'integer' ? '0' : $this->quoteFalse(); + } elseif (is_int($value) || is_float($value)) { + return $value; + /*@TODO + else + if value.acts_like?(:date) || value.acts_like?(:time) + "'#{quoted_date(value)}'" + else + "#{quoted_string_prefix}'#{quote_string(value.to_yaml)}'" + end + */ + } elseif ($value instanceof DateTime || $value instanceof Horde_Date) { + return $this->_adapter->quoteString($type == 'integer' + ? $value->format('U') + : $value->format('Y-m-d H:i:s')); + } else { + /*@TODO + when String, ActiveSupport::Multibyte::Chars + value = value.to_s + if column && column.type == :binary && column.class.respond_to?(:string_to_binary) + "#{quoted_string_prefix}'#{quote_string(column.class.string_to_binary(value))}'" # ' (for ruby-mode) + elsif column && [:integer, :float].include?(column.type) + value = column.type == :integer ? value.to_i : value.to_f + value.to_s + else + "#{quoted_string_prefix}'#{quote_string(value)}'" # ' (for ruby-mode) + end + */ + return $this->_adapter->quoteString($value); + } + } + + /** + * Quotes a string, escaping any ' (single quote) and \ (backslash) + * characters.. + * + * @param string $string + * @return string + */ + public function quoteString($string) + { + return "'".str_replace(array('\\', '\''), array('\\\\', '\\\''), $string)."'"; + } + + /** + * Returns a quoted form of the column name. This is highly adapter + * specific. + * + * @param string $name + * @return string + */ + abstract public function quoteColumnName($name); + + /** + * Returns a quoted form of the table name. Defaults to column name quoting. + * + * @param string $name + * @return string + */ + public function quoteTableName($name) + { + return $this->quoteColumnName($name); + } + + /** + * @return string + */ + public function quoteTrue() + { + return "'t'"; + } + + /** + * @return string + */ + public function quoteFalse() + { + return "'f'"; + } + + /** + * @return string + */ + public function quoteDate($value) + { + return $this->_adapter->quoteString((string)$value); + } + + /** + * @return string + */ + public function quotedStringPrefix() + { + return ''; + } + + + /*########################################################################## + # Schema Statements + ##########################################################################*/ + + /** + * Returns a Hash of mappings from the abstract data types to the native + * database types. See TableDefinition#column for details on the recognized + * abstract data types. + * + * @return array + */ + public function nativeDatabaseTypes() + { + return array(); + } + + /** + * This is the maximum length a table alias can be + * + * @return int + */ + public function tableAliasLength() + { + return 255; + } + + /** + * Truncates a table alias according to the limits of the current adapter. + * + * @param string $tableName + * @return string + */ + public function tableAliasFor($tableName) + { + $alias = substr($tableName, 0, $this->tableAliasLength()); + return str_replace('.', '_', $alias); + } + + /** + * @param string $name + * @return array + */ + abstract public function tables($name = null); + + /** + * Get a Horde_Db_Adapter_Base_Table object for the table. + * + * @param string $tableName + * @param string $name + * + * @return Horde_Db_Adapter_Base_Table + */ + public function table($tableName, $name = null) + { + return $this->componentFactory('Table', array( + $tableName, + $this->primaryKey($tableName), + $this->columns($tableName, $name), + $this->indexes($tableName, $name), + )); + } + + /** + * Return a table's primary key + */ + abstract public function primaryKey($tableName, $name = null); + + /** + * Returns an array of indexes for the given table. + * + * @param string $tableName + * @param string $name + * @return array + */ + abstract public function indexes($tableName, $name = null); + + /** + * Returns an array of Horde_Db_Adapter_Base_Column objects for the + * table specified by +table_name+. See the concrete implementation for + * details on the expected parameter values. + * + * @param string $tableName + * @param string $name + * @return array + */ + abstract public function columns($tableName, $name = null); + + /** + * Creates a new table + * There are two ways to work with #create_table. You can use the block + * form or the regular form, like this: + * + * === Block form + * # create_table() yields a TableDefinition instance + * create_table(:suppliers) do |t| + * t.column :name, :string, :limit => 60 + * # Other fields here + * end + * + * === Regular form + * create_table(:suppliers) + * add_column(:suppliers, :name, :string, {:limit => 60}) + * + * The +options+ hash can include the following keys: + * [:id] + * Set to true or false to add/not add a primary key column + * automatically. Defaults to true. + * [:primary_key] + * The name of the primary key, if one is to be added automatically. + * Defaults to +id+. + * [:options] + * Any extra options you want appended to the table definition. + * [:temporary] + * Make a temporary table. + * [:force] + * Set to true or false to drop the table before creating it. + * Defaults to false. + * + * ===== Examples + * ====== Add a backend specific option to the generated SQL (MySQL) + * create_table(:suppliers, :options => 'ENGINE=InnoDB DEFAULT CHARSET=utf8') + * generates: + * CREATE TABLE suppliers ( + * id int(11) DEFAULT NULL auto_increment PRIMARY KEY + * ) ENGINE=InnoDB DEFAULT CHARSET=utf8 + * + * ====== Rename the primary key column + * create_table(:objects, :primary_key => 'guid') do |t| + * t.column :name, :string, :limit => 80 + * end + * generates: + * CREATE TABLE objects ( + * guid int(11) DEFAULT NULL auto_increment PRIMARY KEY, + * name varchar(80) + * ) + * + * ====== Do not add a primary key column + * create_table(:categories_suppliers, :id => false) do |t| + * t.column :category_id, :integer + * t.column :supplier_id, :integer + * end + * generates: + * CREATE TABLE categories_suppliers_join ( + * category_id int, + * supplier_id int + * ) + * + * See also TableDefinition#column for details on how to create columns. + * + * @param string $name + * @param array $options + */ + public function createTable($name, $options=array()) + { + $pk = isset($options['primaryKey']) && $options['primaryKey'] === false ? false : 'id'; + $tableDefinition = + $this->componentFactory('TableDefinition', array($name, $this, $options)); + if ($pk != false) { + $tableDefinition->primaryKey($pk); + } + return $tableDefinition; + } + + /** + * Execute table creation + * + * @param string $name + * @param array $options + */ + public function endTable($name, $options=array()) + { + if ($name instanceof Horde_Db_Adapter_Base_TableDefinition) { + $tableDefinition = $name; + $options = array_merge($tableDefinition->getOptions(), $options); + } else { + $tableDefinition = $this->createTable($name, $options); + } + + // drop previous + if (isset($options['force'])) { + $this->dropTable($tableDefinition->getName(), $options); + } + + $temp = !empty($options['temporary']) ? 'TEMPORARY' : null; + $opts = !empty($options['options']) ? $options['options'] : null; + + $sql = "CREATE $temp TABLE ".$this->quoteTableName($tableDefinition->getName())." (\n". + $tableDefinition->toSql()."\n". + ") $opts"; + return $this->execute($sql); + } + + /** + * Renames a table. + * ===== Example + * rename_table('octopuses', 'octopi') + * + * @param string $name + * @param string $newName + */ + abstract public function renameTable($name, $newName); + + /** + * Drops a table from the database. + * + * @param string $name + */ + public function dropTable($name) + { + $this->_clearTableCache($name); + return $this->execute('DROP TABLE ' . $this->quoteTableName($name)); + } + + /** + * Adds a new column to the named table. + * See TableDefinition#column for details of the options you can use. + * + * @param string $tableName + * @param string $columnName + * @param string $type + * @param array $options + */ + public function addColumn($tableName, $columnName, $type, $options=array()) + { + $this->_clearTableCache($tableName); + + $limit = isset($options['limit']) ? $options['limit'] : null; + $precision = isset($options['precision']) ? $options['precision'] : null; + $scale = isset($options['scale']) ? $options['scale'] : null; + + $sql = 'ALTER TABLE ' . $this->quoteTableName($tableName) . + ' ADD '.$this->quoteColumnName($columnName) . + ' '.$this->typeToSql($type, $limit, $precision, $scale); + $sql = $this->addColumnOptions($sql, $options); + return $this->execute($sql); + } + + /** + * Removes the column from the table definition. + * ===== Examples + * remove_column(:suppliers, :qualification) + * + * @param string $tableName + * @param string $columnName + */ + public function removeColumn($tableName, $columnName) + { + $this->_clearTableCache($tableName); + + $sql = 'ALTER TABLE ' . $this->quoteTableName($tableName).' DROP '.$this->quoteColumnName($columnName); + return $this->execute($sql); + } + + /** + * Changes the column's definition according to the new options. + * See TableDefinition#column for details of the options you can use. + * ===== Examples + * change_column(:suppliers, :name, :string, :limit => 80) + * change_column(:accounts, :description, :text) + * + * @param string $tableName + * @param string $columnName + * @param string $type + * @param array $options + */ + abstract public function changeColumn($tableName, $columnName, $type, $options=array()); + + /** + * Sets a new default value for a column. If you want to set the default + * value to +NULL+, you are out of luck. You need to + * DatabaseStatements#execute the apppropriate SQL statement yourself. + * ===== Examples + * change_column_default(:suppliers, :qualification, 'new') + * change_column_default(:accounts, :authorized, 1) + * + * @param string $tableName + * @param string $columnName + * @param string $default + */ + abstract public function changeColumnDefault($tableName, $columnName, $default); + + /** + * Renames a column. + * ===== Example + * rename_column(:suppliers, :description, :name) + * + * @param string $tableName + * @param string $columnName + * @param string $newColumnName + */ + abstract public function renameColumn($tableName, $columnName, $newColumnName); + + /** + * Adds a new index to the table. +column_name+ can be a single Symbol, or + * an Array of Symbols. + * + * The index will be named after the table and the first column names, + * unless you pass +:name+ as an option. + * + * When creating an index on multiple columns, the first column is used as a name + * for the index. For example, when you specify an index on two columns + * [+:first+, +:last+], the DBMS creates an index for both columns as well as an + * index for the first colum +:first+. Using just the first name for this index + * makes sense, because you will never have to create a singular index with this + * name. + * + * ===== Examples + * ====== Creating a simple index + * add_index(:suppliers, :name) + * generates + * CREATE INDEX suppliers_name_index ON suppliers(name) + * + * ====== Creating a unique index + * add_index(:accounts, [:branch_id, :party_id], :unique => true) + * generates + * CREATE UNIQUE INDEX accounts_branch_id_index ON accounts(branch_id, party_id) + * + * ====== Creating a named index + * add_index(:accounts, [:branch_id, :party_id], :unique => true, :name => 'by_branch_party') + * generates + * CREATE UNIQUE INDEX by_branch_party ON accounts(branch_id, party_id) + * + * @param string $tableName + * @param string $columnName + * @param array $options + */ + public function addIndex($tableName, $columnName, $options=array()) + { + $this->_clearTableCache($tableName); + + $columnNames = (array)($columnName); + $indexName = $this->indexName($tableName, array('column' => $columnNames)); + + $indexType = !empty($options['unique']) ? "UNIQUE" : null; + $indexName = !empty($options['name']) ? $options['name'] : $indexName; + + foreach ($columnNames as $colName) { + $quotedCols[] = $this->quoteColumnName($colName); + } + $quotedColumnNames = implode(', ', $quotedCols); + $sql = "CREATE $indexType INDEX ".$this->quoteColumnName($indexName). + 'ON '.$this->quoteTableName($tableName) . " ($quotedColumnNames)"; + return $this->execute($sql); + } + + /** + * Remove the given index from the table. + * + * Remove the suppliers_name_index in the suppliers table (legacy support, use the second or third forms). + * remove_index :suppliers, :name + * Remove the index named accounts_branch_id in the accounts table. + * remove_index :accounts, :column => :branch_id + * Remove the index named by_branch_party in the accounts table. + * remove_index :accounts, :name => :by_branch_party + * + * You can remove an index on multiple columns by specifying the first column. + * add_index :accounts, [:username, :password] + * remove_index :accounts, :username + * + * @param string $tableName + * @param array $options + */ + public function removeIndex($tableName, $options=array()) + { + $this->_clearTableCache($tableName); + + $index = $this->indexName($tableName, $options); + $sql = "DROP INDEX ".$this->quoteColumnName($index).' ON ' . $this->quoteTableName($tableName); + return $this->execute($sql); + } + + /** + * Get the name of the index + * + * @param string $tableName + * @param array $options + */ + public function indexName($tableName, $options=array()) + { + if (!is_array($options)) { + $options = array('column' => $options); + } + + if (isset($options['column'])) { + $columns = (array)$options['column']; + return "index_{$tableName}_on_".implode('_and_', $columns); + + } elseif (isset($options['name'])) { + return $options['name']; + + } else { + throw new Horde_Db_Exception('You must specify the index name'); + } + } + + /** + * Returns a string of CREATE TABLE SQL statement(s) for recreating the + * entire structure of the database. + * + * @param string $table + * @return string + */ + abstract public function structureDump($table = null); + + /** + * Recreate the given db + * + * @param string $name + */ + public function recreateDatabase($name) + { + $this->dropDatabase($name); + return $this->createDatabase($name); + } + + /** + * Create the given db + * + * @param string $name + */ + abstract public function createDatabase($name); + + /** + * Drop the given db + * + * @param string $name + */ + abstract public function dropDatabase($name); + + /** + * Get the name of the current db + * + * @return string + */ + abstract public function currentDatabase(); + + /** + * Should not be called normally, but this operation is non-destructive. + * The migrations module handles this automatically. + */ + public function initializeSchemaInformation() + { + try { + $this->execute("CREATE TABLE schema_info (". + " version ".$this->typeToSql('integer'). + ")"); + return $this->execute("INSERT INTO schema_info (version) VALUES (0)"); + } catch (Exception $e) {} + } + + /** + * The sql for this column type + * + * @param string $type + * @param string $limit + */ + public function typeToSql($type, $limit=null, $precision=null, $scale=null) + { + $natives = $this->nativeDatabaseTypes(); + $native = isset($natives[$type]) ? $natives[$type] : null; + if (empty($native)) { return $type; } + + $sql = is_array($native) ? $native['name'] : $native; + if ($type == 'decimal') { + $nativePrec = isset($native['precision']) ? $native['precision'] : null; + $nativeScale = isset($native['scale']) ? $native['scale'] : null; + + $precision = !empty($precision) ? $precision : $nativePrec; + $scale = !empty($scale) ? $scale : $nativeScale; + if ($precision) { + $sql .= $scale ? "($precision, $scale)" : "($precision)"; + } + } else { + $nativeLimit = is_array($native) ? $native['limit'] : null; + if ($limit = !empty($limit) ? $limit : $nativeLimit) { + $sql .= "($limit)"; + } + } + return $sql; + } + + /** + * Add default/null options to column sql + * + * @param string $sql + * @param array $options + */ + public function addColumnOptions($sql, $options) + { + if (isset($options['null']) && $options['null'] === false) { + $sql .= ' NOT NULL'; + } + if (isset($options['default'])) { + $default = $options['default']; + $column = isset($options['column']) ? $options['column'] : null; + $sql .= ' DEFAULT '.$this->quote($default, $column); + } + return $sql; + } + + /** + * SELECT DISTINCT clause for a given set of columns and a given + * ORDER BY clause. Both PostgreSQL and Oracle override this for + * custom DISTINCT syntax. + * + * $connection->distinct("posts.id", "posts.created_at desc") + * + * @param string $columns + * @param string $orderBy + */ + public function distinct($columns, $orderBy=null) + { + return "DISTINCT $columns"; + } + + /** + * ORDER BY clause for the passed order option. + * PostgreSQL overrides this due to its stricter standards compliance. + * + * @param string $sql + * @param array $options + * @return string + */ + public function addOrderByForAssocLimiting($sql, $options) + { + return $sql.'ORDER BY '.$options['order']; + } + + + /*########################################################################## + # Protected + ##########################################################################*/ + + /** + * We need to clear cache for tables when altering them at all + */ + protected function _clearTableCache($tableName) + { + $this->_cache->set("tables/columns/$tableName", null); + $this->_cache->set("tables/indexes/$tableName", null); + } + +} diff --git a/framework/Db/lib/Horde/Db/Adapter/Base/Table.php b/framework/Db/lib/Horde/Db/Adapter/Base/Table.php new file mode 100644 index 000000000..f0dfa0ca4 --- /dev/null +++ b/framework/Db/lib/Horde/Db/Adapter/Base/Table.php @@ -0,0 +1,123 @@ + + * @author Derek DeVries + * @author Chuck Hagenbuch + * @license http://opensource.org/licenses/bsd-license.php + * @category Horde + * @package Horde_Db + * @subpackage Adapter + */ + +/** + * @author Mike Naberezny + * @author Derek DeVries + * @author Chuck Hagenbuch + * @license http://opensource.org/licenses/bsd-license.php + * @category Horde + * @package Horde_Db + * @subpackage Adapter + */ +class Horde_Db_Adapter_Base_Table +{ + protected $_name; + protected $_primaryKey; + protected $_columns; + protected $_indexes; + + + /*########################################################################## + # Construct/Destruct + ##########################################################################*/ + + /** + * Construct + * + * @param string $name The table's name, such as supplier_id in supplier_id int(11). + */ + public function __construct($name, $primaryKey, $columns, $indexes) + { + $this->_name = $name; + $this->_primaryKey = $primaryKey; + $this->_columns = $columns; + $this->_indexes = $indexes; + } + + + /*########################################################################## + # Accessor + ##########################################################################*/ + + /** + * @return string + */ + public function getName() + { + return $this->_name; + } + + /** + * @return mixed + */ + public function getPrimaryKey() + { + return $this->_primaryKey; + } + + /** + * @return array + */ + public function getColumns() + { + return $this->_columns; + } + + /** + * @return Horde_Db_Adapter_Base_Column + */ + public function getColumn($column) + { + return isset($this->_columns[$column]) ? $this->_columns[$column] : null; + } + + /** + * @return array + */ + public function getColumnNames() + { + $names = array(); + foreach ($this->_columns as $column) { + $names[] = $column->getName(); + } + return $names; + } + + /** + * @return array + */ + public function getIndexes() + { + return $this->_indexes; + } + + /** + * @return array + */ + public function getIndexNames() + { + $names = array(); + foreach ($this->_indexes as $index) { + $names[] = $index->getName(); + } + return $names; + } + + + /*########################################################################## + # Protected + ##########################################################################*/ + +} diff --git a/framework/Db/lib/Horde/Db/Adapter/Base/TableDefinition.php b/framework/Db/lib/Horde/Db/Adapter/Base/TableDefinition.php new file mode 100644 index 000000000..a5af543a1 --- /dev/null +++ b/framework/Db/lib/Horde/Db/Adapter/Base/TableDefinition.php @@ -0,0 +1,235 @@ + + * @author Derek DeVries + * @author Chuck Hagenbuch + * @license http://opensource.org/licenses/bsd-license.php + * @category Horde + * @package Horde_Db + * @subpackage Adapter + */ + +/** + * @author Mike Naberezny + * @author Derek DeVries + * @author Chuck Hagenbuch + * @license http://opensource.org/licenses/bsd-license.php + * @category Horde + * @package Horde_Db + * @subpackage Adapter + */ +class Horde_Db_Adapter_Base_TableDefinition implements ArrayAccess +{ + protected $_name = null; + protected $_base = null; + protected $_options = null; + protected $_columns = null; + + /** + * Class Constructor + * + * @param string $name + * @param Horde_Db_Adapter_Base_Schema $base + * @param array $options + */ + public function __construct($name, $base, $options=array()) + { + $this->_name = $name; + $this->_base = $base; + $this->_options = $options; + $this->_columns = array(); + } + + /** + * @return string + */ + public function getName() + { + return $this->_name; + } + + /** + * @return array + */ + public function getOptions() + { + return $this->_options; + } + + /** + * @param string $name + */ + public function primaryKey($name) + { + $natives = $this->_native(); + $this->column($name, $natives['primaryKey']); + } + + /** + * Instantiates a new column for the table. + * The +type+ parameter must be one of the following values: + * :primary_key, :string, :text, + * :integer, :float, :datetime, + * :timestamp, :time, :date, + * :binary, :boolean. + * + * Available options are (none of these exists by default): + * * :limit: + * Requests a maximum column length (:string, :text, + * :binary or :integer columns only) + * * :default: + * The column's default value. You cannot explicitely set the default + * value to +NULL+. Simply leave off this option if you want a +NULL+ + * default value. + * * :null: + * Allows or disallows +NULL+ values in the column. This option could + * have been named :null_allowed. + * + * This method returns self. + * + * ===== Examples + * # Assuming def is an instance of TableDefinition + * def.column(:granted, :boolean) + * #=> granted BOOLEAN + * + * def.column(:picture, :binary, :limit => 2.megabytes) + * #=> picture BLOB(2097152) + * + * def.column(:sales_stage, :string, :limit => 20, :default => 'new', :null => false) + * #=> sales_stage VARCHAR(20) DEFAULT 'new' NOT NULL + * + * @return TableDefinition + */ + public function column($name, $type, $options=array()) + { + if ($this[$name]) { + $column = $this[$name]; + } else { + $column = $this->_base->componentFactory('ColumnDefinition', array( + $this->_base, $name, $type)); + } + + $natives = $this->_native(); + $opt = $options; + + if (isset($opt['limit']) || isset($natives[$type])) { + $nativeLimit = isset($natives[$type]['limit']) ? $natives[$type]['limit'] : null; + $column->setLimit(isset($opt['limit']) ? $opt['limit'] : $nativeLimit); + } + + $column->setPrecision(isset($opt['precision']) ? $opt['precision'] : null); + $column->setScale(isset($opt['scale']) ? $opt['scale'] : null); + $column->setDefault(isset($opt['default']) ? $opt['default'] : null); + $column->setNull(isset($opt['null']) ? $opt['null'] : null); + + $this[$name] ? $this[$name] = $column : $this->_columns[] = $column; + return $this; + } + + /** + * Wrap up table creation block & create the table + */ + public function end() + { + return $this->_base->endTable($this); + } + + /** + * Returns a String whose contents are the column definitions + * concatenated together. This string can then be pre and appended to + * to generate the final SQL to create the table. + * + * @return string + */ + public function toSql() + { + $cols = array(); + foreach ($this->_columns as $col) { $cols[] = $col->toSql(); } + + return " ".implode(", \n ", $cols); + } + + + /*########################################################################## + # ArrayAccess + ##########################################################################*/ + + /** + * ArrayAccess: Check if the given offset exists + * + * @param int $offset + * @return boolean + */ + public function offsetExists($offset) + { + foreach ($this->_columns as $column) { + if ($column->getName() == $offset) return true; + } + return false; + } + + /** + * ArrayAccess: Return the value for the given offset. + * + * @param int $offset + * @return object {@link {@Horde_Db_Adapter_Base_ColumnDefinition} + */ + public function offsetGet($offset) + { + if (!$this->offsetExists($offset)) { + return null; + } + + foreach ($this->_columns as $column) { + if ($column->getName() == $offset) { + return $column; + } + } + } + + /** + * ArrayAccess: Set value for given offset + * + * @param int $offset + * @param mixed $value + */ + public function offsetSet($offset, $value) + { + foreach ($this->_columns as $key=>$column) { + if ($column->getName() == $offset) { + $this->_columns[$key] = $value; + } + } + } + + /** + * ArrayAccess: remove element + * + * @param int $offset + */ + public function offsetUnset($offset) + { + foreach ($this->_columns as $key=>$column) { + if ($column->getName() == $offset) { + unset($this->_columns[$key]); + } + } + } + + + /*########################################################################## + # Protected + ##########################################################################*/ + + /** + * Get the types + */ + protected function _native() + { + return $this->_base->nativeDatabaseTypes(); + } + +} diff --git a/framework/Db/lib/Horde/Db/Adapter/Mssql/Schema.php b/framework/Db/lib/Horde/Db/Adapter/Mssql/Schema.php index 1156332b8..82db9126d 100644 --- a/framework/Db/lib/Horde/Db/Adapter/Mssql/Schema.php +++ b/framework/Db/lib/Horde/Db/Adapter/Mssql/Schema.php @@ -21,7 +21,7 @@ * @package Horde_Db * @subpackage Adapter */ -class Horde_Db_Adapter_Mssql_Schema extends Horde_Db_Adapter_Abstract_Schema +class Horde_Db_Adapter_Mssql_Schema extends Horde_Db_Adapter_Base_Schema { /*########################################################################## # Quoting diff --git a/framework/Db/lib/Horde/Db/Adapter/Mysql/Column.php b/framework/Db/lib/Horde/Db/Adapter/Mysql/Column.php index c94f303ff..c118c53f0 100644 --- a/framework/Db/lib/Horde/Db/Adapter/Mysql/Column.php +++ b/framework/Db/lib/Horde/Db/Adapter/Mysql/Column.php @@ -21,7 +21,7 @@ * @package Horde_Db * @subpackage Adapter */ -class Horde_Db_Adapter_Mysql_Column extends Horde_Db_Adapter_Abstract_Column +class Horde_Db_Adapter_Mysql_Column extends Horde_Db_Adapter_Base_Column { /** * @var array diff --git a/framework/Db/lib/Horde/Db/Adapter/Mysql/Schema.php b/framework/Db/lib/Horde/Db/Adapter/Mysql/Schema.php index 358068475..eb902feba 100644 --- a/framework/Db/lib/Horde/Db/Adapter/Mysql/Schema.php +++ b/framework/Db/lib/Horde/Db/Adapter/Mysql/Schema.php @@ -21,7 +21,7 @@ * @package Horde_Db * @subpackage Adapter */ -class Horde_Db_Adapter_Mysql_Schema extends Horde_Db_Adapter_Abstract_Schema +class Horde_Db_Adapter_Mysql_Schema extends Horde_Db_Adapter_Base_Schema { /*########################################################################## # Quoting diff --git a/framework/Db/lib/Horde/Db/Adapter/Mysqli.php b/framework/Db/lib/Horde/Db/Adapter/Mysqli.php index 19a587e9f..35d422244 100644 --- a/framework/Db/lib/Horde/Db/Adapter/Mysqli.php +++ b/framework/Db/lib/Horde/Db/Adapter/Mysqli.php @@ -23,7 +23,7 @@ * @package Horde_Db * @subpackage Adapter */ -class Horde_Db_Adapter_Mysqli extends Horde_Db_Adapter_Abstract +class Horde_Db_Adapter_Mysqli extends Horde_Db_Adapter_Base { /** * Mysqli database connection object. diff --git a/framework/Db/lib/Horde/Db/Adapter/Oracle/Schema.php b/framework/Db/lib/Horde/Db/Adapter/Oracle/Schema.php index 3ddb1fbdb..f4bb17985 100644 --- a/framework/Db/lib/Horde/Db/Adapter/Oracle/Schema.php +++ b/framework/Db/lib/Horde/Db/Adapter/Oracle/Schema.php @@ -21,7 +21,7 @@ * @package Horde_Db * @subpackage Adapter */ -class Horde_Db_Adapter_Oracle_Schema extends Horde_Db_Adapter_Abstract_Schema +class Horde_Db_Adapter_Oracle_Schema extends Horde_Db_Adapter_Base_Schema { /*########################################################################## # Quoting diff --git a/framework/Db/lib/Horde/Db/Adapter/Postgresql/Column.php b/framework/Db/lib/Horde/Db/Adapter/Postgresql/Column.php index b8cef05e5..895a37b0e 100644 --- a/framework/Db/lib/Horde/Db/Adapter/Postgresql/Column.php +++ b/framework/Db/lib/Horde/Db/Adapter/Postgresql/Column.php @@ -21,7 +21,7 @@ * @package Horde_Db * @subpackage Adapter */ -class Horde_Db_Adapter_Postgresql_Column extends Horde_Db_Adapter_Abstract_Column +class Horde_Db_Adapter_Postgresql_Column extends Horde_Db_Adapter_Base_Column { /*########################################################################## # Constants diff --git a/framework/Db/lib/Horde/Db/Adapter/Postgresql/Schema.php b/framework/Db/lib/Horde/Db/Adapter/Postgresql/Schema.php index 9c73a98c0..74d1df94a 100644 --- a/framework/Db/lib/Horde/Db/Adapter/Postgresql/Schema.php +++ b/framework/Db/lib/Horde/Db/Adapter/Postgresql/Schema.php @@ -21,7 +21,7 @@ * @package Horde_Db * @subpackage Adapter */ -class Horde_Db_Adapter_Postgresql_Schema extends Horde_Db_Adapter_Abstract_Schema +class Horde_Db_Adapter_Postgresql_Schema extends Horde_Db_Adapter_Base_Schema { /** * @var string diff --git a/framework/Db/lib/Horde/Db/Adapter/Sqlite/Column.php b/framework/Db/lib/Horde/Db/Adapter/Sqlite/Column.php index ecaf8107b..765074927 100644 --- a/framework/Db/lib/Horde/Db/Adapter/Sqlite/Column.php +++ b/framework/Db/lib/Horde/Db/Adapter/Sqlite/Column.php @@ -21,7 +21,7 @@ * @package Horde_Db * @subpackage Adapter */ -class Horde_Db_Adapter_Sqlite_Column extends Horde_Db_Adapter_Abstract_Column +class Horde_Db_Adapter_Sqlite_Column extends Horde_Db_Adapter_Base_Column { /** * @var array diff --git a/framework/Db/lib/Horde/Db/Adapter/Sqlite/Schema.php b/framework/Db/lib/Horde/Db/Adapter/Sqlite/Schema.php index 5442efe16..c3ca43e21 100644 --- a/framework/Db/lib/Horde/Db/Adapter/Sqlite/Schema.php +++ b/framework/Db/lib/Horde/Db/Adapter/Sqlite/Schema.php @@ -21,7 +21,7 @@ * @package Horde_Db * @subpackage Adapter */ -class Horde_Db_Adapter_Sqlite_Schema extends Horde_Db_Adapter_Abstract_Schema +class Horde_Db_Adapter_Sqlite_Schema extends Horde_Db_Adapter_Base_Schema { /*########################################################################## # Quoting diff --git a/framework/Db/package.xml b/framework/Db/package.xml index ccff3fb9f..260c2f471 100644 --- a/framework/Db/package.xml +++ b/framework/Db/package.xml @@ -38,14 +38,14 @@ http://pear.php.net/dtd/package-2.0.xsd"> - + - + @@ -99,12 +99,12 @@ http://pear.php.net/dtd/package-2.0.xsd"> - - - - - - + + + + + +