¿Es posible conectar al evento variable_set ()?

8

Me gustaría rastrear el evento de cambios del sistema, para que sean revertables. Al verificar variable_set (), veo que no se proporciona ningún gancho para ese evento. ¿Hay alguna forma de hacer esto?

Puedo modificar para enganchar a los formularios de configuración, pero hay un montón de formularios de configuración para rastrear, si puedo enganchar a variable_set () directamente, el código se vuelve mucho más simple.

También puedo rastrear los cambios de variables con funciones + módulos de brazo fuerte, pero es mejor si el administrador de Drupal puede navegar por el historial de variables sin tocar el código.

Andy Truong
fuente

Respuestas:

11

Parece que es imposible usar solo Drupal, lo que significa:

variable_set()en sí no invoca ningún gancho, pero usa db_merge(). Esa función está usando la MergeQueryclase. Ahora, sería bueno conectarse hook_query_alter(), pero solo funciona para las clases de consulta que implementan la QueryAlterableInterfaceinterfaz. Lamentablemente, esta interfaz ahora está implementada solo por SelectQueryy las SelectQueryExtenderclases, no por la MergeQueryclase.

Tenga en cuenta que incluso si encuentra una manera de crear una clase secundaria de MergeQuery, eso implementará QueryAlterableInterfacey hará que Drupal lo use. hook_query_alter()solo funciona en consultas que tienen etiquetas, y variable_set()no etiqueta su consulta, por lo que el gancho no se usaría de todos modos, a menos que esté dispuesto a hackear el núcleo. Pero si es así, no necesita todo eso, simplemente podría hackear una llamada de enlace.

Si se siente duro , puede usar un enfoque PHP más indirecto: $confes una matriz global de variables de configuración; puede escribir un módulo que lo reemplace con un objeto que actúa como una matriz, como se describe en Desbordamiento de pila . Para que sea un buen sustituto, debe implementarlo ArrayAccess. Extraiga todos los valores del original $confen su objeto. Luego, en ArrayAccess::offsetSet()implementar su lógica de registro.

Mołot
fuente
Olvidé esta vieja respuesta mía y ya encontré cómo hacer casi cualquier cosa en $confese entonces: D Espero que mi respuesta actualizada ayude a alguien.
Mołot
¡Estoy impresionado! : D
Letharion
@Letharion Gracias :) Había una vez que me gustaba la "magia de los objetos que actuaba como ..." en PHP, y todavía recuerdo un poco al respecto;)
Mołot
6

Podría usar un desencadenador de base de datos, que sería más rápido que el código.

Aquí está el documento de MySQL .

  1. crear una tabla para almacenar valores antiguos

    CREATE TABLE variable_backup
    (
        name varchar(128) not null,
        value longblob,
        updated datetime not null,
        primary key (name, updated)
    );
  2. cree sus disparadores, uno para insertar y otro para actualizar:

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

Ahora todas sus actualizaciones e inserciones registrarán valores antiguos en variable_backup.

Scott Joudry
fuente
Me gusta, ordenado y simple. Probablemente más rápido que mi método también. Más limitado, pero suficiente para hacer lo que OP necesita, si tiene suficiente acceso a MySQL.
Mołot
Me gusta de esta manera. Pero creo que también necesitamos rastrear la información del agente de usuario
Andy Truong
Dudo que la información esté disponible para la base de datos.
Scott Joudry
@AndyTruong esa información no estará en la base de datos, lo siento. Traté de mirar alrededor, pero es imposible adivinarlo con datos en la tabla de sesión, y solo las consultas seleccionadas se pueden modificar, por lo que no hay forma de agregarlo. Entonces mi método "hardcore" está ahí para ti. Espero que haya tenido éxito al implementarlo, si no, haga una nueva pregunta que lo vincule y comente que lo hizo.
Mołot
5

Como puede ver en el código fuente, variable_set()no realiza solicitudes de enganches o alteraciones, por ejemplo, no module_invoke_all()o drupal_alter()llama allí.

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

Sin embargo, es posible que pueda escuchar la db_merge()consulta con una ubicación especial hook_query_alter()y realizar un procesamiento adicional allí, pero, como lo señaló Molot, hook_query_alter()parece poco probable que pueda orientar la db_merge()consulta.

Alternativamente, quizás podría cronometrar una instantánea de la tabla de variables para diferenciarla de las revisiones anteriores de esa tabla, o bien implementar alguna otra forma de almacenamiento de revisión de variables para comparar.

David Thomas
fuente
1
Si hook_query_alter se puede utilizar en esta consulta, me encantaría ver cómo. En 8 QueryAlterableInterfacese implementa de hecho por Querysí mismo. Pero en 8 la gestión de la configuración se reconstruye de todos modos. Y en 7 solo las consultas de selección etiquetadas son modificables por lo que veo. Pero tal vez me estoy perdiendo algo?
Mołot
1
No, tienes razón, hook_query_alter fue una suposición, pero no es viable en D7 en este caso, gracias.
David Thomas
0

¡Abrí un ticket de Solicitud de funciones en Drupal.org para crear ganchos para interceptar la configuración y eliminación de variables del sistema, y ​​presenté para revisión un parche central para esto! Por favor mira:

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

Eric Jenkins
fuente