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.

We've moved the forum!

Please use forum.silverstripe.org for any new questions (announcement).
The forum archive will stick around, but will be read only.

You can also use our Slack channel or StackOverflow to ask for help.
Check out our community overview for more options to contribute.

Data Model Questions /

Moderators: martimiz, Sean, Ed, biapar, Willr, Ingo, swaiba

Has_one but belongs_many_many


Go to End


8 Posts   3175 Views

Avatar
Stefdv

Community Member, 110 Posts

5 March 2011 at 10:14am

Hello,

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 ?

Avatar
swaiba

Forum Moderator, 1899 Posts

6 March 2011 at 12:49am

Edited: 06/03/2011 12:49am

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.

Avatar
Stefdv

Community Member, 110 Posts

6 March 2011 at 1:02am

Edited: 06/03/2011 2:28am

Swaiba,

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)

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

Avatar
Stefdv

Community Member, 110 Posts

7 March 2011 at 4:10am

Edited: 07/03/2011 4:28am

Back again :(

help...

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

Avatar
Stefdv

Community Member, 110 Posts

7 March 2011 at 4:49am

Edited: 07/03/2011 5:02am

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'=> ????)

Avatar
swaiba

Forum Moderator, 1899 Posts

8 March 2011 at 1:53am

Could you explain your solution with the DataObjectNameID ?

sure...

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)

Avatar
Stefdv

Community Member, 110 Posts

9 March 2011 at 6:02am

Edited: 09/03/2011 6:35am

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
Avatar
Stefdv

Community Member, 110 Posts

10 March 2011 at 6:48am

Edited: 11/03/2011 5:20am

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.


		//Father
		 $mySet1 = DataObject::get('Dog', "Gendre = 'Male'", "PedigreeName ASC"); 
      		$map1 = $mySet1 ? $mySet1->toDropDownMap('ID', 'PedigreeName', 'Choose') : ''; 
     		$fields->addFieldToTab("Root.Main", new DropdownField('MyFatherID',  'Father', $map1  ));
	 
		//Mother
		 	$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.