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.

Data Model Questions

Has_one but belongs_many_many


8 Posts   2058 Views


5 March 2011 at 10:14am Community Member, 110 Posts


Here's my issue;

Dog has_one Pedigree
Dog belongs_many_many Pedigrees //A dog is the parent or grandparent of an other dog so belongs in a pedigree

Pedigree has_many Dogs //One pedigree can be for several dogs, like from one litter
Pedigree many_many Dogs //the pedigree has many dogs, Parents, grandparents, greatgrandparents

I manage my dogs with modeladmin, but the above relations give me time_out errors. I guess the problem lies in the fact that i create a loop. Edit a dog, create a pedigree that could hold the same dog i'm editing :(

Isn't this possible ?


6 March 2011 at 12:49am (Last edited: 6 March 2011 12:49am), Forum Moderator, 1796 Posts

Hi Stefdv,

this looks fine...

Dog has_one Pedigree
Pedigree has_many Dogs //One pedigree can be for several dogs, like from one litter

I don't follow this... surely (to match your comment) it would be Dog belongs_many_many Dog?

Dog belongs_many_many Pedigrees //A dog is the parent or grandparent of an other dog so belongs in a pedigree
Pedigree many_many Dogs //the pedigree has many dogs, Parents, grandparents, greatgrandparent

