schema.module in Schema 8
Same filename and directory in other branches
The Schema module provides functionality built on the Schema API.
File
schema.moduleView source
<?php
/**
* @file
* The Schema module provides functionality built on the Schema API.
*/
use Drupal\Core\Database\Database;
use Drupal\schema\Comparison\SchemaComparator;
use Drupal\schema\Comparison\SchemaComparisonInfoBuilder;
use Drupal\schema\SchemaManager;
use Drupal\schema\SchemaProviderInterface;
/**
* Implements hooK_help().
*/
function schema_help($path, $arg) {
switch ($path) {
case 'admin/structure/schema':
return '<p>' . t('This page compares the live database as it currently exists against the combination of all schema information provided by all enabled modules.') . '<p>';
case 'admin/structure/schema/describe':
return '<p>' . t("This page describes the Drupal database schema. Click on a table name to see that table's description and fields. Table names within a table or field description are hyperlinks to that table's description.") . '</p>';
case 'admin/structure/schema/inspect':
$output = '<p>' . t("This page shows the live database schema as it currently exists on this system. Known tables are grouped by the module that defines them; unknown tables are all grouped together.") . '</p>';
$output .= '<p>' . t("To implement hook_schema() for a module that has existing tables, copy the schema structure for those tables directly into the module's hook_schema() and return \$schema.") . '</p>';
return $output;
case 'admin/structure/schema/sql':
return '<p>' . t('This page shows the CREATE TABLE statements that the Schema API generates for the selected database engine for each table defined by a module. It is for debugging purposes.') . '</p>';
case 'admin/structure/schema/show':
return '<p>' . t('This page displays the Drupal database schema data structure. It is for debugging purposes.') . '</p>';
}
}
/**
* Fetch the schema engine class name for a given database connection.
*
* @param string $connection
* A database connection key, defaults to 'default'.
*
* @return string
* The schema engine class name if available, otherwise FALSE.
*/
function schema_get_connection_engine_class($connection = 'default') {
if ($info = Database::getConnectionInfo($connection)) {
$driver = $info['default']['driver'];
$class_name = 'Drupal\\schema\\SchemaDatabaseSchema_' . $driver;
if (class_exists($class_name)) {
return $class_name;
}
}
return FALSE;
}
/**
* Fetch a schema engine class instance for a given database connection.
*
* @param string $connection
* A database connection key, defaults to the schema_database_connection
* variable, which itself defaults to 'default'.
*
* @return Drupal\schema\DatabaseSchemaInspectionInterface
* A schema engine class set to the given connection.
*/
function schema_dbobject($connection = NULL) {
if (!isset($connection)) {
$connection = \Drupal::config('schema.settings')
->get('schema_database_connection');
}
if ($class = schema_get_connection_engine_class($connection)) {
return new $class(Database::getConnection('default', $connection));
}
}
/**
* Get an array of connection options that are supported by schema inspection.
*/
function schema_get_connection_options() {
$options =& drupal_static(__FUNCTION__);
if (!isset($options)) {
foreach ($GLOBALS['databases'] as $connection => $targets) {
// Only support connections that can be inspected by schema module.
if (!schema_get_connection_engine_class($connection)) {
continue;
}
$options[$connection] = $connection;
}
}
return $options;
}
//////////////////////////////////////////////////////////////////////
// Schema print functions
//////////////////////////////////////////////////////////////////////
/**
* Builds a pretty ASCII-formatted version of a $schema array.
*
* This is nothing more than a specialized variation of var_dump and
* similar functions and is used only as a convenience to generate the
* PHP for existing database tables (to bootstrap support for modules
* that previously used CREATE TABLE explicitly) and for debugging.
*/
function schema_phpprint($schema) {
$out = '';
foreach ($schema as $name => $table) {
$out .= schema_phpprint_table($name, $table);
}
return $out;
}
function schema_phpprint_table($name, $table) {
$cols = array();
if (isset($table['fields'])) {
foreach ($table['fields'] as $colname => $col) {
$cols[] = "'{$colname}' => " . schema_phpprint_column($col, TRUE);
}
}
$unique = $index = array();
if (isset($table['unique keys'])) {
foreach ($table['unique keys'] as $keyname => $key) {
$unique[] = "'{$keyname}' => " . schema_phpprint_key($key);
}
}
if (isset($table['indexes'])) {
foreach ($table['indexes'] as $keyname => $key) {
$index[] = "'{$keyname}' => " . schema_phpprint_key($key);
}
}
if ($table['description']) {
$description = $table['description'];
}
else {
$description = t('TODO: please describe this table!');
}
$out = '';
$out .= "\$schema['" . $name . "'] = array(\n";
$out .= " 'description' => '{$description}',\n";
$out .= " 'fields' => array(\n ";
$out .= implode(",\n ", $cols);
$out .= ",\n ),\n";
if (isset($table['primary key'])) {
$out .= " 'primary key' => array('" . implode("', '", $table['primary key']) . "'),\n";
}
if (count($unique) > 0) {
$out .= " 'unique keys' => array(\n ";
$out .= implode(",\n ", $unique);
$out .= "\n ),\n";
}
if (count($index) > 0) {
$out .= " 'indexes' => array(\n ";
$out .= implode(",\n ", $index);
$out .= ",\n ),\n";
}
$out .= ");\n";
return $out;
}
function schema_phpprint_column($col, $multiline = FALSE) {
$attrs = array();
$description = isset($col['description']) ? $col['description'] : '';
unset($col['description']);
$attrs[] = "'description' => '{$description}'";
if ($col['type'] == 'varchar' || $col['size'] == 'normal') {
unset($col['size']);
}
foreach (array(
'type',
'unsigned',
'size',
'length',
'not null',
'default',
) as $attr) {
if (isset($col[$attr])) {
if (is_string($col[$attr])) {
$attrs[] = "'{$attr}' => '{$col[$attr]}'";
}
elseif (is_bool($col[$attr])) {
$attrs[] = "'{$attr}' => " . ($col[$attr] ? 'TRUE' : 'FALSE');
}
else {
$attrs[] = "'{$attr}' => {$col[$attr]}";
}
unset($col[$attr]);
}
}
foreach (array_keys($col) as $attr) {
if (is_string($col[$attr])) {
$attrs[] = "'{$attr}' => '{$col[$attr]}'";
}
else {
$attrs[] = "'{$attr}' => {$col[$attr]}";
}
}
if ($multiline) {
return "array(\n " . implode(",\n ", $attrs) . ",\n )";
}
return "array(" . implode(', ', $attrs) . ")";
}
function schema_phpprint_key($keys) {
$ret = array();
foreach ($keys as $key) {
if (is_array($key)) {
$ret[] = "array('{$key[0]}', {$key[1]})";
}
else {
$ret[] = "'{$key}'";
}
}
return "array(" . implode(", ", $ret) . ")";
}
//////////////////////////////////////////////////////////////////////
// Schema comparison functions
//////////////////////////////////////////////////////////////////////
/**
* Unprefix a table name.
*
* This is pretty much the converse of DatabaseConnection::prefixTables().
*
* @param string $name
* The prefixed table name.
* @param DatabaseConnection $connection
* An optional database connection object.
*
* @return string
* The unprefixed table name.
*/
function schema_unprefix_table($name, $connection = NULL) {
$prefixes =& drupal_static(__FUNCTION__, array());
if (!isset($connection)) {
$connection = Database::getConnection();
}
$key = $connection
->getKey();
if (!isset($prefixes[$key])) {
$prefixes[$key] = array();
$info = $connection
->getConnectionOptions();
if (isset($info['prefix'])) {
if (is_array($info['prefix'])) {
$info['prefix'] = $info['prefix'] + array(
'default' => '',
);
}
else {
$info['prefix'] = array(
'default' => $info['prefix'],
);
}
foreach ($info['prefix'] as $table => $prefix) {
if ($table != 'default') {
$prefixes[$key][$prefix . $table] = $table;
}
elseif ($prefix !== '') {
$prefixes[$key][$prefix] = '';
}
}
}
}
return !empty($prefixes[$key]) ? strtr($name, $prefixes[$key]) : $name;
}
/**
* Converts a column's Schema type into an engine-specific data type.
*/
function schema_engine_type($col, $table, $field, $engine = NULL) {
$map = schema_dbobject()
->getFieldTypeMap();
$size = isset($col['size']) ? $col['size'] : 'normal';
$type = $col['type'] . ':' . $size;
if (isset($map[$type])) {
return $map[$type];
}
else {
trigger_error(t('@table.@field: no @engine type for schema type @type.', array(
'@engine' => $engine,
'@type' => $type,
'@table' => $table,
'@field' => $field,
)), E_USER_WARNING);
return $col['type'];
}
}
/**
* Convert an engine-specific data type into a Schema type.
*/
function schema_schema_type($type, $table, $field, $engine = NULL) {
$map = schema_dbobject()
->schema_type_map();
$type = strtolower($type);
if (isset($map[$type])) {
return explode(':', $map[$type]);
}
else {
if (!\Drupal::config('schema.settings')
->get('schema_suppress_type_warnings')) {
trigger_error(t('@table.@field: no schema type for @engine type @type.', array(
'@engine' => $engine,
'@type' => $type,
'@table' => $table,
'@field' => $field,
)), E_USER_WARNING);
}
return array(
$type,
'normal',
);
}
}
/**
* Compares two complete schemas.
* @param $ref array is considered the reference copy
* @param $inspect array is compared against it. If $inspect is NULL, a
* schema for the active database is generated and used.
*
* @deprecated
*/
function schema_compare_schemas($ref, $inspect = NULL) {
if (!isset($inspect)) {
$inspect = schema_dbobject()
->inspect();
}
$comparator = new SchemaComparator($ref, schema_dbobject());
$result = $comparator
->execute();
$result = new SchemaComparisonInfoBuilder($result);
return $result
->getInfoArray();
}
/**
* Compares a reference specification (such as one returned by a
* module's hook_schema) to an inspected specification from the
* database.
* @param $inspect if not provided, the database is inspected.
*
* @deprecated
*/
function schema_compare_table($ref, $inspect = NULL) {
return;
// @todo Refactor SchemaComparator and call from this function.
$_db_type = db_driver();
if (!isset($inspect)) {
// TODO: Handle prefixing the D7 way
// $ref_name = db_prefix_tables('{' . $ref['name'] . '}');
$ref_name = $ref['name'];
$inspect = schema_dbobject()
->inspect(NULL, $ref_name);
$inspect = $inspect[$ref['name']];
}
if (!isset($inspect)) {
return array(
'status' => 'missing',
);
}
// Removed comparison code; most of it now resides in
// SchemaComparator::compareTable().
}
/**
* Computes and returns the complete schema for all the drupal things.
*/
function schema_get_schema($rebuild = FALSE) {
/** @var SchemaManager $manager */
$manager = Drupal::service('plugin.manager.schema');
$plugins = $manager
->createInstances();
$complete_schema = array();
/** @var SchemaProviderInterface $plugin */
foreach ($plugins as $plugin) {
$complete_schema += $plugin
->get($rebuild);
}
return $complete_schema;
}
Functions
Name | Description |
---|---|
schema_compare_schemas | Compares two complete schemas. |
schema_compare_table | Compares a reference specification (such as one returned by a module's hook_schema) to an inspected specification from the database. |
schema_dbobject | Fetch a schema engine class instance for a given database connection. |
schema_engine_type | Converts a column's Schema type into an engine-specific data type. |
schema_get_connection_engine_class | Fetch the schema engine class name for a given database connection. |
schema_get_connection_options | Get an array of connection options that are supported by schema inspection. |
schema_get_schema | Computes and returns the complete schema for all the drupal things. |
schema_help | Implements hooK_help(). |
schema_phpprint | Builds a pretty ASCII-formatted version of a $schema array. |
schema_phpprint_column | |
schema_phpprint_key | |
schema_phpprint_table | |
schema_schema_type | Convert an engine-specific data type into a Schema type. |
schema_unprefix_table | Unprefix a table name. |