Skip to main content

This site requires you to update your browser. Your browsing experience maybe affected by not having the most up to date version.

DataObjectManager Module /

Discuss the DataObjectManager module, and the related ImageGallery module.

Moderators: martimiz, UncleCheese, Sean, biapar, Willr, Ingo, swaiba, simon_w

Using ManyManyDataObjectManager on the belongs_many_many side


Reply


25 Posts   5726 Views

Avatar
MarcusDalgren

Community Member, 288 Posts

5 September 2009 at 2:16am

Ok the function that's causing the error is getRawDetailFields(). Currently it kills my Apache server after loading for awhile. Trying to figure out why.

Avatar
UncleCheese

Forum Moderator, 4096 Posts

5 September 2009 at 2:33am

Can one of you guys post the code you're using so I can set up a test case?

Avatar
MarcusDalgren

Community Member, 288 Posts

5 September 2009 at 2:44am

Edited: 05/09/2009 2:46am

It seems like the culprit is getCMSFields() in the related class. If the related class also has a ManyManyDataObjectManager then it kills my script.

Using the code I posted before the DataObjectManager works on the belongs_many_many side as long as you don't have a ManyManyDataObjectManager on the many_many side as well.

The reason for why it doesn't work is because you end up in an infinite loop. When getCMSFields() gets called on the other class then that in turn calls getCMSFields() on its related class and so on and so on ad infinitum. The way around this is that you HAVE TO define a getCMSFields_forPopup() method which passes in another fieldset than the one with the ManyManyDataObjectManager.

So in summary:

In the latest SVN version of ManyManyDataObjectManager replace this (line 31 to 35):

if( isset( $belongsManyManyRelations ) && array_key_exists( $this->name, $belongsManyManyRelations ) ) {
   $this->manyManyParentClass = $class;
   $manyManyTable = $belongsManyManyRelations[$this->name] . '_' . $this->name;
   break;
}


with this

if( isset( $belongsManyManyRelations ) && array_key_exists( $this->name, $belongsManyManyRelations ) ) {
   $newSingleton = singleton($belongsManyManyRelations[$this->name]);
   $relationships = $newSingleton->uninherited('many_many', true);
   $tie = array_search($controller->ClassName, $relationships);
   $this->manyManyParentClass = $class;
   $manyManyTable = $belongsManyManyRelations[$this->name] . '_' . $tie;
   break;
}


Then make sure to define popup getter methods in your dataobjectmanagers to avoid infinite loops. This is working great for me, let me know if it works.

Avatar
MarcusDalgren

Community Member, 288 Posts

5 September 2009 at 2:53am

Hello Uncle Cheese.

I am running a very basic test case for this with the latest trunk version of Silverstripe and and the latest SVN trunk version of your DataObjectManager. I have just two classes that extend the basic page class with a many many relationship between them.

Do you want me to setup a test case somewhere public where you can have a look at it?

Avatar
UncleCheese

Forum Moderator, 4096 Posts

5 September 2009 at 4:22am

Edited: 05/09/2009 4:23am

No, because I'd like to be able to make the edits to the DOM code to test the results. I know for some reason this forum doesn't have file attachments, but could you just dump your page and dataobject classes?

Careful, Smurkas, you don't want to rely on the popupfields method. It's not required by DOM or CTF that you define such a method. You can pass a Fieldset as the fifth argument to either, in which case the DataObject becomes fieldset agnostic.

Avatar
MarcusDalgren

Community Member, 288 Posts

5 September 2009 at 4:29am

Yeah I went looking for an attach file button so I could attach the classes.

Anyway repeating them here shouldn't be a problem.

So the first class looks like this

class ProductPage extends Page {
   
   static $db = array(
   );
   
   static $many_many = array(
      "Software"   => "SoftwarePage",
   );
   
   static $has_one = array(
   );
   
   public function getCMSFields() {
      $fields = parent::getCMSFields();
      $products = new ManyManyDataObjectManager(
    $this,
    'Software',
    'SoftwarePage',
    array(
       'Title' => 'Software Name',
    )
      );
$products->setPermissions(array('edit', 'delete'));
$products->setAddTitle('Related Software');
      $fields->addFieldToTab('Root.Content.Software', $products);
      return $fields;
   }
}

class ProductPage_Controller extends Page_Controller {
}

Avatar
MarcusDalgren

Community Member, 288 Posts

5 September 2009 at 4:31am

And the other one looks like this

class SoftwarePage extends Page {
   
   static $db = array(
   );

   static $belongs_many_many = array(
      "Products"       => "ProductPage",
   );
   
   static $has_one = array(
   );
   
   public function getCMSFields() {
      $fields = parent::getCMSFields();
   
      $products = new ManyManyDataObjectManager(
$this,
'Products',
'ProductPage',
array(
       'Title' => 'Product Name',
));
$products->setPermissions(array('edit', 'delete'));
$products->setAddTitle('Related Products');
      $fields->addFieldToTab('Root.Content.Products', $products);
      return $fields;
            
      return $fields;
   }
}

class SoftwarePage_Controller extends Page_Controller {
}

Avatar
MarcusDalgren

Community Member, 288 Posts

5 September 2009 at 4:39am

These are the only classes I have in the test system. If I remember correctly I first created a software page before actually putting the ManyManyDataObjectManager in there.

Like I said before, trying to create any of those two classes will fail since they will get stuck in an infinite loops when DataObjectManager calls getCMSFields() on the related object. The solution to this is either to define a custom field getter for the classes and pass the getters as an argument or pass in a fieldset like you suggested.

Like you said that isn't really a satisfactory solution since the $detailFormFields is supposed to be volountary.