Yii Framework Forum: please test my AR Enhancement: automatically sync MANY_MANY table when calling save() - Yii Framework Forum

Jump to content

  • (3 Pages)
  • +
  • 1
  • 2
  • 3
  • You cannot start a new topic
  • You cannot reply to this topic

please test my AR Enhancement: automatically sync MANY_MANY table when calling save() Rate Topic: -----

#21 User is offline   seb 

  • Standard Member
  • PipPip
  • Yii
  • Group: Members
  • Posts: 240
  • Joined: 29-June 09

Posted 20 May 2010 - 03:30 AM

Hi,

Thanks for great component!

I found small issue with current CAdvancedArBehavior version.
Here:
    protected function writeRelation($relation) 
    {
        ...
        // An array of objects is given
        foreach($this->owner->$key as $foreignobject)
        {
            if(!is_numeric($foreignobject))
            {
                $foreignobject = $foreignobject->{$foreignobject->$relation['m2mForeignField']};                
            }
            $this->execute($this->makeManyManyInsertCommand($relation, $foreignobject));
        }
    }


The problem is that {$foreignobject->$relation['m2mForeignField']} is the name of the field inside relation table and not in the foreign table.
For example, we have table posts with id primary key and categories also with id primary key and relation table post_category(category_id, post_id).
Then $foreignobject->{$foreignobject->$relation['m2mForeignField']} is evaluated as $foreingobject->category_id and I have no such field in categories table.

This can be fixed with this change (actually CAdvancedArBehavior v0.2 works this way):
    protected function writeRelation($relation) 
    {
        ...
        // An array of objects is given
        foreach($this->owner->$key as $foreignobject)
        {
            if(!is_numeric($foreignobject))
            {
                //$foreignobject = $foreignobject->{$foreignobject->$relation['m2mForeignField']};
                $foreignobject = $foreignobject->{$foreignobject->tableSchema->primaryKey};
            }
            $this->execute($this->makeManyManyInsertCommand($relation, $foreignobject));
        }
    }

Here we use primary key name from foreign table instead of key name from relation table.
1

#22 User is offline   mrbig 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 1
  • Joined: 02-June 10

Posted 02 June 2010 - 04:29 AM

View Postseb, on 20 May 2010 - 03:30 AM, said:

Hi,

Thanks for great component!

I found small issue with current CAdvancedArBehavior version.


I did the following modification to the original code, this is even shorter
diff --git a/protected/extensions/CAdvancedArBehavior.php b/protected/extensions/CAdvancedArBehavior.php
index 803b75f..2a00aeb 100644
--- a/protected/extensions/CAdvancedArBehavior.php
+++ b/protected/extensions/CAdvancedArBehavior.php
@@ -156,7 +156,7 @@ class CAdvancedArbehavior extends CActiveRecordBehavior
                {
                        if(!is_numeric($foreignobject))
                        {
-                               $foreignobject = $foreignobject->{$foreignobject->$relation['m2mForeignField']};
+                               $foreignobject = $foreignobject->getPrimaryKey();
                        }
                        $this->execute($this->makeManyManyInsertCommand($relation, $foreignobject));
                }


2

#23 User is offline   Sander 

  • Standard Member
  • PipPip
  • Yii
  • Group: Members
  • Posts: 169
  • Joined: 03-November 09
  • Location:Amsterdam, Netherlands

Posted 15 July 2010 - 05:58 AM

I like this extension, it works beautifully. One thing: My app is using a SQLite database, which causes the "insert ignore" and "delete ignore" queries to fail. Dropping the ignore keyword from the query fixes this, so maybe you could conditionally insert the ignore keyword only for dbms that actually support it.

Apart from that little thing, well done!
0

#24 User is offline   JoeCoT 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 2
  • Joined: 15-July 10

Posted 15 July 2010 - 10:42 AM

Seems to work great, only problem I have is that it doesn't seem to work with $model->attributes assignment.

The relation I have is $model->extensions.

If I do this (which is the default) when updating:

$model->attributes=$_POST['Foo'];


$model->extensions isn't updated, even though $_POST['Foo']['extensions'] exists and is an array. I ended up doing this:
if(isset($_POST['Foo']['extensions'])){
        $model->extensions = $_POST['Foo']['extensions'];
        unset($_POST['Foo']['extensions']);
}
else $model->extensions = Array();


Also had to update lines 109 and 114 per rafa.informatica's review, in order to get it to remove all if the array is empty
0

