User form with additional fields

Hey at all,

I am stumbling upon the Account/User relationship once again.
I hope you can help me.

I have created a form to edit a user (username and role) which looked something like this before:

<f:form action="update" object="{account}" objectName="account">
    <f:form.textfield property="accountIdentifier" id="accountIdentifier" name="accountIdentifier" class="form-control" value="{account.accountIdentifier}" />
    <f:for each="{roles}" as="role">
        <f:form.checkbox name="roles" multiple="true" property="roles" value="{role}" /> {role.name}
    </f:for>
</f:form>

Now I want to add a checkbox where you can define if the user should receive notification mails.

This means an additional field in the User class (extending the AbstractParty class) which I call $isNotificationEnabled (as I cannot extend the Account class being part of the framework. Compare: Make account object extendable).

How do I have to change my form so that I can represent my user and my account?

Do I have to change the underlying object to “user”? Like this:

<f:form action="update" object="{user}" objectName="user">
//old account fields
<f:form.checkbox property="isNotificationEnabled" value="{user.isNotificationEnabled}" />
</f:form>

How would I include the account fields then?
(As the Account class is not a OneToOne relationship so that I cannot do the following:)

<f:form.textfield property="account.accountIdentifier" id="accountIdentifier" name="accountIdentifier" class="form-control" value="{user.account.accountIdentifier}" />

Generally I’m not sure how to implement forms that represent several objects. Is there a best practice or tutorial regarding more complex forms (in contrast to the NEOS context)?
Do I have to create a special class that is only used for representing the form? How would this look? Similar to this?

class UserForm {
    private $user;
    private $isNotificationEnabled;
    private $accountIdentifier;
    private $roles;
    
    public function __construct(AbstractParty $user) {
        $this->user = $user;
        $account = $user->getAccounts()->first();
        
        $this->isNotificationEnabled = $user->getIsNotificationEnabled();

        $this->accountIdentifier = $account->getAccountIdentifier();
        $this->roles = $account->getRoles();
    }

    //getters and setters
}

How do you do this? What about property mapping, validation and persistence?

I have found a solution myself:

To save both the user and the account I turned the form into a user form (instead of account form) and include the account fields like this:

<f:form action="update" object="{user}" objectName="user">
    <f:form.textfield property="account.accountIdentifier" id="accountIdentifier" name="accountIdentifier" />

    <f:for each="{roles}" as="role">
        <f:form.checkbox name="roles" multiple="true" property="account.roles" value="{role}" /> {role.name}
    </f:for>

    <f:form.checkbox property="isNotificationEnabled" value="isNotificationEnabled" checked="{user.isNotificationEnabled}" />

    <f:form.submit value="save" />
    <f:link.action action="list">cancel</f:link.action>
</f:form>

I solved the problem mentioned above (that I have no OneToOne relationship) by doing something like this (although the empty setter seems rather awkward):

class User extends AbstractParty {
  
  //Other getters and setters
  
  /**
   * @return Account
   * @throws \Exception
   */
  public function getAccount() {
     $accounts = $this->getAccounts();

     if($accounts->count() !== 1) {
        throw new \Exception('Expected exactly one related account.');
     }

     return $accounts->first();
  }

  /**
   * Dummy setter to prevent property mapping error.
   *
   * @param Account $account
   */
  public function setAccount(Account $account) {
  }
}

This cookbook entry is also interesting regarding the above mentioned problem (although I didn’t solve it like that):

https://wiki.typo3.org/Flow_Cookbook#Create_multiple_objects_with_one_Fluid_form