[EXTENSION] AuditTrail

Hello I am trying to use your extension, but it is not working, there is nothing I can do to save the audit

can you help me out? it seens that it goes througth all colunms, it checks if they are equal, but it won’t save.

PS here is my log,

notice that I place a Yii::log() on your code to see if first the behavior was loading, second if the values where rigth, both positive.




2011/03/23 16:34:20 [trace] [system.db.ar.CActiveRecord] CadEscola.update()

2011/03/23 16:34:20 [trace] [system.db.ar.CActiveRecord] CadEscola.updateByPk()

2011/03/23 16:34:20 [trace] [system.db.CDbCommand] Executing SQL: UPDATE `cad_escola` SET `inep`=:yp0, `escola_nome`=:yp1, `CEP`=:yp2, `end_logradouro`=:yp3, `end_numero`=:yp4, `end_bairro`=:yp5, `end_complemento`=:yp6, `end_municipio`=:yp7, `end_uf`=:yp8, `DDD_Tel`=:yp9, `Telefones`=:yp10, `Telefone_publico`=:yp11, `Fax`=:yp12, `escola_email`=:yp13, `diretor_nome`=:yp14, `diretor_fones`=:yp15, `diretor_celular`=:yp16, `diretor_email`=:yp17, `viceDiretor_nome`=:yp18, `viceDiretor_fones`=:yp19, `viceDiretor_celular`=:yp20, `viceDiretor_email`=:yp21, `coordenador_nome`=:yp22, `coordenador_fones`=:yp23, `coordenador_celular`=:yp24, `coordenador_email`=:yp25, `prof_apoio_nome`=:yp26, `prof_apoio_fones`=:yp27, `prof_apoio_celular`=:yp28, `prof_apoio_email`=:yp29, `secretaria_nome1`=:yp30, `secretaria_nome2`=:yp31, `secretaria_nome3`=:yp32, `dt_inc`=:yp33, `dt_alt`=:yp34, `obs`=:yp35, `idtab_localizacao`=:yp36, `idtab_usuario`=:yp37 WHERE `cad_escola`.`inep`=35008758

2011/03/23 16:34:20 [LoggableBehavior] [application] values differ from each old to new

2011/03/23 16:34:20 [trace] [system.db.CDbCommand] Querying SQL: SHOW COLUMNS FROM `tbl_audit_trail`

2011/03/23 16:34:20 [trace] [system.db.CDbCommand] Querying SQL: SHOW CREATE TABLE `tbl_audit_trail`

2011/03/23 16:34:20 [trace] [system.CModule] Loading "coreMessages" application component

2011/03/23 16:34:20 [LoggableBehavior] [application] values differ from each old to new

2011/03/23 16:34:20 [LoggableBehavior] [application] values differ from each old to new

2011/03/23 16:34:20 [trace] [system.db.ar.CActiveRecord] CadEscolaPrograma.update()

2011/03/23 16:34:20 [trace] [system.db.ar.CActiveRecord] CadEscolaPrograma.updateByPk()

2011/03/23 16:34:20 [trace] [system.db.CDbCommand] Executing SQL: UPDATE `cad_escola_programa` SET `idcad_escola_programa`=:yp0, `nr_alunos_manha`=:yp1, `nr_alunos_tarde`=:yp2, `nr_turmas_manha`=:yp3, `nr_turma_tarde`=:yp4, `dt_inc`=:yp5, `dt_alt`=:yp6, `idtab_programa`=:yp7, `idtab_usuario`=:yp8, `inep`=:yp9 WHERE `cad_escola_programa`.`idcad_escola_programa`=6

2011/03/23 16:34:20 [trace] [system.db.ar.CActiveRecord] CadEscolaPrograma.update()

2011/03/23 16:34:20 [trace] [system.db.ar.CActiveRecord] CadEscolaPrograma.updateByPk()

2011/03/23 16:34:20 [trace] [system.db.CDbCommand] Executing SQL: UPDATE `cad_escola_programa` SET `idcad_escola_programa`=:yp0, `nr_alunos_manha`=:yp1, `nr_alunos_tarde`=:yp2, `nr_turmas_manha`=:yp3, `nr_turma_tarde`=:yp4, `dt_inc`=:yp5, `dt_alt`=:yp6, `idtab_programa`=:yp7, `idtab_usuario`=:yp8, `inep`=:yp9 WHERE `cad_escola_programa`.`idcad_escola_programa`=8

