123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873 |
- <?php
- /**
- * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
- * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
- *
- * Licensed under The MIT License
- * For full copyright and license information, please see the LICENSE.txt
- * Redistributions of files must retain the above copyright notice.
- *
- * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
- * @link https://cakephp.org CakePHP(tm) Project
- * @since 3.0.0
- * @license https://opensource.org/licenses/mit-license.php MIT License
- */
- namespace Cake\Database\Schema;
- use Cake\Database\Connection;
- use Cake\Database\Exception;
- use Cake\Database\Type;
- /**
- * Represents a single table in a database schema.
- *
- * Can either be populated using the reflection API's
- * or by incrementally building an instance using
- * methods.
- *
- * Once created TableSchema instances can be added to
- * Schema\Collection objects. They can also be converted into SQL using the
- * createSql(), dropSql() and truncateSql() methods.
- */
- class TableSchema implements TableSchemaInterface, SqlGeneratorInterface
- {
- /**
- * The name of the table
- *
- * @var string
- */
- protected $_table;
- /**
- * Columns in the table.
- *
- * @var array
- */
- protected $_columns = [];
- /**
- * A map with columns to types
- *
- * @var array
- */
- protected $_typeMap = [];
- /**
- * Indexes in the table.
- *
- * @var array
- */
- protected $_indexes = [];
- /**
- * Constraints in the table.
- *
- * @var array
- */
- protected $_constraints = [];
- /**
- * Options for the table.
- *
- * @var array
- */
- protected $_options = [];
- /**
- * Whether or not the table is temporary
- *
- * @var bool
- */
- protected $_temporary = false;
- /**
- * Column length when using a `tiny` column type
- *
- * @var int
- */
- const LENGTH_TINY = 255;
- /**
- * Column length when using a `medium` column type
- *
- * @var int
- */
- const LENGTH_MEDIUM = 16777215;
- /**
- * Column length when using a `long` column type
- *
- * @var int
- */
- const LENGTH_LONG = 4294967295;
- /**
- * Valid column length that can be used with text type columns
- *
- * @var array
- */
- public static $columnLengths = [
- 'tiny' => self::LENGTH_TINY,
- 'medium' => self::LENGTH_MEDIUM,
- 'long' => self::LENGTH_LONG
- ];
- /**
- * The valid keys that can be used in a column
- * definition.
- *
- * @var array
- */
- protected static $_columnKeys = [
- 'type' => null,
- 'baseType' => null,
- 'length' => null,
- 'precision' => null,
- 'null' => null,
- 'default' => null,
- 'comment' => null,
- ];
- /**
- * Additional type specific properties.
- *
- * @var array
- */
- protected static $_columnExtras = [
- 'string' => [
- 'fixed' => null,
- 'collate' => null,
- ],
- 'text' => [
- 'collate' => null,
- ],
- 'tinyinteger' => [
- 'unsigned' => null,
- ],
- 'smallinteger' => [
- 'unsigned' => null,
- ],
- 'integer' => [
- 'unsigned' => null,
- 'autoIncrement' => null,
- ],
- 'biginteger' => [
- 'unsigned' => null,
- 'autoIncrement' => null,
- ],
- 'decimal' => [
- 'unsigned' => null,
- ],
- 'float' => [
- 'unsigned' => null,
- ],
- ];
- /**
- * The valid keys that can be used in an index
- * definition.
- *
- * @var array
- */
- protected static $_indexKeys = [
- 'type' => null,
- 'columns' => [],
- 'length' => [],
- 'references' => [],
- 'update' => 'restrict',
- 'delete' => 'restrict',
- ];
- /**
- * Names of the valid index types.
- *
- * @var array
- */
- protected static $_validIndexTypes = [
- self::INDEX_INDEX,
- self::INDEX_FULLTEXT,
- ];
- /**
- * Names of the valid constraint types.
- *
- * @var array
- */
- protected static $_validConstraintTypes = [
- self::CONSTRAINT_PRIMARY,
- self::CONSTRAINT_UNIQUE,
- self::CONSTRAINT_FOREIGN,
- ];
- /**
- * Names of the valid foreign key actions.
- *
- * @var array
- */
- protected static $_validForeignKeyActions = [
- self::ACTION_CASCADE,
- self::ACTION_SET_NULL,
- self::ACTION_SET_DEFAULT,
- self::ACTION_NO_ACTION,
- self::ACTION_RESTRICT,
- ];
- /**
- * Primary constraint type
- *
- * @var string
- */
- const CONSTRAINT_PRIMARY = 'primary';
- /**
- * Unique constraint type
- *
- * @var string
- */
- const CONSTRAINT_UNIQUE = 'unique';
- /**
- * Foreign constraint type
- *
- * @var string
- */
- const CONSTRAINT_FOREIGN = 'foreign';
- /**
- * Index - index type
- *
- * @var string
- */
- const INDEX_INDEX = 'index';
- /**
- * Fulltext index type
- *
- * @var string
- */
- const INDEX_FULLTEXT = 'fulltext';
- /**
- * Foreign key cascade action
- *
- * @var string
- */
- const ACTION_CASCADE = 'cascade';
- /**
- * Foreign key set null action
- *
- * @var string
- */
- const ACTION_SET_NULL = 'setNull';
- /**
- * Foreign key no action
- *
- * @var string
- */
- const ACTION_NO_ACTION = 'noAction';
- /**
- * Foreign key restrict action
- *
- * @var string
- */
- const ACTION_RESTRICT = 'restrict';
- /**
- * Foreign key restrict default
- *
- * @var string
- */
- const ACTION_SET_DEFAULT = 'setDefault';
- /**
- * Constructor.
- *
- * @param string $table The table name.
- * @param array $columns The list of columns for the schema.
- */
- public function __construct($table, array $columns = [])
- {
- $this->_table = $table;
- foreach ($columns as $field => $definition) {
- $this->addColumn($field, $definition);
- }
- }
- /**
- * {@inheritDoc}
- */
- public function name()
- {
- return $this->_table;
- }
- /**
- * {@inheritDoc}
- */
- public function addColumn($name, $attrs)
- {
- if (is_string($attrs)) {
- $attrs = ['type' => $attrs];
- }
- $valid = static::$_columnKeys;
- if (isset(static::$_columnExtras[$attrs['type']])) {
- $valid += static::$_columnExtras[$attrs['type']];
- }
- $attrs = array_intersect_key($attrs, $valid);
- $this->_columns[$name] = $attrs + $valid;
- $this->_typeMap[$name] = $this->_columns[$name]['type'];
- return $this;
- }
- /**
- * {@inheritDoc}
- */
- public function removeColumn($name)
- {
- unset($this->_columns[$name], $this->_typeMap[$name]);
- return $this;
- }
- /**
- * {@inheritDoc}
- */
- public function columns()
- {
- return array_keys($this->_columns);
- }
- /**
- * Get column data in the table.
- *
- * @param string $name The column name.
- * @return array|null Column data or null.
- * @deprecated 3.5.0 Use getColumn() instead.
- */
- public function column($name)
- {
- deprecationWarning('TableSchema::column() is deprecated. Use TableSchema::getColumn() instead.');
- return $this->getColumn($name);
- }
- /**
- * {@inheritDoc}
- */
- public function getColumn($name)
- {
- if (!isset($this->_columns[$name])) {
- return null;
- }
- $column = $this->_columns[$name];
- unset($column['baseType']);
- return $column;
- }
- /**
- * Sets the type of a column, or returns its current type
- * if none is passed.
- *
- * @param string $name The column to get the type of.
- * @param string|null $type The type to set the column to.
- * @return string|null Either the column type or null.
- * @deprecated 3.5.0 Use setColumnType()/getColumnType() instead.
- */
- public function columnType($name, $type = null)
- {
- deprecationWarning('TableSchema::columnType() is deprecated. Use TableSchema::setColumnType() or TableSchema::getColumnType() instead.');
- if ($type !== null) {
- $this->setColumnType($name, $type);
- }
- return $this->getColumnType($name);
- }
- /**
- * {@inheritDoc}
- */
- public function getColumnType($name)
- {
- if (!isset($this->_columns[$name])) {
- return null;
- }
- return $this->_columns[$name]['type'];
- }
- /**
- * {@inheritDoc}
- */
- public function setColumnType($name, $type)
- {
- if (!isset($this->_columns[$name])) {
- return $this;
- }
- $this->_columns[$name]['type'] = $type;
- $this->_typeMap[$name] = $type;
- return $this;
- }
- /**
- * {@inheritDoc}
- */
- public function hasColumn($name)
- {
- return isset($this->_columns[$name]);
- }
- /**
- * {@inheritDoc}
- */
- public function baseColumnType($column)
- {
- if (isset($this->_columns[$column]['baseType'])) {
- return $this->_columns[$column]['baseType'];
- }
- $type = $this->getColumnType($column);
- if ($type === null) {
- return null;
- }
- if (Type::getMap($type)) {
- $type = Type::build($type)->getBaseType();
- }
- return $this->_columns[$column]['baseType'] = $type;
- }
- /**
- * {@inheritDoc}
- */
- public function typeMap()
- {
- return $this->_typeMap;
- }
- /**
- * {@inheritDoc}
- */
- public function isNullable($name)
- {
- if (!isset($this->_columns[$name])) {
- return true;
- }
- return ($this->_columns[$name]['null'] === true);
- }
- /**
- * {@inheritDoc}
- */
- public function defaultValues()
- {
- $defaults = [];
- foreach ($this->_columns as $name => $data) {
- if (!array_key_exists('default', $data)) {
- continue;
- }
- if ($data['default'] === null && $data['null'] !== true) {
- continue;
- }
- $defaults[$name] = $data['default'];
- }
- return $defaults;
- }
- /**
- * {@inheritDoc}
- * @throws \Cake\Database\Exception
- */
- public function addIndex($name, $attrs)
- {
- if (is_string($attrs)) {
- $attrs = ['type' => $attrs];
- }
- $attrs = array_intersect_key($attrs, static::$_indexKeys);
- $attrs += static::$_indexKeys;
- unset($attrs['references'], $attrs['update'], $attrs['delete']);
- if (!in_array($attrs['type'], static::$_validIndexTypes, true)) {
- throw new Exception(sprintf('Invalid index type "%s" in index "%s" in table "%s".', $attrs['type'], $name, $this->_table));
- }
- if (empty($attrs['columns'])) {
- throw new Exception(sprintf('Index "%s" in table "%s" must have at least one column.', $name, $this->_table));
- }
- $attrs['columns'] = (array)$attrs['columns'];
- foreach ($attrs['columns'] as $field) {
- if (empty($this->_columns[$field])) {
- $msg = sprintf(
- 'Columns used in index "%s" in table "%s" must be added to the Table schema first. ' .
- 'The column "%s" was not found.',
- $name,
- $this->_table,
- $field
- );
- throw new Exception($msg);
- }
- }
- $this->_indexes[$name] = $attrs;
- return $this;
- }
- /**
- * {@inheritDoc}
- */
- public function indexes()
- {
- return array_keys($this->_indexes);
- }
- /**
- * Read information about an index based on name.
- *
- * @param string $name The name of the index.
- * @return array|null Array of index data, or null
- * @deprecated 3.5.0 Use getIndex() instead.
- */
- public function index($name)
- {
- deprecationWarning('TableSchema::index() is deprecated. Use TableSchema::getIndex() instead.');
- return $this->getIndex($name);
- }
- /**
- * {@inheritDoc}
- */
- public function getIndex($name)
- {
- if (!isset($this->_indexes[$name])) {
- return null;
- }
- return $this->_indexes[$name];
- }
- /**
- * {@inheritDoc}
- */
- public function primaryKey()
- {
- foreach ($this->_constraints as $name => $data) {
- if ($data['type'] === static::CONSTRAINT_PRIMARY) {
- return $data['columns'];
- }
- }
- return [];
- }
- /**
- * {@inheritDoc}
- * @throws \Cake\Database\Exception
- */
- public function addConstraint($name, $attrs)
- {
- if (is_string($attrs)) {
- $attrs = ['type' => $attrs];
- }
- $attrs = array_intersect_key($attrs, static::$_indexKeys);
- $attrs += static::$_indexKeys;
- if (!in_array($attrs['type'], static::$_validConstraintTypes, true)) {
- throw new Exception(sprintf('Invalid constraint type "%s" in table "%s".', $attrs['type'], $this->_table));
- }
- if (empty($attrs['columns'])) {
- throw new Exception(sprintf('Constraints in table "%s" must have at least one column.', $this->_table));
- }
- $attrs['columns'] = (array)$attrs['columns'];
- foreach ($attrs['columns'] as $field) {
- if (empty($this->_columns[$field])) {
- $msg = sprintf(
- 'Columns used in constraints must be added to the Table schema first. ' .
- 'The column "%s" was not found in table "%s".',
- $field,
- $this->_table
- );
- throw new Exception($msg);
- }
- }
- if ($attrs['type'] === static::CONSTRAINT_FOREIGN) {
- $attrs = $this->_checkForeignKey($attrs);
- if (isset($this->_constraints[$name])) {
- $this->_constraints[$name]['columns'] = array_unique(array_merge(
- $this->_constraints[$name]['columns'],
- $attrs['columns']
- ));
- if (isset($this->_constraints[$name]['references'])) {
- $this->_constraints[$name]['references'][1] = array_unique(array_merge(
- (array)$this->_constraints[$name]['references'][1],
- [$attrs['references'][1]]
- ));
- }
- return $this;
- }
- } else {
- unset($attrs['references'], $attrs['update'], $attrs['delete']);
- }
- $this->_constraints[$name] = $attrs;
- return $this;
- }
- /**
- * {@inheritDoc}
- */
- public function dropConstraint($name)
- {
- if (isset($this->_constraints[$name])) {
- unset($this->_constraints[$name]);
- }
- return $this;
- }
- /**
- * Check whether or not a table has an autoIncrement column defined.
- *
- * @return bool
- */
- public function hasAutoincrement()
- {
- foreach ($this->_columns as $column) {
- if (isset($column['autoIncrement']) && $column['autoIncrement']) {
- return true;
- }
- }
- return false;
- }
- /**
- * Helper method to check/validate foreign keys.
- *
- * @param array $attrs Attributes to set.
- * @return array
- * @throws \Cake\Database\Exception When foreign key definition is not valid.
- */
- protected function _checkForeignKey($attrs)
- {
- if (count($attrs['references']) < 2) {
- throw new Exception('References must contain a table and column.');
- }
- if (!in_array($attrs['update'], static::$_validForeignKeyActions)) {
- throw new Exception(sprintf('Update action is invalid. Must be one of %s', implode(',', static::$_validForeignKeyActions)));
- }
- if (!in_array($attrs['delete'], static::$_validForeignKeyActions)) {
- throw new Exception(sprintf('Delete action is invalid. Must be one of %s', implode(',', static::$_validForeignKeyActions)));
- }
- return $attrs;
- }
- /**
- * {@inheritDoc}
- */
- public function constraints()
- {
- return array_keys($this->_constraints);
- }
- /**
- * Read information about a constraint based on name.
- *
- * @param string $name The name of the constraint.
- * @return array|null Array of constraint data, or null
- * @deprecated 3.5.0 Use getConstraint() instead.
- */
- public function constraint($name)
- {
- deprecationWarning('TableSchema::constraint() is deprecated. Use TableSchema::getConstraint() instead.');
- return $this->getConstraint($name);
- }
- /**
- * {@inheritDoc}
- */
- public function getConstraint($name)
- {
- if (!isset($this->_constraints[$name])) {
- return null;
- }
- return $this->_constraints[$name];
- }
- /**
- * {@inheritDoc}
- */
- public function setOptions($options)
- {
- $this->_options = array_merge($this->_options, $options);
- return $this;
- }
- /**
- * {@inheritDoc}
- */
- public function getOptions()
- {
- return $this->_options;
- }
- /**
- * Get/set the options for a table.
- *
- * Table options allow you to set platform specific table level options.
- * For example the engine type in MySQL.
- *
- * @deprecated 3.4.0 Use setOptions()/getOptions() instead.
- * @param array|null $options The options to set, or null to read options.
- * @return $this|array Either the TableSchema instance, or an array of options when reading.
- */
- public function options($options = null)
- {
- deprecationWarning('TableSchema::options() is deprecated. Use TableSchema::setOptions() or TableSchema::getOptions() instead.');
- if ($options !== null) {
- return $this->setOptions($options);
- }
- return $this->getOptions();
- }
- /**
- * {@inheritDoc}
- */
- public function setTemporary($temporary)
- {
- $this->_temporary = (bool)$temporary;
- return $this;
- }
- /**
- * {@inheritDoc}
- */
- public function isTemporary()
- {
- return $this->_temporary;
- }
- /**
- * Get/Set whether the table is temporary in the database
- *
- * @deprecated 3.4.0 Use setTemporary()/isTemporary() instead.
- * @param bool|null $temporary whether or not the table is to be temporary
- * @return $this|bool Either the TableSchema instance, the current temporary setting
- */
- public function temporary($temporary = null)
- {
- deprecationWarning(
- 'TableSchema::temporary() is deprecated. ' .
- 'Use TableSchema::setTemporary()/isTemporary() instead.'
- );
- if ($temporary !== null) {
- return $this->setTemporary($temporary);
- }
- return $this->isTemporary();
- }
- /**
- * {@inheritDoc}
- */
- public function createSql(Connection $connection)
- {
- $dialect = $connection->getDriver()->schemaDialect();
- $columns = $constraints = $indexes = [];
- foreach (array_keys($this->_columns) as $name) {
- $columns[] = $dialect->columnSql($this, $name);
- }
- foreach (array_keys($this->_constraints) as $name) {
- $constraints[] = $dialect->constraintSql($this, $name);
- }
- foreach (array_keys($this->_indexes) as $name) {
- $indexes[] = $dialect->indexSql($this, $name);
- }
- return $dialect->createTableSql($this, $columns, $constraints, $indexes);
- }
- /**
- * {@inheritDoc}
- */
- public function dropSql(Connection $connection)
- {
- $dialect = $connection->getDriver()->schemaDialect();
- return $dialect->dropTableSql($this);
- }
- /**
- * {@inheritDoc}
- */
- public function truncateSql(Connection $connection)
- {
- $dialect = $connection->getDriver()->schemaDialect();
- return $dialect->truncateTableSql($this);
- }
- /**
- * {@inheritDoc}
- */
- public function addConstraintSql(Connection $connection)
- {
- $dialect = $connection->getDriver()->schemaDialect();
- return $dialect->addConstraintSql($this);
- }
- /**
- * {@inheritDoc}
- */
- public function dropConstraintSql(Connection $connection)
- {
- $dialect = $connection->getDriver()->schemaDialect();
- return $dialect->dropConstraintSql($this);
- }
- /**
- * Returns an array of the table schema.
- *
- * @return array
- */
- public function __debugInfo()
- {
- return [
- 'table' => $this->_table,
- 'columns' => $this->_columns,
- 'indexes' => $this->_indexes,
- 'constraints' => $this->_constraints,
- 'options' => $this->_options,
- 'typeMap' => $this->_typeMap,
- 'temporary' => $this->_temporary,
- ];
- }
- }
- // @deprecated 3.4.0 Add backwards compat alias.
- class_alias('Cake\Database\Schema\TableSchema', 'Cake\Database\Schema\Table');
|