The EAdvancedArBehavior extension takes away some of the complexities involved when saving objects, for example, with MANY_MANY and BELONGS_TO relations.
Requirements ¶
Built on Yii 1.1.6
Usage ¶
The EAdvancedArBehavior extension adds up some functionality to the default possibilites of yii´s ActiveRecord implementation.
To use this extension, just copy this file to your extensions/ directory, add 'import' => 'application.extensions.EAdvancedArBehavior', [...] to your config/main.php and add this behavior to each model you would like to inherit the new possibilities:
public function behaviors(){
return array( 'EAdvancedArBehavior' => array(
'class' => 'application.extensions.EAdvancedArBehavior'));
}
Depending on the functionallities you want to enable, you need to set some configuration parameters. This is described below.
Better support for MANY_MANY relations: ¶
Suppose you have a User and Project model having a MANY_MANY relation, for example:
User.php: ~~~ public function relations() {
return array( .....
'projects' => array(self::MANY_MANY, 'Project', 'tbl_project_user(user_id, project_id)') );
} ~~~ Project.php: ~~~ public function relations() {
return array( .....
'users' => array(self::MANY_MANY, 'User', 'tbl_project_user(project_id, user_id)') );
} ~~~
Now you can use it like ~~~ $user = User::model()->findBPk(12) ; $projects = Project::model()->findAll( $criteria ) ; $user->projects = $projects ; $user->save() ; ~~~
Remove relations like ~~~ $user->projects = array() ; // cleans up the relation table // or $user->delete() ; ~~~
Better support for BELONGS_TO relations: ¶
With this extension you can connect two related objects as follows:
$user = new User();
$user->company = Company::model()->find($conditions, $params);
$post->save();
Without this extension, you would have to do this as follows:
$user = new User();
$company = Company::model()->find($conditions, $params) ;
$user->company_id = $company->id ;
$post->save();
HAS_ONE and HAS_MANY ¶
Suppose a User HAS_ONE Address and HAS_MANY Emails, and Address/Email BELONGS_TO User (both have the foreignkey column user_id). So you can do now:
$user = new User() ;
$user->emails = array( $email1, $email2, ... ) ;
$user->address = $address ;
$user->save() ;
Set uninitialized column fields to NULL ¶
See: http://code.google.com/p/yiiext/downloads/detail?name=ensureNull_1.0.1.zip
Use it like
return array(
'EAdvancedArBehavior' => array(
'class' => 'application.extensions.EAdvancedArBehavior',
'useOnUpdate' => false, // set empty fields to NULL only on inserts not updates
));
MySQL ONLY: Multiple timespans with CURRENT_TIMESTAMP ¶
Although the title of this section suggests something which cannot be done with MySQL, there is a nice workaround available. This extension provides the means to have a table with one column for the insert time and an other for the last modification time. First, add the following two columns to your table definition
update_time timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' ON UPDATE CURRENT_TIMESTAMP,
created_time timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
Next, configure the following parameters
return array(
'EAdvancedArBehavior' => array(
'class' => 'application.extensions.EAdvancedArBehavior',
'useNullOnTimestamp' => TRUE, // set timestamps with a default value of 0000-00-00 00:00 to NULL (for inserts)
'useOnUpdate' => true, // required
'onUpdateTimestamp'=>'update_time', // column name of the update time
),
);
ignoreRelationsExcept($array=null) ¶
To reduce unnecessary database queries, define the relations which are modified before save():
$model->ignoreRelationsExcept( array('company', 'address') ) ;
$model->save() ;
All relations are ignored except company and address
TODO ¶
add more functionalities (any AR suggestions are welcome!)
Returns error if the primary key is other than "id"
I suggest changing line 108 from:
$this->owner->$relation[2] = $this->owner->{$key}->id;
To:
$this->owner->$relation[2] = $this->owner->{$key}->primaryKey;
Returns error if the primary key is other than "id"
thanks! I have it implemented in the current version (v0.3)
Transaction
Thank you for your attention.
Perhaps you might want to now implement the transaction.
Transaction
very interesting, that would be useful! I have to perform a little bit of research first, but if I have figured something out I'll post my ideas here!
thnx for tip
Delete MANY_MANY relations
Hi again.
I introduced a new behavior:
public function beforeDelete($event) { Yii::trace('deleting MANY_MANY data for '.get_class($this->owner),'system.db.ar.CActiveRecord'); foreach($this->owner->relations() as $key => $relation) { if($relation['0'] == CActiveRecord::MANY_MANY) // ['0'] equals relationType { $this->executeManyManyEntry($this->makeManyManyDeleteCommand( $relation[2], $this->owner->{$this->owner->tableSchema->primaryKey})); } } }
save-relations-ar-behavior
this extention better then save-relations-ar-behavior component, for me.
Remove all relations with table
I think this will be also good feather to this extension. delete all relation if array will be empty.
Ex:
$post = Post::model()->findByPk(1); $post->tags = array(); $post->save();
enchantment of class function.
public function writeManyManyTables() { ... elseif (is_array($this->owner->$key) && $this->owner->$key === array()) { $this->executeManyManyEntry($this->makeManyManyDeleteCommand( $relation[2], $this->owner->{$this->owner->tableSchema->primaryKey})); } ... }
New Behaviors
Hello
I've uploaded a new version which implements both suggested behaviors concerning deleting relations from the relation table.
Furthermore, the suggested 'transaction' behavior, I actually like how Yii does it (its easy to use) so I can't think of a better way to implement this!
Thanks a lot for the help!
Cheers
Bug Issue
Note:
Do not use this extension on all your active records because on update it will update all items. I wanted to update one of my table element
post
.view count. it updated all my tables.Bug Issue
thanks for pointing that out!!
I've uploaded a new version (v0.8) which solves this issue for HAS_ONE and HAS_MANY
Or did you experience it with MANY_MANY ?
cheers
Update HAS_ONE relations
Hi, I have noticed that this extension only work when creating an object that has a 'HAS_ONE' relation, but not also when updating.
I want to do something like this:
$client->attributes=$_POST['Client'];
$client->clientSetup->attributes = $_POST['ClientSetup'];
$client->save();
The problem is on line 67 of your code, because you only save if the foreignkey field is empty or different.
Could you fix this ?
Error with alphanumeric keys
To avoid error with alphanumeric keys, line 217 should be:
return sprintf("%s, ('%s', '%s')", $sql, $this->owner->{$this->owner->tableSchema->primaryKey}, $rel ) ;
Casing typo in the class name
The class you build is awesome by the way. But it's always referenced as "EAdvancedArBehavior". While the class name in the file is spelled with a lower b in "behavior". This is a problem in Unix environments as the filename does have a capital B in it. The problem doesn't occur unless you are using the class as a behavior for an object that needs to (serialized and) unserialized, which leads to an autoload error.
problem with php 5.4 build in server
I have got error when running my application on php 5.4.4 buildin server
Any idea how to fix this?
I use EAdvancedArBehavior 2.3
Update:
Replace beforeSave function definition
~~~
[diff]
[Solution found here...](http://stackoverflow.com/questions/3115388/declaration-of-methods-should-be-compatible-with-parent-methods-in-php "solution")
If you have any questions, please ask in the forum instead.
Signup or Login in order to comment.