| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614 |
- <?php
- /**
- * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
- * Copyright (c) Cake Software Foundation, Inc. (http://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. (http://cakefoundation.org)
- * @link http://cakephp.org CakePHP(tm) Project
- * @since 3.0.0
- * @license http://www.opensource.org/licenses/mit-license.php MIT License
- */
- namespace Cake\Database\Schema;
- use Cake\Database\Connection;
- use Cake\Database\Exception;
- /**
- * 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 Table instances can be added to
- * Schema\Collection objects. They can also be converted into SQL using the
- * createSql(), dropSql() and truncateSql() methods.
- */
- class Table {
- /**
- * The name of the table
- *
- * @var string
- */
- protected $_table;
- /**
- * Columns in the table.
- *
- * @var array
- */
- protected $_columns = [];
- /**
- * 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;
- /**
- * The valid keys that can be used in a column
- * definition.
- *
- * @var array
- */
- protected static $_columnKeys = [
- 'type' => null,
- 'length' => null,
- 'precision' => null,
- 'null' => null,
- 'default' => null,
- 'comment' => null,
- ];
- /**
- * Additional type specific properties.
- *
- * @var array
- */
- protected static $_columnExtras = [
- 'string' => [
- 'fixed' => 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 = array()) {
- $this->_table = $table;
- foreach ($columns as $field => $definition) {
- $this->addColumn($field, $definition);
- }
- }
- /**
- * Get the name of the table.
- *
- * @return string
- */
- public function name() {
- return $this->_table;
- }
- /**
- * Add a column to the table.
- *
- * ### Attributes
- *
- * Columns can have several attributes:
- *
- * - `type` The type of the column. This should be
- * one of CakePHP's abstract types.
- * - `length` The length of the column.
- * - `precision` The number of decimal places to store
- * for float and decimal types.
- * - `default` The default value of the column.
- * - `null` Whether or not the column can hold nulls.
- * - `fixed` Whether or not the column is a fixed length column.
- * This is only present/valid with string columns.
- * - `unsigned` Whether or not the column is an unsigned column.
- * This is only present/valid for integer, decimal, float columns.
- *
- * In addition to the above keys, the following keys are
- * implemented in some database dialects, but not all:
- *
- * - `comment` The comment for the column.
- *
- * @param string $name The name of the column
- * @param array $attrs The attributes for the column.
- * @return $this
- */
- 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;
- return $this;
- }
- /**
- * Get the column names in the table.
- *
- * @return array
- */
- 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.
- */
- public function column($name) {
- if (!isset($this->_columns[$name])) {
- return null;
- }
- return $this->_columns[$name];
- }
- /**
- * 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 $type The type to set the column to.
- * @return string|null Either the column type or null.
- */
- public function columnType($name, $type = null) {
- if (!isset($this->_columns[$name])) {
- return null;
- }
- if ($type !== null) {
- $this->_columns[$name]['type'] = $type;
- }
- return $this->_columns[$name]['type'];
- }
- /**
- * Get a hash of columns and their default values.
- *
- * @return array
- */
- 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;
- }
- /**
- * Add an index.
- *
- * Used to add indexes, and full text indexes in platforms that support
- * them.
- *
- * ### Attributes
- *
- * - `type` The type of index being added.
- * - `columns` The columns in the index.
- *
- * @param string $name The name of the index.
- * @param array $attrs The attributes for the index.
- * @return $this
- * @throws \Cake\Database\Exception
- */
- public function addIndex($name, $attrs) {
- if (is_string($attrs)) {
- $attrs = ['type' => $attrs];
- }
- $attrs = array_intersect_key($attrs, static::$_indexKeys);
- $attrs = $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"', $attrs['type']));
- }
- if (empty($attrs['columns'])) {
- throw new Exception('Indexes must have at least one column.');
- }
- $attrs['columns'] = (array)$attrs['columns'];
- foreach ($attrs['columns'] as $field) {
- if (empty($this->_columns[$field])) {
- $msg = sprintf(
- 'Columns used in indexes must be added to the Table schema first. ' .
- 'The column "%s" was not found.',
- $field
- );
- throw new Exception($msg);
- }
- }
- $this->_indexes[$name] = $attrs;
- return $this;
- }
- /**
- * Get the names of all the indexes in the table.
- *
- * @return array
- */
- 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
- */
- public function index($name) {
- if (!isset($this->_indexes[$name])) {
- return null;
- }
- return $this->_indexes[$name];
- }
- /**
- * Get the column(s) used for the primary key.
- *
- * @return array Column name(s) for the primary key. An
- * empty list will be returned when the table has no primary key.
- */
- public function primaryKey() {
- foreach ($this->_constraints as $name => $data) {
- if ($data['type'] === static::CONSTRAINT_PRIMARY) {
- return $data['columns'];
- }
- }
- return [];
- }
- /**
- * Add a constraint.
- *
- * Used to add constraints to a table. For example primary keys, unique
- * keys and foreign keys.
- *
- * ### Attributes
- *
- * - `type` The type of constraint being added.
- * - `columns` The columns in the index.
- * - `references` The table, column a foreign key references.
- * - `update` The behavior on update. Options are 'restrict', 'setNull', 'cascade', 'noAction'.
- * - `delete` The behavior on delete. Options are 'restrict', 'setNull', 'cascade', 'noAction'.
- *
- * The default for 'update' & 'delete' is 'cascade'.
- *
- * @param string $name The name of the constraint.
- * @param array $attrs The attributes for the constraint.
- * @return $this
- * @throws \Cake\Database\Exception
- */
- public function addConstraint($name, $attrs) {
- if (is_string($attrs)) {
- $attrs = ['type' => $attrs];
- }
- $attrs = array_intersect_key($attrs, static::$_indexKeys);
- $attrs = $attrs + static::$_indexKeys;
- if (!in_array($attrs['type'], static::$_validConstraintTypes, true)) {
- throw new Exception(sprintf('Invalid constraint type "%s"', $attrs['type']));
- }
- if (empty($attrs['columns'])) {
- throw new Exception('Constraints must have at least one column.');
- }
- $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.',
- $field
- );
- throw new Exception($msg);
- }
- }
- if ($attrs['type'] === static::CONSTRAINT_FOREIGN) {
- $attrs = $this->_checkForeignKey($attrs);
- } else {
- unset($attrs['references'], $attrs['update'], $attrs['delete']);
- }
- $this->_constraints[$name] = $attrs;
- return $this;
- }
- /**
- * 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;
- }
- /**
- * Get the names of all the constraints in the table.
- *
- * @return array
- */
- 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
- */
- public function constraint($name) {
- if (!isset($this->_constraints[$name])) {
- return null;
- }
- return $this->_constraints[$name];
- }
- /**
- * 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.
- *
- * @param array|null $options The options to set, or null to read options.
- * @return $this|array Either the table instance, or an array of options when reading.
- */
- public function options($options = null) {
- if ($options === null) {
- return $this->_options;
- }
- $this->_options = array_merge($this->_options, $options);
- return $this;
- }
- /**
- * Get/Set whether the table is temporary in the database
- *
- * @param bool|null $set whether or not the table is to be temporary
- * @return $this|bool Either the table instance, the current temporary setting
- */
- public function temporary($set = null) {
- if ($set === null) {
- return $this->_temporary;
- }
- $this->_temporary = (bool)$set;
- return $this;
- }
- /**
- * Generate the SQL to create the Table.
- *
- * Uses the connection to access the schema dialect
- * to generate platform specific SQL.
- *
- * @param Connection $connection The connection to generate SQL for
- * @return array List of SQL statements to create the table and the
- * required indexes.
- */
- public function createSql(Connection $connection) {
- $dialect = $connection->driver()->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);
- }
- /**
- * Generate the SQL to drop a table.
- *
- * Uses the connection to access the schema dialect to generate platform
- * specific SQL.
- *
- * @param Connection $connection The connection to generate SQL for.
- * @return array SQL to drop a table.
- */
- public function dropSql(Connection $connection) {
- $dialect = $connection->driver()->schemaDialect();
- return $dialect->dropTableSql($this);
- }
- /**
- * Generate the SQL statements to truncate a table
- *
- * @param Connection $connection The connection to generate SQL for.
- * @return array SQL to drop a table.
- */
- public function truncateSql(Connection $connection) {
- $dialect = $connection->driver()->schemaDialect();
- return $dialect->truncateTableSql($this);
- }
- }
|