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

get parent relation ID before writting the Object


Go to End


12 Posts   14083 Views

Avatar
colymba

Community Member, 26 Posts

24 November 2012 at 1:23am

Hi,

Is it possible to get a Children DataObject $has_one ID before it is written?

I'll try to give an example:
A Product DataObject $has_many Items which are created through a GridField.
Each Item has a $has_one field that gets the ID of its parent Product (ProductID).
This ID is somehow automatically when the Item is created through the GridField.

What am wondering is, how can I get this parent ProductID of the Item being created (from within the getCMSFields function) before it is written to the database?

Hope this makes sense.

Thanks, Thierry

Avatar
zenmonkey

Community Member, 545 Posts

28 November 2012 at 2:04pm

That ParentID will be set automatically on write. If you want to see it, you could hide the Item GridField until after the Product is saved for the first time by wrapping it in if ($this->ID != 0){your grid field} the you could always also show the $this->ID in a LiteralField

I hope that's what you were asking

Avatar
colymba

Community Member, 26 Posts

28 November 2012 at 9:00pm

Thanks, this is actually how this ParentID is automatically set that interest me.
I tried to find out how this "magic" happens but haven't found anything yet. Since this is set automatically there must be a way to replicate the behaviour and find out what the ParentID will be even before the write function is called.

I considered parsing the URL since when adding an object from within a GridField, the ParentID is left in the URL, like this:
/admin/product-admin/Product/EditForm/field/Product/item/1/ItemEditForm/field/productTranslations/item/new

Where "1" is the future ParentID of the object being created.
Just wondering is there is a clean way to do this? Or how does SilverStripe does it? I would guess through the URLHandler?

Avatar
zenmonkey

Community Member, 545 Posts

29 November 2012 at 1:14am

I believe the magic happens in onAfterAfterWrite on one of the prime base classes. I've overloaded this before but you need to the parent function too and I usually check if the value if a value is set or a relation exists before performing any functions to make sure it doesn't get stuck in a loop.

Avatar
Andrew Houle

Community Member, 140 Posts

25 April 2013 at 2:16am

Has anyone got this working? I'm trying to do the same thing.

Avatar
zenmonkey

Community Member, 545 Posts

25 April 2013 at 2:23am

Well ID is autoincrement, so in theory you can guess it on the object Creation, last ID+1 save it in field, then in onAfterWrite double check and pass it to the relation if its differnt.

Avatar
Andrew Houle

Community Member, 140 Posts

25 April 2013 at 3:10am

Just in case it helps anyone else...

It's not my preferred solution, but for now I'm going with...

if($this->ID != 0) {
//Do stuff here after record has been saved
}
else {
//Record has never been saved...
$field = TextField::create('Field')->setTitle('Title')->setDisabled(true)->setValue('You can assign a this field once you have saved the record for the first time.');
}

Avatar
tractorcow

Community Member, 63 Posts

13 September 2013 at 1:40pm

Sorry for necrobumping if this is an old thread. I've just had this problem, and found the (probably correct) solution.

The GridFieldDetailForm (the object that handles sub-object creations in a GridField) can have a set of fields explicitly specified during construction of the actual GridField, which occurs in the parent object's getCMSFields function.

This means you can inject a set of fields at this point, each of which is aware of the parent ID of the object this new entity is being assigned to.

In the below example, I've chosen to simply use a dummy ProductModel, passed it the ID of the parent Product, and extracted its getCMSFields. Within the ProductModel::getCMSFields function, I can now use conditional logic based on the parentID.


class Product extends Page {
	public function getCMSFields() {
		$fields = parent::getCMSFields();
		
		// Models
		$modelsConfig = GridFieldConfig_RecordEditor::create();
		if($this->exists()) {
			// Ensure that fields are generated with knowledge of the parent
			$editComponent = $modelsConfig->getComponentByType('GridFieldDetailForm');
			$model = new ProductModel();
			$model->ProductID = $this->ID;
			$editComponent->setFields($model->getCMSFields());
		}
		$modelsField = new GridField('Models', 'Product Models', $this->Models(), $modelsConfig);
		$fields->addFieldToTab('Root.Models', $modelsField);
		
		return $fields;
	}
}

class ProductModel extends DataObject {
	public  function getCMSFields() {
		// ... in this code $this->Product() gives me the parent product, even if ProductModel hasn't been written to the database yet
	}
}

The downside of this approach, however, is that in ProductModel::getCMSFields, even if you are editing an existing record, $this->ID will be empty (since it uses the dummy object for creating the field list).

Go to Top