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!)
redguy
(Maciej Lizewski)
April 20, 2012, 10:50am
2
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
redguy:
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'
)
);
}
...
}
redguy
(Maciej Lizewski)
April 20, 2012, 12:29pm
4
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.
abennouna
(Abennouna)
April 20, 2012, 1:16pm
5
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!
redguy
(Maciej Lizewski)
April 20, 2012, 2:06pm
7
sonik_the_sonik:
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.
softark
(Softark)
April 20, 2012, 2:11pm
8
Nice topic, indeed.
You should write this in wiki, redguy.
redguy:
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.
Ok. Now it’s, almost, everything clear. Almost, because you didn’t talk about:
redguy
(Maciej Lizewski)
April 20, 2012, 2:54pm
10
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.