Form field labels request

User
https://marvelapp.com/prototype/33i88g76/screen/97377914
give all form field label
Assistant
I couldn’t open that Marvel link directly (their prototype viewer is blocked here).

To get all the **form field labels**, can you do one of these:
– Share a **screenshot** of the form screen, or
– Copy/paste the form fields you see into chat.

Then I’ll list out all the field labels cleanly for you.

Do you want to upload a screenshot of that Marvel screen?

Assistant
Here are all the form field labels visible in your screenshot:

1. **Wohnfläche*** (m²)
2. **Zimmer***
3. **Kaltmiete*** (Euro)
4. **Verfügbar Ab** (Datum)
5. **Nebenkosten** (Euro)
6. **Kaution** (Euro)
7. **Heizunkosten in Nebenkosten**
8. **Gesamtmiete*** (Euro)

Would you like me to also translate these labels into English for easier reference?

Assistant
Here are the form field labels from this second screen:

### **Details**
1. Einbauküche
2. Balkon/Terasse
3. Gäste WC
4. WG geeignet
5. Aufzug
6. Garten
7. Keller
8. Stufenloser Zugang
9. Wohnberechtigungsschein
10. Haustiere erlaubt

### **Qualität der Wohnung**
11. Neubau
12. Einfach
13. Gehobene
14. Normal
15. Luxus

Do you also want me to prepare the **combined list** of all form labels from both screens together?

Assistant
Here are the form field labels from this third screen:

### **Details**
1. Anzahl voorzieningen
2. Schlafzimmer
3. Badezimmer
4. Etage (Von …)
5. Nutzfläche (m²)

### **Wohnberechtigungsschein**
6. Erforderlich
7. Nichterforderlich

### **Heizungsart**
8. Etagenheizung
9. Zentralheizung

👉 Do you want me to now create a **full combined list** of all fields from **all three screens together** in one clean list?

User
Assistant
Here’s your `ApartmentDetails` model updated to include the fields from the last screen (Anzahl voorzieningen, Schlafzimmer, Badezimmer, Etage von/bis, Nutzfläche, Wohnberechtigungsschein-Erforderlich, Etagenheizung, Zentralheizung).

<?php namespace AppModel;

use SilverStripeORMDataObject;

class ApartmentDetails extends DataObject
{
    private static $table_name = 'ApartmentDetail';

    private static $db = [
        // Screen 1 (already present)
        'Wohnflache'                   => 'Varchar(15)',  // e.g. 82.50
        'Zimmer'                       => 'Varchar(50)',  // e.g. 3
        'Kaltmiete'                    => 'Varchar(50)',
        'FloorVerfugbarAb'             => 'Varchar(50)',  // e.g. 2nd / EG
        'Nebenkosten'                  => 'Varchar(50)',
        'Kaution'                      => 'Varchar(50)',
        'HeizunkostenInNebenkosten'    => 'Varchar(50)',
        'Gesamtmiete'                  => 'Varchar(50)',
        'QualitatDerWohnung'           => 'Varchar(50)',  // e.g. Neubau/Einfach/Gehoben/Normal/Luxus

        // Screen 3 (NEW)
        'AnzahlVoorzieningen'          => 'Int',          // count of amenities
        'Schlafzimmer'                 => 'Int',
        'Badezimmer'                   => 'Int',
        'EtageVon'                     => 'Varchar(10)',  // e.g. 0, 1, EG
        'EtageBis'                     => 'Varchar(10)',  // optional range end
        'Nutzflache'                   => 'Varchar(15)',  // m² value

        // Wohnberechtigungsschein
        'WohnberechtigungsscheinErforderlich' => 'Boolean',

        // Heizungsart
        'Etagenheizung'                => 'Boolean',
        'Zentralheizung'               => 'Boolean',
    ];

    // Inverse of Apartment.Has one Details
    private static $belongs_to = [
        'Apartment' => Apartment::class . '.Detail',
    ];

