É possível conectar ao evento variable_set ()?

8

Gostaria de acompanhar o evento de alterações do sistema, para torná-las reversíveis. Ao verificar variable_set (), vejo que não há gancho fornecido para esse evento. Existe alguma maneira de eu fazer isso?

Eu posso alterar para ligar aos formulários de configurações, mas há muitas configurações para rastrear; se eu posso conectar diretamente ao variable_set (), o código se torna muito mais simples.

Também posso rastrear as alterações de variáveis ​​com os recursos + módulos strongarm, mas é melhor se o administrador do Drupal puder navegar no histórico de variáveis ​​sem tocar no código.

Andy Truong
fonte

Respostas:

11

Parece que é impossível usar apenas o Drupal, o que significa:

variable_set()em si não chama nenhum gancho, mas usa db_merge(). Essa função está usando a MergeQueryclasse Agora, seria bom ligar hook_query_alter(), mas ele só funciona para classes de consulta que implementam a QueryAlterableInterfaceinterface. Infelizmente, esta interface é agora implementado apenas pelos SelectQuerye as SelectQueryExtenderaulas, e não pela MergeQueryclasse.

Observe que, mesmo que você encontre uma maneira de criar uma classe filho MergeQuery, isso será implementado QueryAlterableInterfacee fará com que o Drupal a use. hook_query_alter()funciona apenas em consultas que possuem tags e variable_set()não codifica sua consulta; portanto, o gancho não seria usado de qualquer maneira, a menos que você esteja disposto a invadir o núcleo. Mas se você é, não precisa de tudo isso, você pode simplesmente fazer uma chamada de gancho.

Se você se sente incondicional, pode usar uma abordagem PHP mais indireta: $confé uma matriz global de variáveis ​​de configuração; você pode escrever um módulo que o substitua por um objeto que age como uma matriz, conforme descrito em Estouro de pilha . Para torná-lo um bom substituto, você precisa implementar ArrayAccess. Puxe todos os valores do original $confpara o seu objeto. Em seguida, ArrayAccess::offsetSet()implemente sua lógica de log.

Mołot
fonte
Esqueci-me dessa resposta antiga e já descobri como fazer praticamente qualquer coisa $confna época: D Espero que minha resposta atualizada ajude alguém.
Mołot
Estou impressionado! : D
Letharion
@Letharion Obrigado :) Era uma vez eu gostei "objeto agindo como ..." mágica em PHP, e ainda me lembro um pouco sobre isso;)
MOLOT
6

Você pode usar um gatilho de banco de dados, que seria mais rápido que o código.

Aqui está o documento do MySQL .

  1. crie uma tabela para armazenar valores antigos

    CREATE TABLE variable_backup
    (
        name varchar(128) not null,
        value longblob,
        updated datetime not null,
        primary key (name, updated)
    );
  2. crie seus gatilhos, um para inserção e outro para atualização:

    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());

Agora todas as suas atualizações e inserções registrarão valores antigos em variable_backup.

Scott Joudry
fonte
Eu gosto, puro e simples. Provavelmente mais rápido que o meu método também. Mais limitado, mas o suficiente para fazer o que o OP precisa, se ele tiver acesso suficiente ao MySQL.
Mołot
Eu gosto desse jeito. Mas eu acho que nós precisamos para rastrear informações do agente do usuário também
Andy Truong
Duvido que as informações estariam disponíveis para o banco de dados.
10138 Scott Joudry #
@AndyTruong essa informação não estará no banco de dados, desculpe. Tentei olhar em volta, mas é impossível adivinhar com dados na tabela de sessões, e apenas as consultas selecionadas são alteráveis, portanto não há como adicioná-las. Então, meu método "hardcore" está aí para você. Espero que você tenha conseguido implementá-lo, se não - faça uma nova pergunta relacionada a ele e comente que você o fez.
Mołot
5

Como você pode ver no código fonte, variable_set()não solicita ganchos ou alterações, por exemplo, não module_invoke_all()ou drupal_alter()liga para lá.

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;
}

No entanto, você pode ouvir a db_merge()consulta com um local especialmente colocado hook_query_alter()e fazer algum processamento adicional, mas, como apontado por Molot, hook_query_alter()parece improvável que seja capaz de direcionar a db_merge()consulta.

Como alternativa, talvez você possa agendar uma captura instantânea da tabela de variáveis ​​para diferenciá-la das revisões anteriores dessa tabela ou implementar outra forma de armazenamento de revisão de variáveis ​​para comparar.

David Thomas
fonte
11
Se hook_query_alter puder ser usado nessa consulta, eu adoraria ver como. Em 8 QueryAlterableInterfaceé realmente implementado por Querysi só. Porém, em 8 configurações, o gerenciamento é reconstruído de qualquer maneira. E em 7, apenas as consultas de seleção marcadas são alteráveis ​​até onde eu vejo. Mas talvez eu esteja perdendo alguma coisa?
Mołot 30/09
11
Não, você está correto, hook_query_alter era um palpite, mas não é viável no D7 nesse caso, obrigado.
David Thomas
0

Abri um tíquete de solicitação de recurso no Drupal.org para criar ganchos para interceptar a configuração e a exclusão de variáveis ​​do sistema e enviei para revisão um patch principal para isso! Por favor, veja:

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

Eric Jenkins
fonte