Можно ли подключиться к событию variable_set ()?

8

Я хотел бы отследить событие системных изменений, чтобы сделать их обратимыми. При проверке variable_set () я вижу, что для этого события не предусмотрена ловушка. Есть ли способ для меня сделать это?

Я могу изменить привязку к формам настроек, но есть множество форм настроек для отслеживания, если я могу напрямую подключиться к variable_set (), код станет намного проще.

Я также могу отслеживать изменения переменных с помощью модулей features + strongarm, но лучше, если администратор Drupal сможет просматривать историю переменных без касания кода.

Энди Труонг
источник

Ответы:

11

Кажется, что невозможно использовать только Drupal, что означает:

variable_set()Сам по себе не вызывает никаких хуков, но использует db_merge(). Эта функция использует MergeQueryкласс. Теперь было бы неплохо подключиться hook_query_alter(), но это работает только для классов запросов, которые реализуют QueryAlterableInterfaceинтерфейс. К сожалению, этот интерфейс теперь реализован только с помощью SelectQueryи в SelectQueryExtenderклассах, а не в MergeQueryклассе.

Обратите внимание, что даже если вы найдете способ создать дочерний класс MergeQuery, который реализует QueryAlterableInterfaceи заставит его использовать Drupal. hook_query_alter()работает только с запросами, которые имеют теги, и variable_set()не помечает его запрос, поэтому ловушка не будет использоваться в любом случае, если вы не захотите взломать ядро. Но если вам это нужно, вам не нужно все это, вы можете просто взломать вызов.

Если вы чувствуете хардкор, вы можете использовать более косвенный подход PHP: $confэто глобальный массив переменных конфигурации; Вы можете написать модуль, который заменит его объектом, действующим как массив, как описано в Переполнении стека . Чтобы сделать его хорошей заменой, вам нужно реализовать ArrayAccess. Вытащите все значения из оригинала $confв ваш объект. Затем ArrayAccess::offsetSet()внедрите свою логику регистрации.

МОЛОТ
источник
Я забыл об этом$conf своем старом ответе и уже нашел, как сделать с ним что- то еще: D Надеюсь, мой обновленный ответ кому-нибудь поможет.
Молот
Я впечатлен! : D
Летарион
@Letharion Спасибо :) Когда-то мне нравилась магия "объект, действующий как ..." в PHP, и я до сих пор немного об этом помню;)
Mołot
6

Вы можете использовать триггер базы данных, который будет быстрее, чем код.

Вот документация по MySQL .

  1. создать таблицу для хранения старых значений

    CREATE TABLE variable_backup
    (
        name varchar(128) not null,
        value longblob,
        updated datetime not null,
        primary key (name, updated)
    );
  2. создайте свои триггеры, один для вставки и один для обновления:

    CREATE TRIGGER backup_variable_update BEFORE UPDATE ON variable
        FOR EACH ROW
            INSERT INTO variable_backup (name, value, type, updated) VALUES (OLD.name, OLD.value, "update", NOW());
    
    CREATE TRIGGER backup_variable_insert BEFORE INSERT ON variable
        FOR EACH ROW
            INSERT INTO variable_backup (name, value, type, updated) VALUES (NEW.name, NEW.value, "insert", NOW());

Теперь все ваши обновления и вставки будут записывать старые значения в variable_backup.

Скотт Джудри
источник
Мне нравится, аккуратно и просто. Наверное, быстрее, чем мой метод тоже. Более ограниченный, но достаточно, чтобы сделать то, что нужно OP, если он имеет достаточный доступ к MySQL.
Молот
Мне нравится этот способ. Но я думаю, что нам также нужно отслеживать информацию о пользовательских агентах
Энди Труонг
Я сомневаюсь, что информация будет доступна для базы данных.
Скотт Джудри
@ AndyTruong этой информации не будет в базе данных, извините. Я попытался осмотреться, но невозможно угадать это с данными в таблице сеансов, и только выборочные запросы могут быть изменены, поэтому нет способа добавить их. Так что мой "хардкорный" метод для вас. Надеюсь, у вас был успех в его реализации, если нет - задайте новый вопрос, ссылающийся на него, и прокомментируйте, что вы это сделали.
Молот
5

Как вы можете видеть в исходном коде, variable_set()не запрашивает хуки или изменения, например, нет module_invoke_all()или drupal_alter()звонки туда.

function variable_set($name, $value) {
  global $conf;

  db_merge('variable')->key(array('name' => $name))->fields(array('value' => serialize($value)))->execute();

  cache_clear_all('variables', 'cache_bootstrap');

  $conf[$name] = $value;
}

Тем не менее, вы можете прослушать db_merge()запрос в специально размещенном месте hook_query_alter()и выполнить некоторую дополнительную обработку, но, как указал Молот, hook_query_alter()вряд ли удастся нацелиться на db_merge()запрос.

В качестве альтернативы, вы можете сделать снимок таблицы переменных cron, чтобы сравнить ее с предыдущими ревизиями этой таблицы, или реализовать какую-либо другую форму хранения ревизий переменных для сравнения.

Дэвид Томас
источник
1
Если в этом запросе можно использовать hook_query_alter, я бы хотел посмотреть, как это сделать. В 8 QueryAlterableInterfaceдействительно реализовано Queryсамо собой. Но в 8 управление конфигурацией все равно перестраивается. И в 7 только помеченные запросы выбора изменяются, насколько я вижу. Но может я что-то упустил?
Молот
1
Нет, вы правы, hook_query_alter был догадкой, но в этом случае в D7 это было невозможно, спасибо.
Дэвид Томас
0

Я открыл тикет Feature Request на Drupal.org, чтобы создать перехватчики для перехвата установки и удаления системных переменных, и я отправил на проверку основной патч для этого! Посмотри пожалуйста:

https://www.drupal.org/project/drupal/issues/2934718

Эрик Дженкинс
источник