#25 User is offline   Sander 

  • Standard Member
  • PipPip
  • Yii
  • Group: Members
  • Posts: 169
  • Joined: 03-November 09
  • Location:Amsterdam, Netherlands

Posted 16 July 2010 - 08:18 AM

View PostJoeCoT, on 15 July 2010 - 10:42 AM, said:

Seems to work great, only problem I have is that it doesn't seem to work with $model->attributes assignment.

The relation I have is $model->extensions.

If I do this (which is the default) when updating:

$model->attributes=$_POST['Foo'];


$model->extensions isn't updated, even though $_POST['Foo']['extensions'] exists and is an array. I ended up doing this:
if(isset($_POST['Foo']['extensions'])){
        $model->extensions = $_POST['Foo']['extensions'];
        unset($_POST['Foo']['extensions']);
}
else $model->extensions = Array();


Also had to update lines 109 and 114 per rafa.informatica's review, in order to get it to remove all if the array is empty



Did you add a rules() element for your extensions property to declare it safe? Otherwise Yii omits it by default during mass assignment.
0

#26 User is offline   JoeCoT 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 2
  • Joined: 15-July 10

Posted 16 July 2010 - 09:05 AM

View PostSander, on 16 July 2010 - 08:18 AM, said:

Did you add a rules() element for your extensions property to declare it safe? Otherwise Yii omits it by default during mass assignment.


Good point! Hadn't considered that.
0

#27 User is offline   edwaa 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 21
  • Joined: 17-May 09
  • Location:Seattle, WA

Posted 25 July 2010 - 05:24 PM

This is a great extension!

One question: how do I delete all MANY_MANY entries for a given related record? For example, what if I wanted to delete all MANY_MANY relation records for a given post_id?
0

#28 User is offline   Junior - df9 

  • Advanced Member
  • PipPipPip
  • Yii
  • Group: Members
  • Posts: 416
  • Joined: 24-May 09
  • Location:Brazil

Posted 26 July 2010 - 06:06 AM

in my opinion, you have at least two ways to solve this:

1 - set in the database relation "on delete cascade"

2 - put in the afterDelete() event of your model some code to delete all related records


i think the 1 is more elegant

:)

regards!!
______________________________________
Junior
df9.com.br
Linux Registered User #364954
GNU/Linux: together we're ready!
0

#29 User is offline   cma 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 9
  • Joined: 28-July 09

Posted 27 July 2010 - 09:40 AM

I have faced problems when the relation is empty with v.3. I have changed writeRelation like above

  /** writeRelation's job is to check if the user has given an array or an
   * single Object, and executes the needed query */
  protected function writeRelation ( $relation )
  {
    $key = $relation['key'];
    
    // Only an object or primary key id is given
    if ( is_object( $this->owner->$key ) )
    {
      $this->owner->$key = array( $this->owner->$key );
    }
    
    // An array of objects is given
    foreach ( $this->owner->$key as $foreignobject )
    {
      if( !empty( $foreignobject ) )
      {
        if ( ! is_numeric( $foreignobject ) )
        {
          // $foreignobject = $foreignobject->{$foreignobject->$relation['m2mForeignField']};
          //fix seb
          //$foreignobject = $foreignobject->{$foreignobject->tableSchema->primaryKey};
          //fix mrBig
          $foreignobject = $foreignobject->getPrimaryKey();
        
        }
        $this->execute( $this->makeManyManyInsertCommand( $relation , $foreignobject ) );
      }
    }
  }

0

#30 User is offline   el chief 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 56
  • Joined: 24-November 10

Posted 26 November 2010 - 06:33 PM

this is the latest version, yes?

http://code.google.c...avior.php?r=179

do I have to do anything special to use it with a checkboxlist or listbox? such as marking attributes as safe, or loading them , or calling save?
http://learnyii.blogspot.com/

Quick snippets to get you up to speed with the Yii PHP framework
0

#31 User is offline   vaizeman 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 26
  • Joined: 10-December 10

Posted 16 December 2010 - 06:26 AM

Hi,
I've tested your extension with transaction and it doesn't seem to work.
Here my code

//set relations
$model->roles=$role->Ruolo;

