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.

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
Reply


9 Posts   3646 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