Anyway - yes I have found this also if a Dog has a relation back to itself (either directly or indirectly) ModelAdmin fails to scaffold. Whenever I encouter this I fake the relation ship (either the has_one simply becomes an DataObjectNameID => Int or I use a text field and put a csv id list in it.


6 March 2011 at 1:02am (Last edited: 6 March 2011 2:28am), Community Member, 110 Posts


Tx for the reply.

I 'solved' it in an other way.
I want to live by the D.R.Y. rule, so i want each Dog to exists only once in my DB.

Dog has_one Pedigree

Dog belongs_many_many Fathers,Mothers,GrandFathers...etc

Pedigree has_many Dogs

Pedigree has_one Father ,Mother,GrandFather....etc

Father many_many Dogs
Father has_many Pedigrees
{ same goes for Mother, GrandFather etc.}

Now i can create a pedigree by using dropdownfields for Father, Mother etc.
There are a lot of DO's, but that's no problem ( yet)

Asked a stupid question about the filter on a Dataobject::get ...
Sorry about that, that's kinda basic...even for me ;)


7 March 2011 at 4:10am (Last edited: 7 March 2011 4:28am), Community Member, 110 Posts

Back again :(


In my DataBase i've got the following tables;

dog -> ID
father ->ID
father_dogs -> fatherID, DogID
pedigree ->fatherID,motherID etc.

Now in my PedigreeAdmin (ModelAdmin) i have several DropDownTableFields where i choose the Dog that is the Father, Mother etc. (it shows the name of the Dogs, so that is good)
In the pedigree Table the fatherID gets a value, so that's good also.
But there it stops...the table father_dogs doesn't update...

For my dropdowntablefield i use;

new DropdownField('FatherID','',(DataObject::get('Dog', "Gendre = 'Male'", "PedigreeName ASC" )->toDropDownMap("ID", "PedigreeName", "Choose")));

I don't understand why the table father_dogs doesn't update.

In my father, mother etc DataObject i only have;

class Father extends DataObject
   static $has_many = array( 'Pedigrees' => 'Pedigree');
   static $many_many = array ('Dogs' => 'Dog');

As you can see, i don't really want to 'use' these DataObjects. I only need them as a link from my Pedigrees to my Dogs.
I need to link each Dog to be a Father or Grandfather in the Pedigree.

tx in advance


7 March 2011 at 4:49am (Last edited: 7 March 2011 5:02am), Community Member, 110 Posts

Stupid me

I never created the link from Dog to Father or Mother...That would imply that i have, on each dog, several Tabs/fields where i have to assign the Dog to a father, mother etc....That's not an option.

Swaiba, if your still following this post...

Could you explain your solution with the DataObjectNameID ?

I think i need to go this way...

My pedigree has fields that are named ; Father, Mother, Grandfather etc.
I need to populate these fields with Dogs, so my Father gets a DogID, Mother gets a DogID etc.

how do i setup my Pedigree.php?
static $db= array('Father'=> ????)


8 March 2011 at 1:53am Forum Moderator, 1796 Posts

Could you explain your solution with the DataObjectNameID ?


instead of...

$has_one = array('DataObjectName' => 'DataObjectName');

do this...

$db = array('DataObjectNameID' => 'Int');

it means you cannot do...

$doDataObjectName = $do->DataObjectName();

to get the has one, you need to do...

$doDataObjectName = DataObject::get_by_id('DataObjectName',$do->DataObjectNameID);

and in ModealAdmin getCMSFileds, you'll need to set it up for the dropdown field

$dos = DataObject::get('DataObjectName');
$map = $dos ? $dos->toDropdownMap($value,$strText) : array();
$fields->replaceField('DataObjectNameID',new DropdownField('DataObjectNameID','DataObjectName',$map);

same as this for a Many_many expect it stores a CSV list not an Int, except it's Text and when avoiding the relationship getters, the code is a little more complex (i.e. return a $dos from the ID list stored)


9 March 2011 at 6:02am (Last edited: 9 March 2011 6:35am), Community Member, 110 Posts

Okay, let's take it to the beginning please.

I attached a screenshot ( with a little editing ) from my ModelAdmin. This is how it looks now ( Thanks Swaiba for the Literalfield explanations ).

As you can see, this is how a Pedigree looks like. Now, i need to choose a Dog ( DataObject 'Dog' ) in every DropDown .
The funny part is, that i actually CAN choose a Dog in every field ( i use DataObject::get('Dog') for every Dropdown, so that makes sence.)

But it never saves it to any table....

I've made a DO for every subject.

Father has_one Dog
Mother has_one Dog etc.

Dog has_many Fathers etc....

Pedigree has_one Father etc.

But then i have to manage all these DO seperate, when all i want is some kind of 'link' from Pedigree->Father Field-> Dog

So i guess my real question ( for now ;) ) is...;

How do i populate the different DropDownFields with the same DO , and save it to 'what table' ?

If anyone can help out...well...THANK U

Attached Files

10 March 2011 at 6:48am (Last edited: 11 March 2011 5:20am), Community Member, 110 Posts

This topic can be marked as Solved.

I leave it here in case someone else wants to make a pedigree.

I want to thank everybody on the forum ( and especially Swaiba for the explanation about Literalfields and thinking with me ), because i used a lot of code from the forum.

I started with a new approach.

Each Dog only has to have a Father and a Mother. BUT...the Father and Mother are in fact 'Dog' DataObjects.

So i made a verry simple DataObject for the Father and Mother.

   class Father extends DataObject
   static $has_one= array   ('MyDog'          =>    'Dog');

Same for the Mother.

For the Dog i have;

stclass Dog extends DataObject
   static $db = array(   'Name'    =>    'Varchar', //and a lot more !

static $has_one = array('Image'=> 'Image',
                'MyFather'   =>   'Father',
                'MyMother'   =>   'Mother'

Now the fun part is that i'm not using the Father and Mother DataObjects at all. Somehow i need to create these to prevent an error.
In fact all i need is the Dog.MyFatherID and Dog.MyMotherID.

I created a Dropdownfield for both Father and Mother in my Dog DO.

       $mySet1 = DataObject::get('Dog', "Gendre = 'Male'", "PedigreeName ASC");
      $map1 = $mySet1 ? $mySet1->toDropDownMap('ID', 'PedigreeName', 'Choose') : '';
      $fields->addFieldToTab("Root.Main", new DropdownField('MyFatherID', 'Father', $map1 ));
          $mySet1 = DataObject::get('Dog', "Gendre = 'FeMale'", "PedigreeName ASC");
      $map1 = $mySet1 ? $mySet1->toDropDownMap('ID', 'PedigreeName', 'Choose') : '';
      $fields->addFieldToTab("Root.Main", new DropdownField('MyMotherID', 'Mother', $map1 ));

So i'm 'injecting' the FatherID and MotherID fields with a DogID.

Now i can get my Father and Mother with a function on my Dog DO. I get the Dog with the ID that was put in my MyFatherID.

function getMyDad() {
   $father = dataObject::get_by_id('Dog', $this->MyFatherID);
   return $father;


function getMyMom() {
   $mother = dataObject::get_by_id('Dog', $this->MyMotherID);
   return $mother;

In my template i can now buid a pedigree by putting a control MyDad inside a control MyDad inside a control MyDad etc.
ps. I could use $myDad.MyDad.Mydad etc. but i want to use the $Link to show a virtual page for every dog.

Well anyway ...i'm verry verry happy.

Thank u SlverStripe.