是否可以挂钩到variable_set()事件?


8

我想跟踪系统更改事件,使其可恢复。当检查variable_set()时,我看到没有为该事件提供钩子。有什么办法可以做到吗?

我可以更改以挂钩到设置表格,但是要跟踪很多设置表格,如果我可以直接挂钩到variable_set(),则代码将变得更加简单。

我还可以使用功能+ Strongarm模块跟踪变量的更改,但是最好是Drupal管理员可以浏览变量历史记录而无需触摸代码。

Answers:


11

似乎仅使用Drupal是不可能的,这意味着:

variable_set()本身不会调用任何钩子,但会使用db_merge()。该函数正在使用MergeQuery该类。现在,很高兴与挂钩hook_query_alter(),但是它仅适用于实现该QueryAlterableInterface接口的查询类。遗憾的是,此接口现在仅由SelectQuerySelectQueryExtender类实现,而不是由MergeQuery类实现。

请注意,即使您找到创建的子类的方法MergeQuery,该方法也将实现QueryAlterableInterface,并使Drupal使用它。hook_query_alter()仅适用于具有标签的查询,并且variable_set()不为其查询添加标签,因此,除非您愿意破解内核,否则无论如何都不会使用该挂钩。但是,如果您需要的话,则不需要所有这些,您可以简单地进行挂接调用。

如果您感觉很顽固,则可以使用更间接的PHP方法:$conf配置变量的全局数组;您可以编写一个模块,将其替换为类似于数组的对象,如Stack Overflow所述。要使其成为一个好的替代品,您需要实施ArrayAccess。将所有值从原始值拉$conf入对象。然后,ArrayAccess::offsetSet()实现您的日志记录逻辑。


我忘记了我的这个旧答案,那时我已经找到了如何做几乎所有事情的方法$conf:D希望我更新的答案能对某人有所帮助。
Mołot

我印象深刻!:D
Letharion

@Letharion谢谢:)很久以前,我喜欢PHP中的“对象充当...”魔术,但我至今仍对此记忆犹新;)
Mołot2013年

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中记录旧值。


我喜欢它,简洁明了。大概也比我的方法快。如果他具有足够的MySQL访问权限,则权限比较有限,但足以执行OP所需的操作。
Mołot

我喜欢这样 但我认为,我们需要太多跟踪用户代理信息
安迪·特鲁

我怀疑该信息是否可用于数据库。
Scott Joudry

@AndyTruong信息将不在数据库中,对不起。我试图环顾四周,但无法通过会话表中的数据来猜测它,并且只有选择查询是可变的,因此无法添加它。因此,您可以使用我的“硬核”方法。希望您成功实现了它,如果没有实现,请提出一个新的问题链接,并评论您这样做。
Mołot

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()那里进行一些其他处理,但是,正如Molot指出的那样,hook_query_alter()看起来不太可能以db_merge()查询为目标。

或者,您可以cron快照变量表以将其与该表的先前修订版进行比较,或者实现其他形式的变量修订版存储以进行比较。


1
如果hook_query_alter可以在此查询上使用,我很想看看如何。in 8 QueryAlterableInterface确实是由Query自己实现的。但是无论如何,在8配置中都将重建管理。据我所知,只有7个带标签的选择查询是可更改的。但是也许我想念什么?
Mołot

1
不,您是正确的,hook_query_alter是一个猜测,但在这种情况下在D7中不可行,谢谢。
大卫·托马斯

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.