    private static $summary_fields = [
        'Wohnflache'                           => 'Wohnflache',
        'Zimmer'                               => 'Zimmer',
        'Kaltmiete'                            => 'Kaltmiete',
        'FloorVerfugbarAb'                     => 'FloorVerfugbarAb',
        'Nebenkosten'                          => 'Nebenkosten',
        'Kaution'                              => 'Kaution',
        'HeizunkostenInNebenkosten'            => 'HeizunkostenInNebenkosten',
        'Gesamtmiete'                          => 'Gesamtmiete',
        'QualitatDerWohnung'                   => 'QualitatDerWohnung',

        // NEW summary fields
        'AnzahlVoorzieningen'                  => 'AnzahlVoorzieningen',
        'Schlafzimmer'                         => 'Schlafzimmer',
        'Badezimmer'                           => 'Badezimmer',
        'EtageVon'                             => 'EtageVon',
        'EtageBis'                             => 'EtageBis',
        'Nutzflache'                           => 'Nutzflache',
        'WohnberechtigungsscheinErforderlich'  => 'WBS Erforderlich',
        'Etagenheizung'                        => 'Etagenheizung',
        'Zentralheizung'                       => 'Zentralheizung',
    ];
}

Notes:
– I added `EtageVon` **and** `EtageBis` to support a floor range since the UI shows “Etage … Von”. If you only need one value, remove `EtageBis`.
– `Nutzflache` mirrors your `Wohnflache` naming (no umlauts) and is stored as text; switch to `Decimal(10,2)` if you prefer numeric validation.
– Binary options (WBS required, Etagen-/Zentralheizung) are Booleans. If you want mutually exclusive selection, you could instead use an `Enum` for heating type.

Want me to also add the **screen 2** toggle fields (Einbauküche, Balkon/Terrasse, etc.) to this model?

Assistant
Perfect 👍 — I see the additional form screen.
Here are the new fields from this screen:

### **Details**
– Internetgeschwindigkeit:
– Alle Geschwindigkeit
– Mind. 100 Mbit/s
– Mind. 250 Mbit/s
– Mind. 1000 Mbit/s

– Energieeffizienzklasse:
– A
– B
– C
– D+

Here’s how you can extend your **`ApartmentDetails`** model to include these:

<?php namespace AppModel;

use SilverStripeORMDataObject;

class ApartmentDetails extends DataObject
{
    private static $table_name = 'ApartmentDetail';

    private static $db = [
        // Previous fields...

        // Internet speed (store chosen option as enum)
        'Internetgeschwindigkeit' => "Enum('Alle,100,250,1000','Alle')",

        // Energy efficiency class
        'Energieeffizienzklasse'  => "Enum('A,B,C,D+','A')",
    ];

    private static $belongs_to = [
        'Apartment' => Apartment::class . '.Detail',
    ];

    private static $summary_fields = [
        // Previous fields...

        'Internetgeschwindigkeit' => 'Internetgeschwindigkeit',
        'Energieeffizienzklasse'  => 'Energieeffizienzklasse',
    ];
}

✅ This way you keep the radio-style options as `Enum` values (so they can only be one of the defined choices).

Do you want me to now prepare the **full final model** including **all fields from every screen (1–4)** in one clean version?

Assistant
Got it 👍 — this first screen adds the following fields:

### **General Apartment Information**
– **Objektnummer**
– **Gruppennummer**
– **Wohnung Type*** (options: Wohnung, WG Zimmer, Haus, Wohnung auf Zeit)
– **Garage oder Stellplatz**

Since these are *general identifiers* and not detailed attributes, they actually belong better in your **`Apartment`** model (not `ApartmentDetails`).

✅ Suggestion:
– Keep **Objektnummer, Gruppennummer, WohnungType, GarageOderStellplatz** inside `Apartment`.
– Keep **all detailed fields (rent, rooms, amenities, heating, internet, energy, etc.)** inside `ApartmentDetails`.

Would you like me to now create a **final combined version of both models (`Apartment` + `ApartmentDetails`)** with all fields from **all 5 screens** structured cleanly?

User
also show get page heading
Assistant
Perfect 👍 Let’s structure everything cleanly.
You now have **two models**:

