<?php
/**
* Copyright 2007 Maintainable Software, LLC
* Copyright 2008 The Horde Project (http://www.horde.org/)
*
* @author Mike Naberezny <hide@address.com>
* @author Derek DeVries <hide@address.com>
* @author Chuck Hagenbuch <hide@address.com>
* @license http://opensource.org/licenses/bsd-license.php
* @category Horde
* @package Horde_Db
* @subpackage Adapter
*/
/**
* @author Mike Naberezny <hide@address.com>
* @author Derek DeVries <hide@address.com>
* @author Chuck Hagenbuch <hide@address.com>
* @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;
protected $_columntypes = array ('string', 'text', 'integer', 'float',
'datetime', 'timestamp', 'time', 'date', 'binary', 'boolean');
/**
* 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 one or several new columns for the table.
* The +type+ parameter must be one of the following values:
* <tt>:primary_key</tt>, <tt>:string</tt>, <tt>:text</tt>,
* <tt>:integer</tt>, <tt>:float</tt>, <tt>:datetime</tt>,
* <tt>:timestamp</tt>, <tt>:time</tt>, <tt>:date</tt>,
* <tt>:binary</tt>, <tt>:boolean</tt>.
*
* Available options are (none of these exists by default):
* * <tt>:limit</tt>:
* Requests a maximum column length (<tt>:string</tt>, <tt>:text</tt>,
* <tt>:binary</tt> or <tt>:integer</tt> columns only)
* * <tt>:default</tt>:
* 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.
* * <tt>:null</tt>:
* Allows or disallows +NULL+ values in the column. This option could
* have been named <tt>:null_allowed</tt>.
*
* This method returns <tt>self</tt>.
*
* ===== 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 (is_array($name)) {
foreach ($name as $col)
$this->column($col, $type, $options);
}
else {
if ($this[$name]) {
$column = $this[$name];
} else {
$column = new Horde_Db_Adapter_Abstract_ColumnDefinition(
$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;
}
/**
* Adds created_at and updated_at columns to the table
*
* This method returns <tt>self</tt>.
*/
public function timestamps()
{
return $this->column(array('created_at', 'updated_at'), 'datetime');
}
/*
* Add one or several references to foreign keys
*
* This method returns <tt>self</tt>.
*/
public function belongsTo($columns)
{
if (is_array($columns)) {
foreach ($columns as $col)
$cols[] = $col . '_id';
}
else {
$cols = $columns . '_id';
}
return $this->column($cols, 'integer');
}
/*
* Alias for the belongsTo() method
*
* This method returns <tt>self</tt>.
*/
public function references($columns)
{
return $this->belongsTo($columns);
}
/**
* Use __call to implement sexy migrations
*
* This method returns <tt>self</tt>.
*/
public function __call($method, $arguments)
{
if (!in_array($method, $this->_columntypes)) {
throw new BadMethodCallException('Call to undeclared method "'.$method.'"');
}
else if (count($arguments) > 0 && count($arguments) < 3) {
return $this->column($arguments[0], $method,
isset($arguments[1]) ? $arguments[1] : array());
}
else {
throw new BadMethodCallException('Method "'.$method.'" takes two arguments');
}
}
/**
* 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();
}
}