1<?php 2 3/** 4 * @file 5 * Schema API handling functions. 6 */ 7 8use Drupal\Core\Entity\Sql\SqlContentEntityStorageSchema; 9 10/** 11 * @addtogroup schemaapi 12 * @{ 13 */ 14 15/** 16 * Indicates that a module has not been installed yet. 17 */ 18const SCHEMA_UNINSTALLED = -1; 19 20/** 21 * Returns an array of available schema versions for a module. 22 * 23 * @param string $module 24 * A module name. 25 * 26 * @return array|bool 27 * If the module has updates, an array of available updates sorted by 28 * version. Otherwise, FALSE. 29 */ 30function drupal_get_schema_versions($module) { 31 $updates = &drupal_static(__FUNCTION__, NULL); 32 if (!isset($updates[$module])) { 33 $updates = []; 34 foreach (\Drupal::moduleHandler()->getModuleList() as $loaded_module => $filename) { 35 $updates[$loaded_module] = []; 36 } 37 38 // Prepare regular expression to match all possible defined hook_update_N(). 39 $regexp = '/^(?<module>.+)_update_(?<version>\d+)$/'; 40 $functions = get_defined_functions(); 41 // Narrow this down to functions ending with an integer, since all 42 // hook_update_N() functions end this way, and there are other 43 // possible functions which match '_update_'. We use preg_grep() here 44 // instead of foreaching through all defined functions, since the loop 45 // through all PHP functions can take significant page execution time 46 // and this function is called on every administrative page via 47 // system_requirements(). 48 foreach (preg_grep('/_\d+$/', $functions['user']) as $function) { 49 // If this function is a module update function, add it to the list of 50 // module updates. 51 if (preg_match($regexp, $function, $matches)) { 52 $updates[$matches['module']][] = $matches['version']; 53 } 54 } 55 // Ensure that updates are applied in numerical order. 56 foreach ($updates as &$module_updates) { 57 sort($module_updates, SORT_NUMERIC); 58 } 59 } 60 return empty($updates[$module]) ? FALSE : $updates[$module]; 61} 62 63/** 64 * Returns the currently installed schema version for a module. 65 * 66 * @param string $module 67 * A module name. 68 * @param bool $reset 69 * Set to TRUE after installing or uninstalling an extension. 70 * @param bool $array 71 * Set to TRUE if you want to get information about all modules in the 72 * system. 73 * 74 * @return string|int 75 * The currently installed schema version, or SCHEMA_UNINSTALLED if the 76 * module is not installed. 77 */ 78function drupal_get_installed_schema_version($module, $reset = FALSE, $array = FALSE) { 79 $versions = &drupal_static(__FUNCTION__, []); 80 81 if ($reset) { 82 $versions = []; 83 } 84 85 if (!$versions) { 86 if (!$versions = \Drupal::keyValue('system.schema')->getAll()) { 87 $versions = []; 88 } 89 } 90 91 if ($array) { 92 return $versions; 93 } 94 else { 95 return isset($versions[$module]) ? $versions[$module] : SCHEMA_UNINSTALLED; 96 } 97} 98 99/** 100 * Updates the installed version information for a module. 101 * 102 * @param string $module 103 * A module name. 104 * @param string $version 105 * The new schema version. 106 */ 107function drupal_set_installed_schema_version($module, $version) { 108 \Drupal::keyValue('system.schema')->set($module, $version); 109 // Reset the static cache of module schema versions. 110 drupal_get_installed_schema_version(NULL, TRUE); 111} 112 113/** 114 * Creates all tables defined in a module's hook_schema(). 115 * 116 * @param string $module 117 * The module for which the tables will be created. 118 */ 119function drupal_install_schema($module) { 120 $schema = drupal_get_module_schema($module); 121 _drupal_schema_initialize($schema, $module, FALSE); 122 123 foreach ($schema as $name => $table) { 124 \Drupal::database()->schema()->createTable($name, $table); 125 } 126} 127 128/** 129 * Removes all tables defined in a module's hook_schema(). 130 * 131 * @param string $module 132 * The module for which the tables will be removed. 133 */ 134function drupal_uninstall_schema($module) { 135 $tables = drupal_get_module_schema($module); 136 _drupal_schema_initialize($tables, $module, FALSE); 137 $schema = \Drupal::database()->schema(); 138 foreach ($tables as $table) { 139 if ($schema->tableExists($table['name'])) { 140 $schema->dropTable($table['name']); 141 } 142 } 143} 144 145/** 146 * Returns a module's schema. 147 * 148 * This function can be used to retrieve a schema specification in 149 * hook_schema(), so it allows you to derive your tables from existing 150 * specifications. 151 * 152 * @param string $module 153 * The module to which the table belongs. 154 * @param string $table 155 * The name of the table. If not given, the module's complete schema 156 * is returned. 157 */ 158function drupal_get_module_schema($module, $table = NULL) { 159 // Load the .install file to get hook_schema. 160 module_load_install($module); 161 $schema = \Drupal::moduleHandler()->invoke($module, 'schema'); 162 163 if (isset($table)) { 164 if (isset($schema[$table])) { 165 return $schema[$table]; 166 } 167 return []; 168 } 169 elseif (!empty($schema)) { 170 return $schema; 171 } 172 return []; 173} 174 175/** 176 * Fills in required default values for table definitions from hook_schema(). 177 * 178 * @param array $schema 179 * The schema definition array as it was returned by the module's 180 * hook_schema(). 181 * @param string $module 182 * The module for which hook_schema() was invoked. 183 * @param bool $remove_descriptions 184 * (optional) Whether to additionally remove 'description' keys of all tables 185 * and fields to improve performance of serialize() and unserialize(). 186 * Defaults to TRUE. 187 */ 188function _drupal_schema_initialize(&$schema, $module, $remove_descriptions = TRUE) { 189 // Set the name and module key for all tables. 190 foreach ($schema as $name => &$table) { 191 if (empty($table['module'])) { 192 $table['module'] = $module; 193 } 194 if (!isset($table['name'])) { 195 $table['name'] = $name; 196 } 197 if ($remove_descriptions) { 198 unset($table['description']); 199 foreach ($table['fields'] as &$field) { 200 unset($field['description']); 201 } 202 } 203 } 204} 205 206/** 207 * Typecasts values to proper data types. 208 * 209 * MySQL PDO silently casts, e.g. FALSE and '' to 0, when inserting the value 210 * into an integer column, but PostgreSQL PDO does not. Look up the schema 211 * information and use that to correctly typecast the value. 212 * 213 * @param array $info 214 * An array describing the schema field info. 215 * @param mixed $value 216 * The value to be converted. 217 * 218 * @return mixed 219 * The converted value. 220 * 221 * @deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Use 222 * \Drupal\Core\Entity\Sql\SqlContentEntityStorageSchema::castValue() instead. 223 * 224 * @see https://www.drupal.org/node/3051983 225 */ 226function drupal_schema_get_field_value(array $info, $value) { 227 @trigger_error('drupal_schema_get_field_value() is deprecated in drupal:8.8.0. It will be removed from drupal:9.0.0. Use \Drupal\Core\Entity\Sql\SqlContentEntityStorageSchema::castValue($info, $value) instead. See https://www.drupal.org/node/3051983', E_USER_DEPRECATED); 228 return SqlContentEntityStorageSchema::castValue($info, $value); 229} 230 231/** 232 * @} End of "addtogroup schemaapi". 233 */ 234