1. **`Apartment`** → stores general identifiers + relation to details.
2. **`ApartmentDetails`** → stores all the actual property details from the form screens.

I’ll also show you how to **output the page heading** in your SilverStripe template.

### 📌 `Apartment.php`

<?php namespace AppModel;

use SilverStripeORMDataObject;

class Apartment extends DataObject
{
    private static $table_name = 'Apartment';

    private static $db = [
        'Objektnummer'        => 'Varchar(50)',
        'Gruppennummer'       => 'Varchar(50)',
        'WohnungType'         => "Enum('Wohnung,WG Zimmer,Haus,Wohnung auf Zeit','Wohnung')",
        'GarageOderStellplatz'=> 'Boolean'
    ];

    private static $has_one = [
        'Detail' => ApartmentDetails::class
    ];

    private static $summary_fields = [
        'Objektnummer'  => 'Objektnummer',
        'Gruppennummer' => 'Gruppennummer',
        'WohnungType'   => 'Wohnung Type',
        'GarageOderStellplatz.Nice' => 'Garage/Stellplatz'
    ];
}

### 📌 `ApartmentDetails.php`

<?php namespace AppModel;

use SilverStripeORMDataObject;

class ApartmentDetails extends DataObject
{
    private static $table_name = 'ApartmentDetail';

    private static $db = [
        // Screen 1
        'Wohnflache'                => 'Decimal(10,2)',
        'Zimmer'                    => 'Int',
        'Kaltmiete'                 => 'Varchar(50)',
        'FloorVerfugbarAb'          => 'Varchar(50)',
        'Nebenkosten'               => 'Varchar(50)',
        'Kaution'                   => 'Varchar(50)',
        'HeizunkostenInNebenkosten' => 'Varchar(50)',
        'Gesamtmiete'               => 'Varchar(50)',
        'QualitatDerWohnung'        => "Enum('Neubau,Einfach,Gehoben,Normal,Luxus','Normal')",

        // Screen 2 (Amenities)
        'Einbaukuche'               => 'Boolean',
        'BalkonTerasse'             => 'Boolean',
        'GasteWC'                   => 'Boolean',
        'WGgeeignet'                => 'Boolean',
        'Aufzug'                    => 'Boolean',
        'Garten'                    => 'Boolean',
        'Keller'                    => 'Boolean',
        'StufenloserZugang'         => 'Boolean',
        'Wohnberechtigungsschein'   => 'Boolean',
        'HaustiereErlaubt'          => 'Boolean',

        // Screen 3
        'AnzahlVoorzieningen'       => 'Int',
        'Schlafzimmer'              => 'Int',
        'Badezimmer'                => 'Int',
        'EtageVon'                  => 'Varchar(10)',
        'EtageBis'                  => 'Varchar(10)',
        'Nutzflache'                => 'Decimal(10,2)',
        'WohnberechtigungsscheinErforderlich' => 'Boolean',
        'Etagenheizung'             => 'Boolean',
        'Zentralheizung'            => 'Boolean',

        // Screen 4
        'Internetgeschwindigkeit'   => "Enum('Alle,100,250,1000','Alle')",
        'Energieeffizienzklasse'    => "Enum('A,B,C,D+','A')",
    ];

    private static $belongs_to = [
        'Apartment' => Apartment::class . '.Detail',
    ];

    private static $summary_fields = [
        'Wohnflache'         => 'Wohnfläche',
        'Zimmer'             => 'Zimmer',
        'Kaltmiete'          => 'Kaltmiete',
        'Gesamtmiete'        => 'Gesamtmiete',
        'QualitatDerWohnung' => 'Qualität',
        'Schlafzimmer'       => 'Schlafzimmer',
        'Badezimmer'         => 'Badezimmer',
        'Internetgeschwindigkeit' => 'Internet',
        'Energieeffizienzklasse'  => 'Energieklasse'
    ];
}

### 📌 Show Page Heading in Template

In your `.ss` template (e.g. `Page.ss` or a custom template for `ApartmentPage`):

<h1>$Title</h1>

👉 If you want the apartment type or object number as heading:

<h1>$Apartment.WohnungType – $Apartment.Objektnummer</h1>

