auto timestamp and user on record modification

Hi everybody! This is my first message in the forum. Thanks to you I’ve learnt a lot of thing but now I have to ask for your help.

To goal of what I want to develop is something that will save user_id and timestamp when I create or update a record in tables that own "developer specified" fields.

I’d like to have a general configuration (in the main.php?) that allow me to define the name of the fields for every table and a more specific one (to the Model level) if a table has different fields name.

E.g:




TABLE PRODUCTS:


- id

- desc

- ...

[b]

- created_at

- user_created

- updated_at

- user_updated

[/b]



When I have a table like that (with that particular fields) I’d like something (I think a behaviour) that populate my fields.

Could anyone give me an advice? Where do I have to start? And what’s the best way to do that? Has this feature any sense? :)

Thank you!

(I apologize for my english!)

nice solution is to create behavior which does this. then you can attach such behavior to many different models. example behavior implementation:




class BlameableBehavior extends CActiveRecordBehavior {


    function beforeSave( $event ) {

        $owner = $this->getOwner();

        $user = Yii::app()->user;

        if( $owner->getIsNewRecord() ) {

            $owner->created_at = date( 'Y-m-d H:i:s' );

            $owner->created_by = $user !== null ? intval( $user->id ) : 0;

            if( $owner->hasAttribute( 'created_by_login' ) ) {

                $owner->created_by_login = $user !== null ? $user->name : 'guest';

            }

        }

        $owner->updated_at = date( 'Y-m-d H:i:s' );

        $owner->updated_by = $user !== null ? intval( $user->id ) : 0;

        if( $owner->hasAttribute( 'updated_by_login' ) ) {

            $owner->updated_by_login = $user !== null ? $user->name : 'guest';

        }

    }

}



then you attach it to model like this:




class MyModel extends CActiveRecord {

...

    public function behaviors() {

        return array(

            'BlameableBehavior' => array(

                'class' => 'BlameableBehavior'

            )

        );

    }

...

}



There’s already a built-in behavior for this…

http://www.yiiframework.com/doc/api/1.1/CTimestampBehavior

If you check what it does - it is not the same. The builtin behavior does not set user id/login only timestamps, which in many cases is not enough for audit trail… This is why I keep my own behavior.

Thanks for sharing redguy.

I haven’t jumped into customized behaviors yet, but I see the advantage of your example as I currently use a mix of beforeSave and CTimestampBehavior

Thank you Redguy for your reply. I’ll test (and hopefully extend) your solution as soon as possible!

jellysandwich, I saw that link but, as Redguy said, it’s not exactly what I was looking for.

I’m not sure about these lines:




 $owner->created_by = $user !== null ? intval( $user->id ) : 0;

            if( $owner->hasAttribute( 'created_by_login' ) ) {

                $owner->created_by_login = $user !== null ? $user->name : 'guest';

            }



Why should I have a column “created_by” and “created_by_login”? What’s the difference?

And, is there a way to add this behaviour only in one place and not in every Model?

Thanks again!

These are mine columns. I just pasted my own behavior. you can customize it to suit your needs :)

I prefer storing numerical user id (created_by, updated_by), but sometime I also save login (created_by_login, updated_by_login) - this behavior checks if attached model has such attributes and sets them. If model does not have created_by_login attribute - only numerical id will be stored. I left this because it shows how you can check in behavior if model has specific attributes or not.

Nice topic, indeed.

You should write this in wiki, redguy.

Ok. Now it’s, almost, everything clear. Almost, because you didn’t talk about:

:)

As I know - you have to add it in every model you want to have such behavior… I would not want to have such global configuration because I use many third party plugins which do not follow my field namid conventions or do not have such fields.

You can overload default gii/giix templates so they add by default such behavior in generated models.