Drupal的注册表是指registry和registry_file两个数据表。前一个表保存所有可用的类和接口以及它们所对应的文件,后一个表保存每个文件的hash码。
1. 将所有需要更新的文件都汇总的$files数组:
// 需要更新的文件有两部分:一是系统includes目录下所有的.inc文件,二是模块描述文件中通过files属性声明的文件。 $files = array(); $modules = db_query("SELECT * FROM {system} WHERE type = 'module'")->fetchAll(); foreach ($modules as &$module) { $module->info = unserialize($module->info); $dir = dirname($module->filename); $module->dir = $dir; if ($module->status) { foreach ($module->info['files'] as $file) { $files["$dir/$file"] = array('module' => $module->name, 'weight' => $module->weight); } } } foreach (file_scan_directory('includes', '/\.inc$/') as $filename => $file) { $files["$filename"] = array('module' => '', 'weight' => 0); }
2. 更新$files数组的hash属性:
foreach (db_query("SELECT * FROM {registry_file}")->fetchAllAssoc('filename', PDO::FETCH_ASSOC) as $filename => $file) { // Add the hash for those files we have already parsed. if (isset($files[$filename])) { $files[$filename]['hash'] = $file['hash']; } else { // Flush the registry of resources in files that are no longer on disc // or are in files that no installed modules require to be parsed. db_delete('registry') ->condition('filename', $filename) ->execute(); db_delete('registry_file') ->condition('filename', $filename) ->execute(); } }
3. 更新registry和registry_file表:
$parsed_files = array(); // 重新计算每个文件的Hash码 foreach ($files as $filename => $file) { if (file_exists($filename)) { $hash = hash_file('sha256', $filename); if (empty($file['hash']) || $file['hash'] != $hash) { $file['hash'] = $hash; $parsed_files[$filename] = $file; } } } foreach ($parsed_files as $filename => $file) { // 搜索文件中的类和接口 if (preg_match_all('/^\s*(?:abstract|final)?\s*(class|interface)\s+([a-zA-Z0-9_]+)/m', file_get_contents($filename), $matches)) { foreach ($matches[2] as $key => $name) { // 将类和接口名称更新到registry表 db_merge('registry') ->key(array( 'name' => $name, 'type' => $matches[1][$key], )) ->fields(array( 'filename' => $filename, 'module' => $module, 'weight' => $weight, )) ->execute(); } // Delete any resources for this file where the name is not in the list // we just merged in. db_delete('registry') ->condition('filename', $filename) ->condition('name', $matches[2], 'NOT IN') ->execute(); } // 更新registry_file表 db_merge('registry_file') ->key(array('filename' => $filename)) ->fields(array( 'hash' => $file['hash'], )) ->execute(); }
所以,模块安装时,让Drupal自动更新注册表的关键是要在.info文件中注明files属性。例如,comment模块的.info文件就是这样写的:
name = Comment description = Allows users to comment on and discuss published content. package = Core version = VERSION core = 7.x dependencies[] = text files[] = comment.module files[] = comment.test configure = admin/content/comment stylesheets[all][] = comment.css