Передача запроса в module_hook, который использует вторую базу данных - PullRequest
0 голосов
/ 29 декабря 2018

Я хотел бы использовать другое соединение с базой данных, которое запрашивает базу данных, используя хук в моем собственном модуле, называемом «соединитель».Этот хук должен принимать параметр, который является запросом, который должен быть выполнен с использованием вторичной базы данных, прежде чем он переключится обратно на первичную 7-базу данных Drupal.Кажется, проблема в том, что запрос каким-то образом генерируется для (основной) базы данных Drupal (как он был создан до перехода на вторичную базу данных), даже если сам SQL выглядит хорошо для меня.Что я тут не так делаю?

Hook:

<code>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 "
"; db_set_active (); // без значения параметра paramater, установленного по умолчанию для сайта drupal_set_message (t ('Запросы былиmade. ')); вернуть $ 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 &#039;drupal.registration&#039; doesn&#039;t exist: SELECT registration.* FROM {registration} registration WHERE (id = :db_condition_placeholder_0) ; Array ( [:db_condition_placeholder_0] =&gt; 46 ) in connector_api_db() (line 70 of /<path-to-drupal>/drupal-7.61/modules/connector/connector.main.inc).

Ответы [ 2 ]

0 голосов
/ 30 декабря 2018

Для дальнейшего использования, это то, что я придумал (включая биты кэширования):

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;

}
0 голосов
/ 29 декабря 2018

Это, строго говоря, не ответ, а скорее предложение.

Дело в том, что ваш хук получает $query, уже построенный с исходным подключением к базе данных, это объясняетошибки.Чтобы быть эффективным, db_set_active() должен вызываться перед вызовом конструктора запросов.

В противном случае вам придется переопределить конструкторы как для класса 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(), и позволяет реализации свободно выполнять и извлекать результаты по мере необходимости.

...