2011/03/23 16:34:20 [trace] [system.db.ar.CActiveRecord] CadEscolaPrograma.deleteAll()

2011/03/23 16:34:20 [trace] [system.db.CDbCommand] Executing SQL: DELETE FROM `cad_escola_programa` WHERE (idcad_escola_programa NOT IN (:ycp0, :ycp1)) AND (inep= 35008758)

2011/03/23 16:34:20 [trace] [system.CModule] Loading "log" application component

2011/03/23 16:34:20 [trace] [system.CModule] Loading "request" application component

2011/03/23 16:34:20 [trace] [system.CModule] Loading "urlManager" application component

2011/03/23 16:34:21 [trace] [system.web.filters.CFilterChain] Running filter CadEscolaController.filteraccessControl()

2011/03/23 16:34:21 [trace] [system.CModule] Loading "user" application component

2011/03/23 16:34:21 [trace] [system.CModule] Loading "session" application component

2011/03/23 16:34:21 [trace] [system.CModule] Loading "authManager" application component

2011/03/23 16:34:21 [trace] [system.CModule] Loading "db" application component

2011/03/23 16:34:21 [trace] [system.db.CDbConnection] Opening DB connection

2011/03/23 16:34:21 [trace] [system.db.CDbCommand] Querying SQL: SELECT * FROM AuthAssignment WHERE userid=:userid

2011/03/23 16:34:21 [trace] [system.db.CDbCommand] Querying SQL: SELECT * FROM AuthItem WHERE name=:name

2011/03/23 16:34:21 [trace] [system.web.auth.CDbAuthManager] Checking permission "viewCadEscola"

2011/03/23 16:34:21 [trace] [system.db.CDbCommand] Querying SQL: SELECT parent FROM AuthItemChild WHERE child=:name

2011/03/23 16:34:21 [trace] [system.db.CDbCommand] Querying SQL: SELECT * FROM AuthItem WHERE name=:name

2011/03/23 16:34:21 [trace] [system.web.auth.CDbAuthManager] Checking permission "visitanteEscola"

2011/03/23 16:34:21 [trace] [system.db.CDbCommand] Querying SQL: SELECT parent FROM AuthItemChild WHERE child=:name

2011/03/23 16:34:21 [trace] [system.db.CDbCommand] Querying SQL: SELECT * FROM AuthItem WHERE name=:name

2011/03/23 16:34:21 [trace] [system.web.auth.CDbAuthManager] Checking permission "administrador"

2011/03/23 16:34:21 [trace] [system.db.CDbCommand] Querying SQL: SHOW COLUMNS FROM `cad_escola_programa`

2011/03/23 16:34:21 [trace] [system.db.CDbCommand] Querying SQL: SHOW CREATE TABLE `cad_escola_programa`

2011/03/23 16:34:21 [info] [application] behavior attached

2011/03/23 16:34:21 [info] [application] behavior attached

2011/03/23 16:34:21 [trace] [system.db.CDbCommand] Querying SQL: SHOW COLUMNS FROM `cad_escola`

2011/03/23 16:34:21 [trace] [system.db.CDbCommand] Querying SQL: SHOW CREATE TABLE `cad_escola`

2011/03/23 16:34:21 [trace] [system.db.ar.CActiveRecord] CadEscola.findByPk()

2011/03/23 16:34:21 [trace] [system.db.CDbCommand] Querying SQL: SELECT * FROM `cad_escola` `t` WHERE `t`.`inep`=35008758 LIMIT 1

2011/03/23 16:34:21 [trace] [system.db.ar.CActiveRecord] lazy loading CadEscola.idtabLocalizacao0

2011/03/23 16:34:21 [trace] [system.db.CDbCommand] Querying SQL: SHOW COLUMNS FROM `tab_localizacao`

2011/03/23 16:34:21 [trace] [system.db.CDbCommand] Querying SQL: SHOW CREATE TABLE `tab_localizacao`

2011/03/23 16:34:21 [info] [application] behavior attached

