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.

General Questions /

General questions about getting started with SilverStripe that don't fit in any of the categories above.

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

Two DataObjects in one form


Go to End


9 Posts   4866 Views

Avatar
Judge

Community Member, 79 Posts

4 March 2010 at 1:55am

Edited: 04/03/2010 2:27am

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...?

Go to Top