我想使用另一个数据库连接,该连接使用我自己的名为“连接器”的模块中的钩子查询数据库。该钩子应带有一个查询参数,该参数将在切换回主Drupal 7数据库之前使用辅助数据库执行。问题似乎是,查询是针对(主要的)Drupal数据库生成的(因为它是在切换到辅助数据库之前创建的),即使SQL本身对我来说看起来很好。我在这里做什么错了?
挂钩:
function connector_api_db($query) {
$result = [];
$database_info = array(
'database' => variable_get('connector_db_name'),
'username' => variable_get('connector_db_user'),
'password' => variable_get('connector_db_pwd'),
'host' => variable_get('connector_db_host'),
'driver' => 'mysql',
);
Database::addConnectionInfo('secondary_db', 'default', $database_info);
db_set_active('secondary_db'); // Initialize the connection
/* This actually works but I can here not use my own query as a parameter in this function. Not what I want. */
//$query = db_select('registration')->fields('registration')
//->condition('id', 46, '=');
echo $query->__toString() . "<br />"; /* Get query string */
var_dump($query->getArguments()); /* Get the arguments passed to the string */
$result = $query->execute()->fetchAssoc();
echo "<pre>";
print_r($result);
echo "</pre>";
db_set_active(); // without the paramater means set back to the default for the site
drupal_set_message(t('The queries have been made.'));
return $result;
}
调用该钩子:
$query = db_select('registration')
->fields('registration')
->condition('id', 46, '=');
$response = module_invoke('connector', 'api_db', $query);
结果如下:
SELECT registration.* FROM {registration} registration WHERE (id = :db_condition_placeholder_0)
array(1) { [":db_condition_placeholder_0"]=> int(46) }
Additional uncaught exception thrown while handling exception.
Original
PDOException: SQLSTATE[42S02]: Base table or view not found: 1146 Table 'drupal.registration' doesn't exist: SELECT registration.* FROM {registration} registration WHERE (id = :db_condition_placeholder_0) ; Array ( [:db_condition_placeholder_0] => 46 ) in connector_api_db() (line 70 of /<path-to-drupal>/drupal-7.61/modules/connector/connector.main.inc).
答案 0 :(得分:1)
严格来讲,这不是答案,而是建议。
问题是您的钩子收到一个已经用原始数据库连接构建的$query
,这说明了错误。为了有效,db_set_active()
应该在调用Query构造函数之前先 调用。
否则,您将必须同时覆盖 Select 类及其父类 Query 的构造函数,或更确切地说,是“重建” Select语句的“查询”构建器实例(如果需要范围查询等,也可能是其他)。
此外,除非有明确的要求在这种情况下提供专用挂钩,否则没有必要。
例如,执行以下操作会更简单:
connector.module :
/**
* Implements hook_init()
*
* Adds secondary database connection information.
*/
function connector_init() {
$database_info = array(
'database' => variable_get('connector_db_name'),
'username' => variable_get('connector_db_user'),
'password' => variable_get('connector_db_pwd'),
'host' => variable_get('connector_db_host'),
'driver' => 'mysql',
);
Database::addConnectionInfo('secondary_db', 'default', $database_info);
}
/**
* Switches from primary to secondary database and the other way round.
*/
function connector_switch_db($db_key = 'secondary_db') {
return db_set_active($db_key);
}
示例:
// Set secondary db active.
$primary_db_key = connector_switch_db();
$query = db_select('registration')
->fields('registration')
->condition('id', 46, '=');
$result = $query->execute()->fetchAssoc();
// Switch back to the primary database.
connector_switch_db($primary_db_key);
这种较软的方法还可以防止使用(...)->execute()->fetchAssoc()
之类的硬代码,并允许实现自由执行并根据需要获取结果。
答案 1 :(得分:1)
这是我想出的(包括缓存位)供以后参考:
function connector_init() {
foreach([
'connector_db_host',
'connector_db_name',
'connector_db_user',
'connector_db_pwd',
] as $var) {
drupal_static($var, variable_get($var, ''));
}
Database::addConnectionInfo('secondary_db', 'default', [
'host' => drupal_static('connector_db_host'),
'database' => drupal_static('connector_db_name'),
'username' => drupal_static('connector_db_user'),
'password' => drupal_static('connector_db_pwd'),
'driver' => 'mysql',
]);
}
function connector_api_db($query) {
$result = [];
$sql_query = $query->__toString();
$arguments = $query->getArguments();
if (count($arguments) > 0) {
ksort($arguments);
}
$cache_id = 'sql_' . md5($sql_query . '|' . print_r($arguments, 1));
$cache = cache_get($cache_id, 'cache_connector');
if ($cache && $cache->expire >= time()) {
$result = $cache->data;
} else {
db_set_active('secondary_db'); // Switch to secondary db */
$query_failed = FALSE;
try {
$db_result = db_query($sql_query, $arguments);
$db_result = (0 === $db_result->rowCount()) ? [] : $db_result->fetchAssoc();
} catch (\PDOException $e) {
$db_result = [];
$query_failed = TRUE;
} finally {
db_set_active(); /* switch back to default */
}
$result = (object)[
'query' => $sql_query,
'arguments' => $arguments,
'result' => (object)$db_result
];
if (!$query_failed) {
cache_set($cache_id, $result, 'cache_connector', strtotime('+10 minutes'));
}
}
return $result;
}