This answers one of my questions:
http://doc.silverstripe.org/doku.php?id=datamodel#batch_update
$Desk->castedUpdate(
ArrayLib::filter_keys(
$_REQUEST,
array('DeskName', 'Floor')
)
);
This snippet is used to load submitted form items directly into a DataObject.
-- Jason
Edit: yes, this is the solution I was looking for.
Firstly, make sure the two DataObjects do not have fields with the same name, otherwise they will clash.
Define the master and detail objects (as before):
Employee.php
class Employee extends DataObject {
static $db = array(
'Name' => 'Varchar(255),
'Position' => 'Varchar(255)'
);
static $has_one = array(
'Desk' => 'Desk'
);
}
Desk.php
Remember we do not want a Desk to have many Employees. A Desk will have one Employee *or* one DeskPlant *or* one PersonalComputer (these cannot be modelled in SS at the moment).
class Desk extends DataObject {
static $db = array(
'DeskName' => 'Varchar(255),
'Floor' => 'Varchar(255),
);
}
DataModelAdmin EmployeeAdmin.php:
class EmployeeAdmin extends ModelAdmin {
public static $managed_models = array(
'Employee' // Not Desk
);
static $url_segment = 'employee';
static $menu_title = 'Employees';
}
In the getCMSFields() method, define the Desk fields in the second tab (the first tab will be populated with the Employee record):
class Employee extends DataObject {
...
function getCMSFields()
{
$fields = parent::getCMSFields();
// There has to be a way to create a bunch of form fields in bulk, from the DataObject?
$desk = $this->getComponent('Desk');
$fields->addFieldToTab('Root.Table', new TextField('DeskName', 'Desk Name', $desk->TableName));
$fields->addFieldToTab('Root.Table', new TextField('Floor', 'Floor', $desk->Floor));
return $fields;
}
}
Now handle the submission of the desk along with the Employee, linking the new desk record to the employee record when the employee is first created. We could be a little more clever and only create the desk in the database if (or when) actual data is submitted.
class Employee extends DataObject {
...
function onBeforeWrite()
{
$fields = parent::getCMSFields();
$desk = $this->getComponent('Desk');
$desk->castedUpdate(
ArrayLib::filter_keys(
$_REQUEST,
array('DeskName', 'Floor')
)
);
$desk->write();
if (!$this->ID) {
// New employee record; link the desk to the employee.
$this->DeskID = $desk->ID;
}
}
}
Seems to work great. In summary this is what we have achieved:
* A one-to-one relationship between Employee and Desk.
* When a new Employee is created, a Desk is created and linked to it.
* When we edit an Employee, a second tab allows us to edit the Desk at the same time.
I don't know if I am misusing getComponent() here. It returns the linked Desk if one exists, or a blank Desk otherwise. I *think* that is what it is meant to do...?