Est-il possible de se connecter à l'événement variable_set ()?


8

Je voudrais suivre l'événement des modifications du système, pour les rendre réversibles. Lors de la vérification de variable_set (), je vois qu'il n'y a pas de hook fourni pour cet événement. Y a-t-il un moyen pour moi de faire ça?

Je peux modifier pour accrocher aux formulaires de paramètres, mais il y a beaucoup de formulaires de paramètres à suivre, si je peux accrocher directement à variable_set (), le code devient beaucoup plus simple.

Je peux également suivre les changements de variables avec les fonctionnalités + modules Strongarm, mais il est préférable que l'administrateur Drupal puisse parcourir l'historique des variables sans toucher au code.

Réponses:


11

Il semble impossible d'utiliser uniquement Drupal, ce qui signifie:

variable_set()lui-même n'invoque aucun crochet, mais il utilise db_merge(). Cette fonction utilise la MergeQueryclasse. Maintenant, ce serait bien de s'y accrocher hook_query_alter(), mais cela ne fonctionne que pour les classes de requête qui implémentent l' QueryAlterableInterfaceinterface. Malheureusement, cette interface n'est désormais implémentée que par SelectQueryles SelectQueryExtenderclasses et et non par la MergeQueryclasse.

Notez que même si vous trouverez un moyen de créer une classe enfant de MergeQuery, cela implémentera QueryAlterableInterfaceet fera utiliser Drupal. hook_query_alter()ne fonctionne que sur les requêtes qui ont des balises, et variable_set()ne marque pas sa requête, donc le hook ne sera pas utilisé de toute façon, sauf si vous êtes prêt à pirater le noyau. Mais si vous l'êtes, vous n'avez pas besoin de tout cela, vous pouvez simplement pirater un appel téléphonique.

Si vous vous sentez hardcore, vous pouvez utiliser une approche PHP plus indirecte: $confest un tableau global de variables de configuration; vous pouvez écrire un module qui le remplacera par un objet agissant comme un tableau, comme décrit dans Stack Overflow . Pour en faire un bon substitut, vous devez l'implémenter ArrayAccess. Tirez toutes les valeurs de l'original $confdans votre objet. Ensuite, ArrayAccess::offsetSet()implémentez votre logique de journalisation.


J'ai oublié ma vieille réponse et j'ai déjà trouvé comment faire à peu près n'importe quoi avec $conf: D J'espère que ma réponse mise à jour aidera quelqu'un.
Mołot

Je suis impressionné! : D
Letharion

@Letharion Merci :) Il était une fois la magie de "l'objet agissant comme ..." en PHP, et je m'en souviens encore un peu;)
Mołot

6

Vous pouvez utiliser un déclencheur de base de données, qui serait plus rapide que le code.

Voici le doc MySQL .

  1. créer une table pour stocker les anciennes valeurs

    CREATE TABLE variable_backup
    (
        name varchar(128) not null,
        value longblob,
        updated datetime not null,
        primary key (name, updated)
    );
    
  2. créez vos déclencheurs, un pour l'insertion et un pour la mise à jour:

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

Désormais, toutes vos mises à jour et insertions enregistreront les anciennes valeurs dans variable_backup.


J'aime ça, net et simple. Probablement plus rapide que ma méthode aussi. Plus limité, mais suffisant pour faire ce dont OP a besoin, s'il dispose d'un accès MySQL suffisant.
Mołot

J'aime cette façon. Mais je pense que nous devons également suivre les informations sur les agents utilisateurs
Andy Truong

Je doute que des informations soient disponibles dans la base de données.
Scott Joudry

@AndyTruong cette information ne sera pas dans la base de données, désolé. J'ai essayé de regarder autour, mais il est impossible de le deviner avec des données dans la table de session, et seules les requêtes sélectionnées sont modifiables, donc aucun moyen de les ajouter. Donc ma méthode "hardcore" est là pour vous. J'espère que vous avez réussi à le mettre en œuvre, si ce n'est pas le cas - posez une nouvelle question qui y est liée et commentez que vous l'avez fait.
Mołot

5

Comme vous pouvez le voir dans le code source, variable_set()ne fait aucune demande de hooks ou de modifications, par exemple non module_invoke_all()ou drupal_alter()y appelle.

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

Cependant, vous pourrez peut-être écouter la db_merge()requête avec un emplacement spécialement placé hook_query_alter()et y effectuer des traitements supplémentaires, mais, comme l'a souligné Molot, il hook_query_alter()semble peu probable de pouvoir cibler la db_merge()requête.

Alternativement, vous pouvez peut-être créer un instantané cron de la table de variables pour le comparer aux révisions précédentes de cette table, ou bien implémenter une autre forme de stockage de révision de variables pour comparer.


1
Si hook_query_alter peut être utilisé sur cette requête, j'aimerais voir comment. En 8 QueryAlterableInterfaceest en effet mis en œuvre par Querylui-même. Mais dans 8 la gestion de la configuration est reconstruite de toute façon. Et dans 7, seules les requêtes sélectionnées marquées sont modifiables pour autant que je vois. Mais peut-être que je manque quelque chose?
Mołot

1
Non, vous avez raison, hook_query_alter était une supposition, mais pas viable dans D7 dans ce cas, merci.
David Thomas

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.