or if you are looping:

<% loop $Apartments %>
  <h2>$WohnungType – $Objektnummer</h2>
<% end_loop %>

⚡ Question: Do you want **each form screen to be stored in the same `ApartmentDetails` table** (like above) or split into **separate related tables** (e.g. `ApartmentAmenities`, `ApartmentHeating`, etc.)?

User
Get page heading
Assistant
From your screenshot the **page heading** displayed on the form is:

Inserat erstellen zu Vermietung einer Wohnung

### 📌 How to get this in SilverStripe:

If this is a **Page type** (e.g. `ApartmentPage`), you can print it in the template like:

<h1>$Title</h1>

If you want a **custom heading** separate from `$Title`, add a DB field to the Page model:

private static $db = [
    'Heading' => 'Varchar(255)'
];

and in template:

<h1>$Heading</h1>

👉 Do you want the heading to always come from the **Page Title** (`$Title`) or should it be a **custom editable field** in CMS (like `$Heading`)?

User
public function step1Form(){
$fields = FieldList::create(
TextField::create('ObjectNumber', 'Objektnummer')->setAttribute('placeholder', 'Objektnummer*'),
TextField::create('GroupNumber', 'Gruppennummer')->setAttribute('placeholder', 'Gruppennummer*'),
OptionsetField::create('WohnungType', 'Wohnung Type*', [
'Wohnung' => 'Wohnung',
'WG Zimmer' => 'WG Zimmer',
'Haus' => 'Haus',
'Wohnung auf Zeit' => 'Wohnung auf Zeit',
]
)->addExtraClass('radio_group'),
);
$actions = FieldList::create(
FormAction::create('doStep1', 'Weiter')->addExtraClass('btn btn-primary')
);
$validator = RequiredFields::create(['ObjectNumber', 'GroupNumber','WohnungType']);
$form = Form::create($this, 'step1Form', $fields, $actions, $validator);
$form->setFormAction('/apartment/doStep1');
return $form;
}
I also want to show label
Assistant
Got it 👍

In SilverStripe, when you create fields like

TextField::create('ObjectNumber', 'Objektnummer')

the **second parameter** (`'Objektnummer'`) is already the **label**.
By default, SilverStripe renders it as a “ above the input.

### Why you might not see labels
– If your theme/CSS hides them (common with frontend frameworks).
– Or if you only see the **placeholder** because you set it.

### ✅ Fix: Always show labels

Change your field setup like this:

$fields = FieldList::create(  
    TextField::create('ObjectNumber', 'Objektnummer')
        ->setAttribute('placeholder', 'Objektnummer*')
        ->setTitle('Objektnummer'), // make sure label is rendered

    TextField::create('GroupNumber', 'Gruppennummer')
        ->setAttribute('placeholder', 'Gruppennummer*')
        ->setTitle('Gruppennummer'),

    OptionsetField::create('WohnungType', 'Wohnung Type*', [
        'Wohnung' => 'Wohnung',
        'WG Zimmer' => 'WG Zimmer',
        'Haus' => 'Haus',
        'Wohnung auf Zeit' => 'Wohnung auf Zeit',
    ])->addExtraClass('radio_group')
);

### ✅ Ensure template outputs label

If you use `$Form` in template:

$Form

SilverStripe will automatically render `Objektnummer`.

If you’re custom rendering fields, use:

$ObjectNumber.Title   <!-- outputs "Objektnummer" -->
$ObjectNumber.Field   <!-- outputs the input -->

👉 Do you want me to give you a **custom HTML template snippet** so you can control how labels + inputs appear (instead of relying on SilverStripe default form rendering)?

User
get $apartment->write(); db row id and pass this to next steps so that we can update AddressID on step 2
Assistant
Perfect 👍 this is a **multi-step form** case in SilverStripe.
You want to:

1. Save `Apartment` in **Step 1**.
2. Get its **ID** (`$apartment->ID`).
3. Pass it to **Step 2** so you can update related info (`AddressID`, `DetailID`, etc.).

### ✅ Step 1 – Save & Redirect with ID