$transaction=$model->dbConnection->beginTransaction();
try
{
	$checkVal=$model->save(false);

	if($checkVal){
		if(!empty($ips)){
			foreach($ips as $i=>$item){
				if(!empty($item->IP)){
					$item->IDUser=$model->IDUser;
					$item->sdave(false);
				}
			}
		}
	}

	$transaction->commit();

	if($checkVal)
	$this->redirect(array('view','id'=>$model->IDUser));
}
catch(Exception $e)
{
	$transaction->rollBack();
	$errorMessage="Achtung!! error!";
	Yii::app()->user->setFlash('errorMessage',$errorMessage);
}


the model is the following:
User
Role
IP

the User has many to many relations with Role and 0 to many relations with IP

without error it works well and save the related table well.

If I trigger an error (sdave method) the values are still saved in the db
0

#32 User is offline   vaizeman 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 26
  • Joined: 10-December 10

Posted 16 December 2010 - 06:55 AM

View Postvaizeman, on 16 December 2010 - 06:26 AM, said:

Hi,
I've tested your extension with transaction and it doesn't seem to work.
Here my code

//set relations
$model->roles=$role->Ruolo;

$transaction=$model->dbConnection->beginTransaction();
try
{
	$checkVal=$model->save(false);

	if($checkVal){
		if(!empty($ips)){
			foreach($ips as $i=>$item){
				if(!empty($item->IP)){
					$item->IDUser=$model->IDUser;
					$item->sdave(false);
				}
			}
		}
	}

	$transaction->commit();

	if($checkVal)
	$this->redirect(array('view','id'=>$model->IDUser));
}
catch(Exception $e)
{
	$transaction->rollBack();
	$errorMessage="Achtung!! error!";
	Yii::app()->user->setFlash('errorMessage',$errorMessage);
}


the model is the following:
User
Role
IP

the User has many to many relations with Role and 0 to many relations with IP

without error it works well and save the related table well.

If I trigger an error (sdave method) the values are still saved in the db


solved. one of my tables was myisam.
0

#33 User is offline   Michel Kogan 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 21
  • Joined: 28-February 11

Posted 28 April 2011 - 05:43 AM

I think first version (+update part) is the best version. Is there any alternative for this script right now ( after about 2 years )
0

#34 User is offline   intel352 

  • Standard Member
  • PipPip
  • Yii
  • Group: Members
  • Posts: 196
  • Joined: 05-February 10
  • Location:Southport, NC

Posted 28 April 2011 - 08:13 AM

Check Thyseus' extensions, he continued this thought process into a packaged extension long ago.
Need live Yii support? - Join the #yii IRC channel on Freenode!
0

#35 User is offline   Toan Do 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 1
  • Joined: 10-May 11

Posted 16 May 2011 - 03:31 AM

Hey Rangel Reale:
When use '$this->owner'. It occurs the following error: Property "UserGroupsUser.owner" is not defined

Please help me

Cheers
0

#36 User is offline   duna 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 18
  • Joined: 04-May 11

Posted 17 May 2011 - 04:33 AM

http://code.google.c...dArBehavior.php

In line 159 the id of the realted object is retrieved if a object is passed to store as related:

$foreignobject = $foreignobject->{$foreignobject->$relation['m2mForeignField']};


I think it must be:

$foreignobject = $foreignobject->{$foreignobject->tableSchema->primaryKey};


Example:
Category.id
PostCategories.category_id
PostCategories.post_id
Post.id

$Post->categories = array(Category::model()->findByPk(1));

$foreignobject is an object of Category, its id is stored in $foreignobject->id but the value of $relation['m2mForeignField'] is `category_id`.

Ihe downloads at http://www.yiiframew...ncedarbehavior/ are outdated (v0.1 and v0.2)
0

#37 User is offline   dhampik 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 30
  • Joined: 25-January 11
  • Location:Russia

Posted 24 May 2011 - 06:12 AM

As people write above,

the latest version is on google code and you should apply mrbig's patch

Quote

diff --git a/protected/extensions/CAdvancedArBehavior.php b/protected/extensions/CAdvancedArBehavior.php
index 803b75f..2a00aeb 100644
--- a/protected/extensions/CAdvancedArBehavior.php
+++ b/protected/extensions/CAdvancedArBehavior.php
@@ -156,7 +156,7 @@ class CAdvancedArbehavior extends CActiveRecordBehavior
                {
                        if(!is_numeric($foreignobject))
                        {
-                               $foreignobject = $foreignobject->{$foreignobject->$relation['m2mForeignField']};
+                               $foreignobject = $foreignobject->getPrimaryKey();
                        }
                        $this->execute($this->makeManyManyInsertCommand($relation, $foreignobject));
                }


thyseus, please update your extension on yii site and on google code!
0

