Schema System

CakePHP features a schema system that is capable of reflecting and generatingschema information for tables in SQL datastores. The schema system cangenerate/reflect a schema for any SQL platform that CakePHP supports.

The main pieces of the schema system are Cake\Database\Schema\Collection andCake\Database\Schema\TableSchema. These classes give you access todatabase-wide and individual Table object features respectively.

The primary use of the schema system is for Fixtures. However, itcan also be used in your application if required.

Schema\TableSchema Objects

  • class Cake\Database\Schema\TableSchema
  • The schema subsystem provides a simple TableSchema object to hold data about atable in a database. This object is returned by the schema reflectionfeatures:
  1. use Cake\Database\Schema\TableSchema;
  2.  
  3. // Create a table one column at a time.
  4. $schema = new TableSchema('posts');
  5. $schema->addColumn('id', [
  6. 'type' => 'integer',
  7. 'length' => 11,
  8. 'null' => false,
  9. 'default' => null,
  10. ])->addColumn('title', [
  11. 'type' => 'string',
  12. 'length' => 255,
  13. // Create a fixed length (char field)
  14. 'fixed' => true
  15. ])->addConstraint('primary', [
  16. 'type' => 'primary',
  17. 'columns' => ['id']
  18. ]);
  19.  
  20. // Schema\TableSchema classes could also be created with array data
  21. $schema = new TableSchema('posts', $columns);

Schema\TableSchema objects allow you to build up information about a table’s schema. It helps tonormalize and validate the data used to describe a table. For example, thefollowing two forms are equivalent:

  1. $schema->addColumn('title', 'string');
  2. // and
  3. $schema->addColumn('title', [
  4. 'type' => 'string'
  5. ]);

While equivalent, the 2nd form allows more detail and control. This emulatesthe existing features available in Schema files + the fixture schema in 2.x.

Accessing Column Data

Columns are either added as constructor arguments, or via addColumn(). Oncefields are added information can be fetched using column() or columns():

  1. // Get the array of data about a column
  2. $c = $schema->column('title');
  3.  
  4. // Get the list of all columns.
  5. $cols = $schema->columns();

Indexes and Constraints

Indexes are added using the addIndex(). Constraints are added usingaddConstraint(). Indexes and constraints cannot be added for columns that donot exist, as it would result in an invalid state. Indexes are different fromconstraints, and exceptions will be raised if you try to mix types between themethods. An example of both methods is:

  1. $schema = new TableSchema('posts');
  2. $schema->addColumn('id', 'integer')
  3. ->addColumn('author_id', 'integer')
  4. ->addColumn('title', 'string')
  5. ->addColumn('slug', 'string');
  6.  
  7. // Add a primary key.
  8. $schema->addConstraint('primary', [
  9. 'type' => 'primary',
  10. 'columns' => ['id']
  11. ]);
  12. // Add a unique key
  13. $schema->addConstraint('slug_idx', [
  14. 'columns' => ['slug'],
  15. 'type' => 'unique',
  16. ]);
  17. // Add index
  18. $schema->addIndex('slug_title', [
  19. 'columns' => ['slug', 'title'],
  20. 'type' => 'index'
  21. ]);
  22. // Add a foreign key
  23. $schema->addConstraint('author_id_idx', [
  24. 'columns' => ['author_id'],
  25. 'type' => 'foreign',
  26. 'references' => ['authors', 'id'],
  27. 'update' => 'cascade',
  28. 'delete' => 'cascade'
  29. ]);

If you add a primary key constraint to a single integer column it will automaticallybe converted into a auto-increment/serial column depending on the databaseplatform:

  1. $schema = new TableSchema('posts');
  2. $schema->addColumn('id', 'integer')
  3. ->addConstraint('primary', [
  4. 'type' => 'primary',
  5. 'columns' => ['id']
  6. ]);

In the above example the id column would generate the following SQL inMySQL:

  1. CREATE TABLE `posts` (
  2. `id` INTEGER AUTO_INCREMENT,
  3. PRIMARY KEY (`id`)
  4. )

If your primary key contains more than one column, none of them willautomatically be converted to an auto-increment value. Instead you will need totell the table object which column in the composite key you want toauto-increment:

  1. $schema = new TableSchema('posts');
  2. $schema->addColumn('id', [
  3. 'type' => 'integer',
  4. 'autoIncrement' => true,
  5. ])
  6. ->addColumn('account_id', 'integer')
  7. ->addConstraint('primary', [
  8. 'type' => 'primary',
  9. 'columns' => ['id', 'account_id']
  10. ]);

The autoIncrement option only works with integer and bigintegercolumns.

Reading Indexes and Constraints

Indexes and constraints can be read out of a table object using accessormethods. Assuming that $schema is a populated TableSchema instance you could do thefollowing:

  1. // Get contraints. Will return the
  2. // names of all constraints.
  3. $constraints = $schema->constraints()
  4.  
  5. // Get data about a single constraint.
  6. $constraint = $schema->constraint('author_id_idx')
  7.  
  8. // Get indexes. Will return the
  9. // names of all indexes.
  10. $indexes = $schema->indexes()
  11.  
  12. // Get data about a single index.
  13. $index = $schema->index('author_id_idx')

Adding Table Options

Some drivers (primarily MySQL) support and require additional table metadata. Inthe case of MySQL the CHARSET, COLLATE and ENGINE properties arerequired for maintaining a table’s structure in MySQL. The following could beused to add table options:

  1. $schema->options([
  2. 'engine' => 'InnoDB',
  3. 'collate' => 'utf8_unicode_ci',
  4. ]);

Platform dialects only handle the keys they are interested inand ignore the rest. Not all options are supported on all platforms.

Converting Tables into SQL

Using the createSql() or dropSql() you can getplatform specific SQL for creating or dropping a specific table:

  1. $db = ConnectionManager::get('default');
  2. $schema = new TableSchema('posts', $fields, $indexes);
  3.  
  4. // Create a table
  5. $queries = $schema->createSql($db);
  6. foreach ($queries as $sql) {
  7. $db->execute($sql);
  8. }
  9.  
  10. // Drop a table
  11. $sql = $schema->dropSql($db);
  12. $db->execute($sql);

By using a connection’s driver the schema data can be converted into platformspecific SQL. The return of createSql and dropSql is a list of SQLqueries required to create a table and the required indexes. Some platforms mayrequire multiple statements to create tables with comments and/or indexes. Anarray of queries is always returned.

Schema Collections

  • class Cake\Database\Schema\Collection
  • Collection provides access to the various tables available on a connection.You can use it to get the list of tables or reflect tables intoTableSchema objects. Basic usage of the class looks like:
  1. $db = ConnectionManager::get('default');
  2.  
  3. // Create a schema collection.
  4. $collection = $db->schemaCollection();
  5.  
  6. // Get the table names
  7. $tables = $collection->listTables();
  8.  
  9. // Get a single table (instance of Schema\TableSchema)
  10. $tableSchema = $collection->describe('posts');