2011/03/23 16:34:21 [trace] [system.db.CDbCommand] Querying SQL: SELECT `idtabLocalizacao0`.`idtab_localizacao` AS `t1_c0`, `idtabLocalizacao0`.`desctab_localizacao` AS `t1_c1`, `idtabLocalizacao0`.`dt_inc` AS `t1_c2`, `idtabLocalizacao0`.`dt_alt` AS `t1_c3`, `idtabLocalizacao0`.`ordem` AS `t1_c4`, `idtabLocalizacao0`.`idtab_usuario` AS `t1_c5` FROM `tab_localizacao` `idtabLocalizacao0`  WHERE (`idtabLocalizacao0`.`idtab_localizacao`=:ypl0) ORDER BY ordem

2011/03/23 16:34:21 [info] [application] behavior attached

2011/03/23 16:34:21 [trace] [system.db.ar.CActiveRecord] lazy loading CadEscola.idtabUsuario0

2011/03/23 16:34:21 [trace] [system.db.CDbCommand] Querying SQL: SHOW COLUMNS FROM `tab_usuario`

2011/03/23 16:34:21 [trace] [system.db.CDbCommand] Querying SQL: SHOW CREATE TABLE `tab_usuario`

2011/03/23 16:34:21 [info] [application] behavior attached

2011/03/23 16:34:21 [trace] [system.db.CDbCommand] Querying SQL: SELECT `idtabUsuario0`.`idtab_usuario` AS `t1_c0`, `idtabUsuario0`.`login` AS `t1_c1`, `idtabUsuario0`.`senha` AS `t1_c2`, `idtabUsuario0`.`email` AS `t1_c3`, `idtabUsuario0`.`dt_inc` AS `t1_c4`, `idtabUsuario0`.`dt_alt` AS `t1_c5`, `idtabUsuario0`.`idtab_nivel` AS `t1_c6` FROM `tab_usuario` `idtabUsuario0`  WHERE (`idtabUsuario0`.`idtab_usuario`=:ypl0)

2011/03/23 16:34:21 [info] [application] behavior attached

2011/03/23 16:34:21 [trace] [system.CModule] Loading "widgetFactory" application component

2011/03/23 16:34:21 [trace] [system.CModule] Loading "coreMessages" application component

2011/03/23 16:34:21 [trace] [system.CModule] Loading "assetManager" application component

2011/03/23 16:34:21 [trace] [system.CModule] Loading "clientScript" application component

2011/03/23 16:34:21 [trace] [system.CModule] Loading "format" application component

2011/03/23 16:34:21 [trace] [system.db.CDbCommand] Querying SQL: SELECT sum(nr_alunos_manha) FROM cad_escola_programa where inep = 35008758

2011/03/23 16:34:21 [trace] [system.db.CDbCommand] Querying SQL: SELECT sum(nr_alunos_tarde) FROM cad_escola_programa where inep = 35008758

2011/03/23 16:34:21 [trace] [system.db.CDbCommand] Querying SQL: SELECT sum(nr_alunos_tarde+nr_alunos_manha) FROM cad_escola_programa where inep = 35008758

2011/03/23 16:34:21 [trace] [system.db.CDbCommand] Querying SQL: SELECT sum(nr_turmas_manha) FROM cad_escola_programa where inep = 35008758

2011/03/23 16:34:21 [trace] [system.db.CDbCommand] Querying SQL: SELECT sum(nr_turma_tarde) FROM cad_escola_programa where inep = 35008758

2011/03/23 16:34:21 [trace] [system.db.CDbCommand] Querying SQL: SELECT sum(nr_turmas_manha+ nr_turma_tarde) FROM cad_escola_programa where inep = 35008758

2011/03/23 16:34:21 [trace] [system.db.ar.CActiveRecord] CadEscolaPrograma.count()

2011/03/23 16:34:21 [trace] [system.db.CDbCommand] Querying SQL: SHOW COLUMNS FROM `tab_programa`

2011/03/23 16:34:21 [trace] [system.db.CDbCommand] Querying SQL: SHOW CREATE TABLE `tab_programa`

2011/03/23 16:34:21 [info] [application] behavior attached

2011/03/23 16:34:21 [trace] [system.db.ar.CActiveRecord] CadEscolaPrograma.count() eagerly

2011/03/23 16:34:21 [trace] [system.db.CDbCommand] Querying SQL: SELECT COUNT(DISTINCT `t`.`idcad_escola_programa`) FROM `cad_escola_programa` `t`  LEFT OUTER JOIN `tab_programa` `idtabPrograma0` ON (`t`.`idtab_programa`=`idtabPrograma0`.`idtab_programa`)  WHERE (inep=:ycp0)