#38 User is offline   thyseus 

  • Advanced Member
  • PipPipPip
  • Yii
  • Group: Members
  • Posts: 301
  • Joined: 18-April 09
  • Location:Leipzig, Germany

Posted 25 May 2011 - 06:05 AM

Hey people,

good to know that people still uses this extension.

I just packaged a new version.

Thanks to dhampik to drop me a notice that there is still demand for this extension.

changelog:

- added $ignoreRelations to ignore specified relations. The Behavior
will take all found many2many relations by default. Specify exceptions in
this array.
- fixes all the bugs and glitches found in the discussion

please TEST and tell me if i forgot something ? :)
0

#39 User is offline   dhampik 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 30
  • Joined: 25-January 11
  • Location:Russia

Posted 25 May 2011 - 06:24 AM

View Postthyseus, on 25 May 2011 - 06:05 AM, said:

please TEST and tell me if i forgot something ? :)


thyseus,
I just tested it and I get an error when I try to save model with the current version of extension.
The exception is on line
$foreignobject = $foreignobject->{$foreignobject->$relation['m2mForeignField']};


It seems that the following happens:
3 tables {{news <id, title, text>}}, {{news_region <id, news_id, region_id>}} and {{region <id, name>}}.
Your script tries to get region.region_id property, instead of region.id property and that causes an error.
This problem could be solved with mrbig's patch. See the discussion above.
0

#40 User is offline   Ma Sivakumar 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 1
  • Joined: 31-August 10

Posted 21 July 2011 - 09:20 PM

Thanks for the useful extension.

A. With Postgresql as database, I had to change the following lines.

142c142
<                                               $info['m2mThisField'] = $this->owner->tableSchema->PrimaryKey;
---
>                                               $info['m2mThisField'] = $this->owner->tableSchema->primaryKey;


193c193
<               return sprintf("delete ignore from %s where %s = '%s'",
---
>               return sprintf("delete from %s where %s = '%s'",


B. To recap procedure to use this extension (collected from various places)

Use Case : A medicine contains many constituents, A constituent can be part of many medicines.

1. Download into protected/extensions http://www.yiiframew...ehavior.php.bz2

2. Extract
bunzip2 CAdvancedArBehavior.php.bz2


3. Import in config/main.php
        
'import'=>array(
                'application.models.*',
                'application.components.*',
+               'application.extensions.CAdvancedArBehavior',
        ),


4. To define many to many relation between medicine and contents
In relations() method of models/Constituent.php
   return array(
+ 'medicines' => array(self::MANY_MANY,'Medicine','masters.medicine_contents(constituent_id,medicine_id) '),
  );


In relations() method of models/Medicine.php
   return array(
+'constituents' => array(self::MANY_MANY,'Constituent','masters.medicine_contents(medicine_id,constituent_id) '),
  );


5. To make CAdvancedArBehavior available, add the following in models/Medicine.php
+       public function behaviors(){
+          return array( 'CAdvancedArBehavior' => array(
+            'class' => 'application.extensions.CAdvancedArBehavior'));
+          }


6. In actionCreate() and actionUpdate() methods of controllers/MedicineController.php
  • Assign constituents from POST before save() is called.
  • Based on the relations defined for medicine (above), CAdvancedArBehavior makes corresponding entries in medicine_contents table


+$medicine->constituents=$_POST["Medicine"]["constituents"];
$medicine->save();
$this->redirect(array('view','id'=>$medicine->medicine_id));


7. UI to select 5 constituents for each medicine using a Drop Down list (To Do : option to select 0 or more, using javascript)

In views/medicine/_form.php
<div class="row">
<?php
$criteria=new CDbCriteria(array('order'=>'constituent_name',));
$constituentArs=Constituent::model()->findAll($criteria);

for($i=0; $i<5; $i++)
  {
  ?>
  <div class="row"> 
    <?php echo CHtml::activeDropDownList($medicine, "constituents[$i]", CHtml::listData($constituentArs, 'constituent_id', 'constituent_name'),array('prompt'=>'--Select--'));?>
<?php //echo $form->textField($constituent,'quantity',array('size'=>4,'maxlength'=>4));?>
  </div> 
  <?php
  }
?>
</div>

1

Share this topic:


  • (3 Pages)
  • +
  • 1
  • 2
  • 3
  • You cannot start a new topic
  • You cannot reply to this topic

1 User(s) are reading this topic
0 members, 1 guests, 0 anonymous users