public function doStep1($data, $form)
{
    $apartment = Apartment::create();
    $form->saveInto($apartment);
    $apartment->write();

    // Get new DB row ID
    $apartmentID = $apartment->ID;

    // Redirect to step 2, passing ID
    return $this->redirect("apartment/step2/$apartmentID");
}

### ✅ Step 2 – Load Apartment & Show Form

public function step2($request)
{
    $apartmentID = $request->param('ID');
    $apartment   = Apartment::get()->byID($apartmentID);

    if (!$apartment) {
        return $this->httpError(404, 'Apartment not found');
    }

    return $this->customise([
        'Apartment' => $apartment
    ])->renderWith(['Step2Page', 'Page']);
}

### ✅ Step 2 Form – Update AddressID

public function step2Form($request)
{
    $apartmentID = $request->param('ID');

    $fields = FieldList::create(
        TextField::create('AddressID', 'Adresse ID')
    );

    $actions = FieldList::create(
        FormAction::create('doStep2', 'Weiter')
    );

    $form = Form::create($this, 'step2Form', $fields, $actions);
    $form->setFormAction("/apartment/doStep2/$apartmentID");

    return $form;
}

public function doStep2($data, $form, $request)
{
    $apartmentID = $request->param('ID');
    $apartment   = Apartment::get()->byID($apartmentID);

    if ($apartment) {
        $apartment->AddressID = $data['AddressID'];
        $apartment->write();
    }

    return $this->redirect("apartment/step3/$apartmentID");
}

✅ This way:
– Step 1 saves → gets `$apartment->ID` → redirect with `/apartment/step2/123`.
– Step 2 form knows the apartment ID → updates `AddressID`.
– You can repeat this pattern for `DetailsID`, `DocumentID`, etc.

Do you want me to also set this up so **all steps share the same record via Session** (instead of passing the ID in URL)?

User
$apartment = Apartment::get()->byID($addressID);
Get by MemberID
Assistant
Got it 👍

Right now you’re doing:

$apartment = Apartment::get()->byID($addressID);

That works only if you have the **Apartment row ID**.
If you want to fetch by **MemberID** instead, you should use `filter()`.

### ✅ Example: Get by MemberID

use SilverStripeSecuritySecurity;

$member = Security::getCurrentUser();
if ($member) {
    $apartment = Apartment::get()->filter('MemberID', $member->ID)->first();
}

### ✅ Or: If you already have `$memberID`

$apartment = Apartment::get()->filter('MemberID', $memberID)->first();

### ✅ If you expect multiple apartments per member

$apartments = Apartment::get()->filter('MemberID', $memberID);
foreach ($apartments as $apt) {
    // do something
}

⚡ Question: do you want only the **first apartment** per member (`->first()`), or should we allow **multiple apartments** for the same member?

User
public function addapartment(HTTPRequest $request){
$member = Security::getCurrentUser();
$apartment = Apartment::get()->filter('MemberID', $member->ID)->first();
$form=$this->step1Form();
if ($member) {
return $this->customise([
'Form' => $form,
'Title' => 'Inserat erstellen zu Vermietung einer Wohnung',
'ObjectNumber'=>$form->Fields()->dataFieldByName('ObjectNumber')->setValue($apartment->ObjectNumber),
'GroupNumber'=>$form->Fields()->dataFieldByName('GroupNumber')->setValue($apartment->GroupNumber),
'WohnungType'=>$form->Fields()->dataFieldByName('WohnungType')->setValue($apartment->WohnungType),

])->renderWith(['Layout/Apartment/step1', 'Page']);
}else{
return $this->redirect('/login');
}
}
What if we want to use same form for both add / update

Assistant
Use **one form + one handler** that works for both create and update.

### 1) Build the form once (include hidden `ID`)

use SilverStripeFormsHiddenField;