2011/03/23 16:34:21 [trace] [system.db.ar.CActiveRecord] CadEscolaPrograma.findAll()

2011/03/23 16:34:21 [trace] [system.db.CDbCommand] Querying SQL: SELECT `t`.`idcad_escola_programa` AS `t0_c0`, `t`.`nr_alunos_manha` AS `t0_c1`, `t`.`nr_alunos_tarde` AS `t0_c2`, `t`.`nr_turmas_manha` AS `t0_c3`, `t`.`nr_turma_tarde` AS `t0_c4`, `t`.`dt_inc` AS `t0_c5`, `t`.`dt_alt` AS `t0_c6`, `t`.`idtab_programa` AS `t0_c7`, `t`.`idtab_usuario` AS `t0_c8`, `t`.`inep` AS `t0_c9`, `idtabPrograma0`.`idtab_programa` AS `t1_c0`, `idtabPrograma0`.`desctab_programa` AS `t1_c1`, `idtabPrograma0`.`ordem` AS `t1_c2`, `idtabPrograma0`.`dt_inc` AS `t1_c3`, `idtabPrograma0`.`dt_alt` AS `t1_c4`, `idtabPrograma0`.`idtab_usuario` AS `t1_c5` FROM `cad_escola_programa` `t`  LEFT OUTER JOIN `tab_programa` `idtabPrograma0` ON (`t`.`idtab_programa`=`idtabPrograma0`.`idtab_programa`)  WHERE (inep=:ycp0) ORDER BY ordem LIMIT 50

2011/03/23 16:34:21 [info] [application] behavior attached

2011/03/23 16:34:21 [info] [application] behavior attached

2011/03/23 16:34:21 [info] [application] behavior attached

2011/03/23 16:34:21 [trace] [system.db.CDbCommand] Querying SQL: SELECT * FROM AuthAssignment WHERE userid=:userid

2011/03/23 16:34:21 [trace] [system.db.CDbCommand] Querying SQL: SELECT * FROM AuthItem WHERE name=:name

2011/03/23 16:34:21 [trace] [system.web.auth.CDbAuthManager] Checking permission "indexCadEscola"

2011/03/23 16:34:21 [trace] [system.db.CDbCommand] Querying SQL: SELECT parent FROM AuthItemChild WHERE child=:name

2011/03/23 16:34:21 [trace] [system.db.CDbCommand] Querying SQL: SELECT * FROM AuthItem WHERE name=:name

2011/03/23 16:34:21 [trace] [system.web.auth.CDbAuthManager] Checking permission "visitanteEscola"

2011/03/23 16:34:21 [trace] [system.db.CDbCommand] Querying SQL: SELECT parent FROM AuthItemChild WHERE child=:name

2011/03/23 16:34:21 [trace] [system.db.CDbCommand] Querying SQL: SELECT * FROM AuthItem WHERE name=:name

2011/03/23 16:34:21 [trace] [system.web.auth.CDbAuthManager] Checking permission "administrador"

2011/03/23 16:34:21 [trace] [system.db.CDbCommand] Querying SQL: SELECT * FROM AuthAssignment WHERE userid=:userid

2011/03/23 16:34:21 [trace] [system.db.CDbCommand] Querying SQL: SELECT * FROM AuthItem WHERE name=:name

2011/03/23 16:34:21 [trace] [system.web.auth.CDbAuthManager] Checking permission "indexCadOng"

2011/03/23 16:34:21 [trace] [system.db.CDbCommand] Querying SQL: SELECT parent FROM AuthItemChild WHERE child=:name

2011/03/23 16:34:21 [trace] [system.db.CDbCommand] Querying SQL: SELECT * FROM AuthItem WHERE name=:name

2011/03/23 16:34:21 [trace] [system.web.auth.CDbAuthManager] Checking permission "visitanteONG"

2011/03/23 16:34:21 [trace] [system.db.CDbCommand] Querying SQL: SELECT parent FROM AuthItemChild WHERE child=:name

2011/03/23 16:34:21 [trace] [system.db.CDbCommand] Querying SQL: SELECT * FROM AuthItem WHERE name=:name

2011/03/23 16:34:21 [trace] [system.web.auth.CDbAuthManager] Checking permission "administrador"

