在SilverStripe中获取has_one关系

I have a DataObject called Applicant and it $has_one Member (this is the SilverStripe Member class).

private static $has_one = array (
    'MemberApplicant' => 'Member'
);

When a member is logged in and visits the ApplicationPage I want to be able to populate the form based on the members Applicant data.

I can make this work but I feel like I should be able to access the data easier.

Here is what I do:

$memberID = Member::currentUserID();
$applicant = Applicant::get()->filter('MemberApplicantID', $memberID)->first();

$form->loadDataFrom($applicant);

Shouldn't I be able to instantiate a Member and then call its relative $MemberApplicant?

Shouldn't I be able to instantiate a Member and then call its relative $MemberApplicant?

Of course. I assume you have a 1:1 relation, then you have to define the counter part on Member using $belongs_to (see this diagram)

class Applicant extends DataObject
{
private static $has_one = [
    'MemberApplicant' => 'Member'
];
...

class MemberApplicantExtenension extends DataExtension
{
private static $belongs_to = [
    'Applicant' => 'Applicant'
];

...

Now add the DataExtension to the Member object in /mysite/_config/config.yml

Member:
  extensions:
    - MemberApplicantExtenension

and run a dev/build?flush.

Now you're able to get the related Applicant from the Member using built in ORM magic:

//Get the current Member
$member = Member::CurrentUser();

//get the $belongs_to
$applicant = $member->Applicant();

It sounds like you want to be able to avoid an "additional" ORM query by going through the current user's Member record, however this is not how SilverStripe (Or any system that uses SQL JOINs works).

When you add a $has_one to a class, you essentially add a foreign key to that class's table. In your case it will be called MemberApplicantID, which is a foreign key to the Member table's primary key - its ID field. Thus your ORM query needs to go through an Applicant instance first.

Caveat: The above is not entirely true, DataObject does allow you to define a private (SilverStripe config) static $belongs_to on your model classes which lets you query "The other way around". I've never actually done this before, but it does look like you'd declare this on a custom DataExtension that decorates Member and has a value of "Applicant". See DataObject::belongsToComponent().

You can also simplify your existing ORM query slightly without having to instantiate a DataList explicitly, but the route to your target data remains the same:

// SilverStripe >= 3.2
$applicant = DataObject::get_one('Applicant', array('MemberApplicantID = ?' => $memberID));

// SilverStripe < 3.2
$applicant = DataObject::get_one('Applicant', '"MemberApplicantID" = ' . $memberID);