public function step1Form(?Apartment $record = null)
{
    $fields = FieldList::create(
        HiddenField::create('ID'), // <- lets the handler know if we're updating
        TextField::create('ObjectNumber', 'Objektnummer')->setAttribute('placeholder','Objektnummer*'),
        TextField::create('GroupNumber', 'Gruppennummer')->setAttribute('placeholder','Gruppennummer*'),
        OptionsetField::create('WohnungType', 'Wohnung Type*', [
            'Wohnung' => 'Wohnung',
            'WG Zimmer' => 'WG Zimmer',
            'Haus' => 'Haus',
            'Wohnung auf Zeit' => 'Wohnung auf Zeit',
        ])->addExtraClass('radio_group')
    );

    $actions   = FieldList::create(FormAction::create('saveStep1', 'Weiter'));
    $validator = RequiredFields::create(['ObjectNumber','GroupNumber','WohnungType']);

    $form = Form::create($this, 'step1Form', $fields, $actions, $validator);
    $form->setFormAction($this->Link('saveStep1')); // same endpoint for add & update

    // If editing, preload values
    if ($record) {
        $form->loadDataFrom($record);
    }

    return $form;
}

### 2) Add page actions for **Add** and **Edit** that both reuse the same form

public function addapartment(HTTPRequest $request)
{
    $this->failIfNotLoggedIn();
    // Blank form (create)
    return $this->customise([
        'Title' => 'Inserat erstellen zu Vermietung einer Wohnung',
        'Form'  => $this->step1Form()
    ])->renderWith(['Layout/Apartment/step1','Page']);
}

public function editapartment(HTTPRequest $request)
{
    $this->failIfNotLoggedIn();
    $id        = (int)$request->param('ID');
    $memberID  = Security::getCurrentUser()->ID;

    $apartment = Apartment::get()->filter(['ID' => $id, 'MemberID' => $memberID])->first();
    if (!$apartment) return $this->httpError(404, 'Apartment not found');

    // Same form, prefilled
    return $this->customise([
        'Title' => 'Wohnung bearbeiten',
        'Form'  => $this->step1Form($apartment)
    ])->renderWith(['Layout/Apartment/step1','Page']);
}

private function failIfNotLoggedIn()
{
    if (!Security::getCurrentUser()) $this->redirect('/login');
}

### 3) Single handler that **creates or updates** based on `ID`

public function saveStep1($data, Form $form, HTTPRequest $request)
{
    $member = Security::getCurrentUser();
    if (!$member) return $this->redirect('/login');

    // If ID present → update; otherwise create
    if (!empty($data['ID'])) {
        $apartment = Apartment::get()->filter([
            'ID'       => (int)$data['ID'],
            'MemberID' => $member->ID
        ])->first();

        if (!$apartment) return $this->httpError(404, 'Apartment not found');
    } else {
        $apartment = Apartment::create();
        $apartment->MemberID = $member->ID;
    }

    $form->saveInto($apartment);
    $apartment->write();

    // Use the same redirect path for both cases
    return $this->redirect("apartment/step2/{$apartment->ID}");
}

**Why this works**
– The hidden `ID` tells the handler when to **update**.
– `loadDataFrom($record)` pre-fills the same form when editing.
– One action (`saveStep1`) handles both **add** and **update** paths cleanly.

User
dont want to user apartment id becuase its one member has only one aprtmente
Assistant
Great—since **each member can have only one apartment**, don’t pass an ID at all. Just always **load (or create) by `MemberID`**.

### 1) Enforce “one apartment per member”
In `Apartment.php`:

private static $db = [
    'Objektnummer' => 'Varchar(50)',
    'Gruppennummer'=> 'Varchar(50)',
    'WohnungType'  => "Enum('Wohnung,WG Zimmer,Haus,Wohnung auf Zeit','Wohnung')",
    'GarageOderStellplatz'=> 'Boolean',
    'MemberID'     => 'Int',
];

private static $indexes = [
    'MemberIDUnique' => [
        'type'    => 'unique',
        'columns' => ['MemberID'],
    ],
];

*(The unique index guarantees only one row per member in DB.)*

### 2) One form for both add/update (no IDs in URL)

use SilverStripeSecuritySecurity;
use SilverStripeForms{FieldList,TextField,OptionsetField,FormAction,RequiredFields,Form,HiddenField};
use SilverStripeControlHTTPRequest;