2011/03/23 16:34:21 [trace] [system.db.CDbCommand] Querying SQL: SELECT * FROM AuthAssignment WHERE userid=:userid

2011/03/23 16:34:21 [trace] [system.db.CDbCommand] Querying SQL: SELECT * FROM AuthItem WHERE name=:name

2011/03/23 16:34:21 [trace] [system.web.auth.CDbAuthManager] Checking permission "indexCadPlanoOficina"

2011/03/23 16:34:21 [trace] [system.db.CDbCommand] Querying SQL: SELECT parent FROM AuthItemChild WHERE child=:name

2011/03/23 16:34:21 [trace] [system.db.CDbCommand] Querying SQL: SELECT * FROM AuthItem WHERE name=:name

2011/03/23 16:34:21 [trace] [system.web.auth.CDbAuthManager] Checking permission "visitante"

2011/03/23 16:34:21 [trace] [system.db.CDbCommand] Querying SQL: SELECT parent FROM AuthItemChild WHERE child=:name

2011/03/23 16:34:21 [trace] [system.db.CDbCommand] Querying SQL: SELECT * FROM AuthItem WHERE name=:name

2011/03/23 16:34:21 [trace] [system.web.auth.CDbAuthManager] Checking permission "administrador"

2011/03/23 16:34:21 [trace] [system.db.CDbCommand] Querying SQL: SELECT * FROM AuthAssignment WHERE userid=:userid

2011/03/23 16:34:21 [trace] [system.db.CDbCommand] Querying SQL: SELECT * FROM AuthItem WHERE name=:name

2011/03/23 16:34:21 [trace] [system.web.auth.CDbAuthManager] Checking permission "indexAuxiliares"

2011/03/23 16:34:21 [trace] [system.db.CDbCommand] Querying SQL: SELECT parent FROM AuthItemChild WHERE child=:name

2011/03/23 16:34:21 [trace] [system.db.CDbCommand] Querying SQL: SELECT * FROM AuthItem WHERE name=:name

2011/03/23 16:34:21 [trace] [system.web.auth.CDbAuthManager] Checking permission "auxiliares"

2011/03/23 16:34:21 [trace] [system.db.CDbCommand] Querying SQL: SELECT parent FROM AuthItemChild WHERE child=:name

2011/03/23 16:34:21 [trace] [system.db.CDbCommand] Querying SQL: SELECT * FROM AuthItem WHERE name=:name

2011/03/23 16:34:21 [trace] [system.web.auth.CDbAuthManager] Checking permission "administrador"




One change request. Right now you require that the primary key be id. To make that not a requirement only 2 changes are needed in the portlet.

Change:


$this->model->id

To:


$this->model->primaryKey 

Twice

Questions:

  1. You mention building in RBAC in the install guide but not where to build it in. Where should we add that?

  2. Do you have any ideas for how we might build in logging for foreign keys? (Eg We associate trainings to members. If a training is removed from a member, I would like to show that, but since it is a foreign keyed table right now it would just log that member_training row 1203 was deleted rather than member 4 had training 5 deleted.) We can help with the coding, but your advice as to where we might start would be excellent.

  3. Finally, is their any way to have the data processed for display? We use int columns to store unix time so processing that back to user time before display would be great.

Thanks for these great suggestions. I will build them into a release! I can’t believe I didn’t think of the primary key issue. Sorry about that :)

As for your questions:

  1. If you are using RBAC, the specific extension you use would determine where to build that in. The controllers in the module extend Controller, which is what the scaffolding generates for you automatically. This means that if you use an extension like SRBAC or rights, the modifications they make to controller should still execute when you are running through the extension controllers. I was intentionally vague on the specifics because this extension doesn’t deal with rbac at all, it is just designed to be nice to other extensions :)

  2. We’ve looked at this also, but the problem is how to determine when to show and when not to show these things automatically. Showing changes for foreign keys works great in a less complicated table setup, but as you get to dozens or hundreds of tables, things start getting crazy. For instance, you may have a table orders and a table order_items with a foreign key pointing back to orders. In this instance, it would be great to show on order’s audit trail that some order items had changed. However, take the example of if you also store order status, tracking, comment, and various other sorts of metadata with your order. Now you would have an audit trail widget showing change data for all sorts of things, and most of the data displayed would be ancillary. You may have to go through pages of changes before finding changes to the actual order model. I just decided the simple way was better, especially since you can always search through the full log to find what data member_trainings 1205 had in it.

