Ist es möglich, sich an das Ereignis variable_set () zu binden?


8

Ich möchte das Systemänderungsereignis verfolgen, um sie rückgängig zu machen. Wenn ich variable_set () überprüfe, sehe ich, dass für dieses Ereignis kein Hook bereitgestellt wird. Gibt es eine Möglichkeit für mich, dies zu tun?

Ich kann Änderungen an Einstellungsformularen vornehmen, aber es gibt viele Einstellungsformulare, die verfolgt werden müssen. Wenn ich direkt an variable_set () binden kann, wird der Code viel einfacher.

Ich kann die Variablenänderungen auch mit Features + Strongarm-Modulen verfolgen, aber es ist besser, wenn der Drupal-Administrator den Variablenverlauf durchsuchen kann, ohne den Code zu berühren.

Antworten:


11

Es scheint unmöglich zu sein, nur Drupal zu verwenden, was bedeutet:

variable_set()selbst ruft keine Hooks auf, verwendet aber db_merge(). Diese Funktion verwendet die MergeQueryKlasse. Nun, es wäre schön, sich damit zu verbinden hook_query_alter(), aber es funktioniert nur für Abfrageklassen, die die QueryAlterableInterfaceSchnittstelle implementieren . Leider wird diese Schnittstelle jetzt nur von der SelectQueryund den SelectQueryExtenderKlassen implementiert , nicht von der MergeQueryKlasse.

Beachten Sie, dass selbst wenn Sie einen Weg finden, eine untergeordnete Klasse von zu erstellen MergeQuery, diese implementiert QueryAlterableInterfacewird und Drupal sie verwendet. hook_query_alter()Funktioniert nur bei Abfragen mit Tags und variable_set()markiert die Abfrage nicht mit Tags. Daher wird der Hook ohnehin nicht verwendet, es sei denn, Sie sind bereit, den Kern zu hacken. Aber wenn Sie es sind, brauchen Sie das alles nicht, Sie könnten einfach einen Hook-Call einhacken.

Wenn Sie sich hardcore fühlen , können Sie einen indirekteren PHP-Ansatz verwenden: $confist ein globales Array von Konfigurationsvariablen; Sie können ein Modul schreiben, das es durch ein Objekt ersetzt, das sich wie ein Array verhält, wie unter Stapelüberlauf beschrieben . Um es zu einem guten Ersatz zu machen, müssen Sie implementieren ArrayAccess. Ziehen Sie alle Werte vom Original $confin Ihr Objekt. Dann in ArrayAccess::offsetSet()implementieren Ihre Logging - Logik.


Ich habe meine alte Antwort vergessen und schon damals herausgefunden, wie man so ziemlich alles macht $conf: D Ich hoffe, meine aktualisierte Antwort wird jemandem helfen.
Mołot

Ich bin beeindruckt! : D
Letharion

@ Letharion Danke :) Es war einmal, als ich "Objekt als ..." Magie in PHP mochte, und ich erinnere mich noch ein bisschen daran;)
Mołot

6

Sie könnten einen Datenbank-Trigger verwenden, der schneller als Code wäre.

Hier ist das MySQL-Dokument .

  1. Erstellen Sie eine Tabelle zum Speichern alter Werte

    CREATE TABLE variable_backup
    (
        name varchar(128) not null,
        value longblob,
        updated datetime not null,
        primary key (name, updated)
    );
  2. Erstellen Sie Ihre Trigger, einen zum Einfügen und einen zum Aktualisieren:

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

Jetzt zeichnen alle Ihre Aktualisierungen und Einfügungen alte Werte in variable_backup auf.


Ich mag es, ordentlich und einfach. Wahrscheinlich auch schneller als meine Methode. Eingeschränkter, aber genug, um das zu tun, was OP benötigt, wenn er über ausreichenden MySQL-Zugriff verfügt.
Mołot

Ich mag diesen Weg. Aber ich denke, wir müssen auch die Informationen der Benutzeragenten verfolgen
Andy Truong

Ich bezweifle, dass der Datenbank Informationen zur Verfügung stehen würden.
Scott Joudry

@AndyTruong diese Informationen werden nicht in der Datenbank sein, sorry. Ich habe versucht, mich umzuschauen, aber es ist unmöglich, es mit Daten in der Sitzungstabelle zu erraten, und nur ausgewählte Abfragen können geändert werden, sodass keine Möglichkeit besteht, sie hinzuzufügen. Meine "Hardcore" -Methode ist also für Sie da. Ich hoffe, Sie hatten Erfolg bei der Implementierung, wenn nicht - stellen Sie eine neue Frage, die darauf verweist, und kommentieren Sie, dass Sie dies getan haben.
Mołot

5

Wie Sie im Quellcode sehen können, werden variable_set()keine Hooks oder Änderungen angefordert, z. B. no module_invoke_all()oder drupal_alter()Aufrufe.

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

Möglicherweise können Sie die db_merge()Abfrage jedoch mit einer speziell platzierten Abfrage abhören hook_query_alter()und dort zusätzliche Verarbeitungen vornehmen. Wie von Molot hervorgehoben, ist es jedoch hook_query_alter()unwahrscheinlich, dass Sie auf die db_merge()Abfrage abzielen können .

Alternativ können Sie möglicherweise einen Snapshot der Variablentabelle erstellen, um sie von früheren Revisionen dieser Tabelle zu unterscheiden, oder eine andere Form des Speichers für variable Revisionen implementieren, mit der Sie vergleichen können.


1
Wenn hook_query_alter für diese Abfrage verwendet werden kann, würde ich gerne sehen, wie. In 8 QueryAlterableInterfaceist in der Tat von Queryselbst implementiert . Aber in 8 wird das Konfigurationsmanagement trotzdem neu aufgebaut. Und in 7 sind meines Erachtens nur markierte ausgewählte Abfragen änderbar. Aber vielleicht fehlt mir etwas?
Mołot

1
Nein, Sie haben Recht, hook_query_alter war eine Vermutung, aber in D7 in diesem Fall nicht realisierbar, danke.
David Thomas

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.