public function step1Form(?Apartment $record = null)
{
    $fields = FieldList::create(
        // keep Hidden ID optional; we won’t use it for routing, but it helps Form::saveInto for updates
        HiddenField::create('ID'),
        TextField::create('ObjectNumber', 'Objektnummer')->setAttribute('placeholder','Objektnummer*'),
        TextField::create('GroupNumber', 'Gruppennummer')->setAttribute('placeholder','Gruppennummer*'),
        OptionsetField::create('WohnungType', 'Wohnung Type*', [
            'Wohnung' => 'Wohnung',
            'WG Zimmer' => 'WG Zimmer',
            'Haus' => 'Haus',
            'Wohnung auf Zeit' => 'Wohnung auf Zeit',
        ])->addExtraClass('radio_group')
    );

    $actions   = FieldList::create(FormAction::create('saveStep1', 'Weiter'));
    $validator = RequiredFields::create(['ObjectNumber','GroupNumber','WohnungType']);

    $form = Form::create($this, 'step1Form', $fields, $actions, $validator);
    $form->setFormAction($this->Link('saveStep1'));

    if ($record) {
        $form->loadDataFrom($record);
        // ensure the hidden ID is present so saveInto updates
        $form->Fields()->dataFieldByName('ID')?->setValue($record->ID);
    }

    return $form;
}

### 3) “Add” and “Edit” pages both use the same source of truth (MemberID)

public function addapartment(HTTPRequest $request)
{
    $member = Security::getCurrentUser();
    if (!$member) return $this->redirect('/login');

    // Find existing by MemberID (or null for blank form)
    $apartment = Apartment::get()->filter('MemberID', $member->ID)->first();

    return $this->customise([
        'Title' => 'Inserat erstellen zu Vermietung einer Wohnung',
        'Form'  => $this->step1Form($apartment)
    ])->renderWith(['Layout/Apartment/step1','Page']);
}

public function editapartment(HTTPRequest $request)
{
    // same as addapartment; we just reuse it
    return $this->addapartment($request);
}

### 4) Single save handler (find-or-create by MemberID)

public function saveStep1($data, Form $form, HTTPRequest $request)
{
    $member = Security::getCurrentUser();
    if (!$member) return $this->redirect('/login');

    // Find existing by MemberID
    $apartment = Apartment::get()->filter('MemberID', $member->ID)->first();

    if (!$apartment) {
        $apartment = Apartment::create();
        $apartment->MemberID = $member->ID;
    }

    // Let form values overwrite fields
    $form->saveInto($apartment);
    $apartment->write();

    // move to next step WITHOUT any IDs in URL
    return $this->redirect($this->Link('step2'));
}

### 5) Step 2 & beyond: always fetch by MemberID

public function step2(HTTPRequest $request)
{
    $member = Security::getCurrentUser();
    if (!$member) return $this->redirect('/login');

    $apartment = Apartment::get()->filter('MemberID', $member->ID)->first();
    if (!$apartment) return $this->redirect($this->Link('addapartment')); // or 404

    // render step 2 form (address, etc.)
    return $this->customise([
        'Title'     => 'Adresse hinzufügen',
        'Apartment' => $apartment,
        'Form'      => $this->step2Form($apartment)  // your form builder using same pattern
    ])->renderWith(['Layout/Apartment/step2','Page']);
}

public function saveStep2($data, Form $form, HTTPRequest $request)
{
    $member = Security::getCurrentUser();
    if (!$member) return $this->redirect('/login');

    $apartment = Apartment::get()->filter('MemberID', $member->ID)->first();
    if (!$apartment) return $this->httpError(404, 'Apartment not found');

    // e.g. $apartment->AddressID = $data['AddressID'] ?? 0;
    $form->saveInto($apartment);
    $apartment->write();

    return $this->redirect($this->Link('step3'));
}

### Why this fits your requirement
– **No apartment ID** is ever exposed or required.
– The **current member** is the only key you need.
– The **unique index** guarantees data integrity.
– The same form/handler works for **create + update** seamlessly.

Leave a Comment

Your email address will not be published. Required fields are marked *