I’m not saying I can never be persuaded to change my mind. I just chose the simpler route since neither way felt 100% right.

  1. I like this idea of processing the data for display. What if I let you pass a columns array to the widget and define them however you want, and default to the way it works now if you don’t pass through any columns. This way you could use the value section to set up an expression whose value (passed through eval) would be shown instead of the direct data. Would this help or do you need further refinement?
  1. We are using an RBAC extension so that is what we will do.

  2. Maybe I missed a part of something, but where is this full log located that would have the data from the member_training. I don’t know if this would make any since, but maybe it could be something to define in the behavior for the member_training table so that it would log with the Member model rather than the member_training module. Alternatively, is their an easy way for me to combine portlets or have a few on a page. I can’t imagine anyone ever having the time to go and find the logs for each member training or order item change, though seeing it at the bottom of the page (though perhaps separately) might be good. The trick would be to be able to show an entry for deleted trainings since their would no longer be a way to tie them back.

  3. Are you thinking something like the way you can pass a function to be evaled before display to grid view? I think that would work well. So it would be something like


array(

 	'starttime'=>"date('m-d-Y g:ia',$data)",

 	// This might be a bit harder since it would need to call an active record, 

	// but it should still work

 	'owner'=>"(find member with pk $data)->name",

 	etc

);

2 and 3 look like they could become a little database intensive so I will probably separate the audit log to a separate page so that only runs when people want to see it, but I still think it would be good since it will make the log more usable to the end user rather than needing someone from the computer department to interpret it…

Hello, I figured ou what was the problem and why it wasn’t saving my audit, if you like here are a couple mods you should do to make debugs easy

change all your


$log->save

for




    if (!$log->save()) {

	Yii::log('Not save for '.print_r($log->getErrors(),true),CLogger::LEVEL_ERROR,  'LoggableBehavior');	

    }



and I found a couple more erros, if you try to save a model witch has a null value in any of the columns you get an error, to avoid it you should

change




  $log->old_value = $old;



with




if ($old == null) {

  $old = 'null';

}					

$log->old_value = $old;



and




$log->new_value = $value;



with




if ($value == null) {

  $value = 'null';

}

$log->new_value = $value;



wherever you find it.

good luck

I am rolling up a bunch of changes to the module now for a big 1.2 release, so this is a good time to change things. Would it be easier to just allow null values in the log table? This would fix your issue. It could also allow for changes to be recorded from anonymous users by saving a null value. Thoughts?

On a side note, I’m sorry I did not notice your help request until now, but I am glad you figured it out.

I think it is best to write ‘null’ instead of letting it be null, but it is you choice you could instead of writing ‘null’ change to any message you like with a variable, better for internationalization I guess.

the log part you should do, took me a buch to figure my probllem was that the user ID in my case was a string and in you case should the an integer, either way you go, log the erro in Yii log to make things a lot easier on ppl ;)

np in not seeing my request, better that way I figured some time after.

On a side note, since you are changing some stuff I did one more change in you code.

I have in my tables a column for alter dates, witch I didn’t see the need to log since it is an automated thing, I don’t use Mysql current timestant, I do it in my code, so to save some space I added a ‘ignore columns’ list, so it checked against that list.

so if the column was on my ignore list, the audit didn’t log that column, maybe it should be a good added functionality.

not sure if I made myself clear, english is not my born language.

if you need any help, just say so. I am new to Yii framework, but a good programmer :D

I think what you are saying is that it would be useful to have an "ignore columns" list inside of your models so that changes for those columns are not recorded.

If this is the case, I think I have a better idea – what if I added a list of "include columns" and "ignore columns" on the display widget. If you give a list of columns to show, it only shows changes in those columns. If you give a list of columns to ignore, it shows all columns except those columns. Would this help?

Also, I will revise the behavior to update times itself instead of relying on timestamp fields (mysql) and triggers (postgres).

I just found two other issues.

In the loggable behavior.

There are two places where it is $log=new auditTrail; instead of $log=new AuditTrail;

PHP 5.3 is case sensitive (or at least my install is) so they have to match.

So, to summarize all changes that I have (I still need to test, but coding is done) for 1.2 release:

-model_id and user_id are char(255) instead of integer, because some people have character based keys for users/models

-user_id can be null (maybe a backend process is doing something)

-previous and current values can be null

-widget allows you to pass custom formatting in the format that CDataGrid uses

-capitalization is all standardized now when creating new objects (sorry!)

-uses migrations instead of sql scripts to create tables

Questions remaining are:

Transactions – should I add an option to use these? Should they be default to yes?

Failed audit trail saves – should I throw an exception?

Only displaying some columns – is there interest in passing in a list of columns to not show in the audit trail?

Please let me know your thoughts

Transactions might be good, but not something I know much about (though it is on the list to learn).

I would say yes so we see it and can try to fix it to where the audit will save. I don’t wish to randomly lose audits.

Yes, I track the last login time for my users, but I generally don’t want to see that in the audit trail.

Hi, I’m working on a similar thing, as a part of the requirements of my new project. The main difference between my implementation and yours is that I must provide not only an audit functionality, but also a “validate or roll-back” functionality. In other words, if a lowly employee updates some information about something, the update will be stored, but not used, until a higher-up sees the update in the audit log, and decides to validate it (commit it to the database), or cancel it (roll it back). It will be all about RBAC, some users will have an acces right giving them the possibility of updating some object attributes (table fields) without validation, others will have to submit their updates to their supervisor’s validation.

Would you be planning to add something like this to your extension ?

Ok folks, I just uploaded version 1.2. The main changes are

*Bug fixes

*Migrations for database management instead of sql scripts

*Does not require numeric ids for users or tables

*Output for widget can be overriden using a syntax similar to XDataGrid column syntax.

You can get the updated version here:

http://www.yiiframework.com/extension/audittrail/

Please note:

My update took so long because I have been constantly fighting with PHPUnit. My laptop died in April and since then I have been trying to get everything back up and going. I still cannot get PHPUnit and MAMP to play nice, so this update HAS NOT BEEN TESTED PROGRAMMATICALLY!!! I set up some basic manual tests, but I am not happy about this. I finally gave up fighting PHPUnit so I could release something.

Future enhancements:

– Rollback - Should we allow rollback by value (ie: one field can roll back and others not), or rollback to date (the state of the row at a certain point)?

– Transactions - How should we handle a failed update

– Weird issues with events inside of CActiveRecord - Some CActiveRecord methods that update the database do not raise any events. Should we overide these methods to raise these events (they would lose some speed) and allow them to log, or should we allow them to not log?

Hi there!!!

Very good extension MadSkillsTisdale!!!

Does anybody know how to log Yii-User updates? Ex.: lastvisit, create a user, update profile, change password, etc.

auditTrail 1.1.1

User 0.3

Thanks!

It looks like all of the models in yii-user extend from from a class called UActiveRecord that is included in the components folder of the yii-user extension. It appears that this class extends CAtiveRecord, so you can just add the LoggableBehavior to UActiveRecord and that should log all changes made by that module. Of course, you will have to redo this every time you upgrade yii-user, but it will only take 5 minutes or so for this work to be done

OK, thanks!!! I will try…

Hello, I’m trying to change the user_id column of the grid to display the username of my users table. (I’m using the extension of Yii-User-Management)

First define a new relationship




 public function relations ()

 {

     	Yii:: import ('application.modules.user.models .*');

     	Yii:: app () -> GetModule ('user');

 return array (

         	'users' => array (self:: BELONGS_TO 'YumUser', 'user_id'),

 );

 }



Then in view of the grid replace ‘user_id’ by




     	array (

         	'name' => 'user_id',

         	'value' => $ data-> users-> username,

    	)



But it still shows the id and not the username. I’ve been trying and that work with other models but had never tried with an extension.

thanks alot.

Hello. Is possible configure this module for audit only selected fields in model ? I don’t care audit field as create_time, create_user, update_time … Thank You a thank’s for this helpful modul. Zdenek

I’d like to thank you for this extension: it is very useful!

Please consider following bugs I encountered:

[list=1]

[*]Provided db migration does not work with MySQL. Here’s what I had to change:

  • column types not set for model and field, modified to:

'model' => 'string NOT NULL',

'field' => 'string NOT NULL',

  • MySQL does not allow indices on full-text fields. Had to remove keys on old_value and new_value

[*]Not all Yii applications contain generated-by-default Controller class. It’s better to use your own base controller class (eg AuditTrailController), that implements required variables

[/list]