Remove public from URL

User
remove public from silverstripe url
/public
Assistant
Got it—this usually happens when your domain points to the project root instead of the Silverstripe webroot (`/public`). Here are the clean ways to remove `/public` from the URL.

# Recommended (best practice): point your webroot to `/public`
**Apache (vhost)**

<VirtualHost *:80>
    ServerName example.com
    DocumentRoot /var/www/site/current/public

    <Directory /var/www/site/current/public>
        AllowOverride All
        Require all granted
    </Directory>
</VirtualHost>

**Nginx**

server {
    server_name example.com;
    root /var/www/site/current/public;
    index index.php;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ .php$ {
        include fastcgi_params;
        fastcgi_pass unix:/run/php/php8.2-fpm.sock; # adjust
        fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
    }
}

**cPanel / Plesk**
– Change the **Document Root** of the domain to `/public` (Domains → Document Root).
No URL will show `/public` after this.

# If you **can’t** change the document root (shared hosting)
Add this **.htaccess in your project root (above `/public`)** so Apache internally rewrites to `/public` without showing it:

<IfModule mod_rewrite.c>
  RewriteEngine On

  # Don’t loop if the request is already for /public
  RewriteRule ^public/ - [L]

  # Serve real files/folders that exist in the root (e.g. .well-known)
  RewriteCond %{REQUEST_FILENAME} -f [OR]
  RewriteCond %{REQUEST_FILENAME} -d
  RewriteRule ^ - [L]

  # Internally route everything else to /public
  RewriteRule ^(.*)$ public/$1 [L]
</IfModule>

This keeps the browser at `https://example.com/…` while the server serves from `/public`.

# Silverstripe config tips
– In `.env`, set your base URL to the root domain (no `/public`):

SS_BASE_URL="https://example.com"

– After changing server config, hit your site with `?flush` (e.g., `https://example.com/?flush`) to refresh cached configs/routes.

# What **not** to do
– Don’t move everything out of `/public` or change Composer’s `public-dir` to `.` unless you absolutely must; it weakens security. Using `/public` as the webroot is the intended, safer setup.

If you tell me your stack (Apache/Nginx/cPanel) and where your project lives, I can drop in the exact path-ready snippet.

User
Image upload in sliverstripe and save and show
Assistant
Here’s a clean, copy-paste path to **upload an image, save it, and show it** in Silverstripe (v4/v5). I’m giving both CMS and front-end options.

# 1) Add an Image relation on your object
Example `DataObject` (works the same on a `Page` subclass).

namespace AppModel;

use SilverStripeORMDataObject;
use SilverStripeAssetsImage;

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

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

    private static $has_one = [
        'Photo' => Image::class, // <-- the uploaded image
    ];

    // So the image auto-publishes with the record
    private static $owns = [
        'Photo',
    ];

    private static $summary_fields = [
        'Title',
        'Photo.CMSThumbnail' => 'Photo',
    ];
}

Run `/dev/build?flush`.

# 2) Upload via CMS (ModelAdmin/Page)
In your `DataObject` or `Page`:

use SilverStripeFormsFieldList;
use SilverStripeFormsTextField;
use SilverStripeAssetAdminFormsUploadField;

public function getCMSFields()
{
    $fields = parent::getCMSFields();

    $fields->addFieldsToTab('Root.Main', [
        TextField::create('Title'),
        UploadField::create('Photo', 'Profile Photo')
            ->setFolderName('profiles')                   // assets/profiles/
            ->setAllowedExtensions(['jpg','jpeg','png','webp'])
            ->setAllowedMaxFileNumber(1)
            ->setIsMultiUpload(false),
    ]);

    return $fields;
}

Publish the record. Because of `$owns = ['Photo']`, the image will also go Live.

# 3) Upload from a **front-end form** (controller)
## Form

use SilverStripeFormsForm;
use SilverStripeFormsFieldList;
use SilverStripeFormsTextField;
use SilverStripeFormsFormAction;
use SilverStripeFormsRequiredFields;
use SilverStripeAssetAdminFormsUploadField;
use SilverStripeControlController;

use AppModelProfile;

class ProfileController extends Controller
{
    private static $allowed_actions = ['Form','save'];

    public function Form()
    {
        $fields = FieldList::create(
            TextField::create('Title'),
            UploadField::create('Photo', 'Upload photo')
                ->setFolderName('profiles')
                ->setAllowedExtensions(['jpg','jpeg','png','webp'])
                ->setIsMultiUpload(false)
        );

        $actions = FieldList::create(
            FormAction::create('save', 'Save')
        );

        $validator = RequiredFields::create(['Title', 'Photo']);

        return Form::create($this, 'Form', $fields, $actions, $validator);
    }

    public function save($data, Form $form)
    {
        $record = Profile::create();
        // This will pull the uploaded file from UploadField and set PhotoID
        $form->saveInto($record);
        $record->write();

        // Make sure the image is publicly visible
        if ($record->PhotoID && $record->Photo()->isDraft()) {
            $record->Photo()->publishSingle();
        }

        return $this->redirect($this->Link('?saved=1'));
    }
}

> Note: Front-end uploads require permission to create files. If your users aren’t CMS users, gate the action (e.g., only for logged-in members) or add a custom policy/extension to allow uploads safely.

# 4) Show the image in a template
In your `.ss` template (e.g., `ProfilePage.ss` or where you loop items):

<% if $Photo %>
  <img src="$Photo.Fill(800,500).URL" alt="$Title.ATT">
<% else %>
  <p>No photo uploaded.</p>
<% end_if %>

Handy variants:
– `$Photo.ScaleMax(1200, 800).URL`
– `$Photo.Fit(600, 400).URL`
– `$Photo.URL` (original)

# 5) Common gotchas
– **Don’t move `/public`**: keep webroot at `/public` for security.
– **Publishing**: If content must be visible to anonymous users, ensure the image is **published**. Either call `$image->publishSingle()` (as above) or rely on `$owns` and publish the parent record.
– **Flush**: After code changes, open any URL with `?flush` to clear caches.
– **Folder names**: `setFolderName('profiles')` stores files under `assets/profiles/`.

If you share which object you’re attaching the image to (e.g., `MemberBasicData`, `RentalWorkerInformation`, or a `Page`), I’ll tailor the exact code block for that class.

User
UploadField::create('Bilder', 'Upload Image')
->setAllowedExtensions(['jpg', 'jpeg', 'png'])
->setAttribute('id', 'fileUpload')
->setAttribute('accept', 'image/jpeg, image/png')
->setAttribute('style', 'display:none;'),
I've created field like this
Assistant
Nice—now wire it up so it saves, publishes, and you can trigger it with your own button + preview.

## 1) DataObject relation

use SilverStripeORMDataObject;
use SilverStripeAssetsImage;

class Profile extends DataObject
{
    private static $db = ['Title' => 'Varchar(255)'];

    private static $has_one = [
        'Bilder' => Image::class, // matches your UploadField name
    ];

    private static $owns = ['Bilder']; // auto-publish with record
}

Run `/dev/build?flush`.

## 2) Field (keep yours, add single-file + folder)

use SilverStripeAssetAdminFormsUploadField;

$upload = UploadField::create('Bilder', 'Upload Image')
    ->setAllowedExtensions(['jpg','jpeg','png'])
    ->setIsMultiUpload(false)
    ->setAllowedMaxFileNumber(1)
    ->setFolderName('profiles')
    ->setAttribute('id', 'fileUpload') // wrapper id
    ->setAttribute('accept', 'image/jpeg, image/png')
    ->setAttribute('style', 'display:none;'); // you’re hiding the UI

## 3) Save (front-end controller action)

public function save($data, SilverStripeFormsForm $form)
{
    $record = Profile::create();
    $form->saveInto($record);  // sets BilderID
    $record->write();

    if ($record->BilderID) {
        $img = $record->Bilder();
        if ($img && $img->exists() && $img->isDraft()) {
            $img->publishSingle();
        }
    }

    return $this->redirect($this->Link('?saved=1'));
}

## 4) Custom trigger button + live preview (template)

<button type="button" id="pickImage" class="button">Choose image</button>
<div id="imgPreview">
  <% if $Bilder %>
    <img src="$Bilder.Fit(500,350).URL" alt="$Title.ATT">
  <% end_if %>
</div>

$Form <!-- make sure your form renders the hidden UploadField -->
<script>
(function(){
  const trigger = document.getElementById('pickImage');
  const holder  = document.getElementById('fileUpload');   // UploadField wrapper
  if (!trigger || !holder) return;

  // Find the real <input type="file"> inside UploadField
  const fileInput = holder.querySelector('input[type="file"]');

  trigger.addEventListener('click', function(e){
    e.preventDefault();
    if (fileInput) fileInput.click();
  });

  // Live preview (front-end only)
  holder.addEventListener('change', function(e){
    if (e.target === fileInput && fileInput.files && fileInput.files[0]) {
      const reader = new FileReader();
      reader.onload = function(ev){
        let img = document.querySelector('#imgPreview img');
        if (!img) {
          img = document.createElement('img');
          document.getElementById('imgPreview').appendChild(img);
        }
        img.src = ev.target.result;
        img.style.maxWidth = '100%';
        img.style.display = '';
      };
      reader.readAsDataURL(fileInput.files[0]);
    }
  });
})();
</script>

## 5) Show saved image anywhere

<% if $Bilder %>
  <img src="$Bilder.Fill(800,500).URL" alt="$Title.ATT">
<% end_if %>

### Notes
– Keep the field name **exactly** `Bilder` to match the `has_one` (`BilderID` is saved automatically by `saveInto`).
– `setIsMultiUpload(false)` + `setAllowedMaxFileNumber(1)` ensures single image.
– If files must be visible to guests, **publish** the image (done above).

User
this is form ss

$Title

Bilder

JPEG, PNG

$Bilder

<script>
const fileInput = document.getElementById('fileUpload');
					const fileName = document.getElementById('file-name');

					fileInput.addEventListener('change', function () {
						if (this.files.length > 0) {
							fileName.textContent = this.files[0].name;
						} else {
							fileName.textContent = 'Bilder';
						}
					});
</script>

$Description

$Form.Actions

Assistant
Great—your template is almost there. The only catch: **`UploadField` puts the `id` on its wrapper “, not on the real “.** So “ won’t open the picker automatically, and your JS is targeting the wrapper (which has no `.files`).

Here’s a drop-in fix:

## 1) PHP (field setup)
Keep your field, but ensure single file + folder (optional):

$upload = UploadField::create('Bilder', 'Upload Image')
    ->setAllowedExtensions(['jpg','jpeg','png'])
    ->setIsMultiUpload(false)
    ->setAllowedMaxFileNumber(1)
    ->setFolderName('profiles')
    ->setAttribute('id', 'fileUpload')               // id on wrapper div
    ->setAttribute('accept', 'image/jpeg, image/png')
    ->setAttribute('style', 'display:none;');        // hide UploadField UI

## 2) Template (.ss)
Use the label as your custom button, render the field, and wire the **real** file input inside the UploadField:

<!-- Your label UI -->
<label class="upload-box" for="fileUpload">
  <div class="upload-left">
    <img src="https://img.icons8.com/ios-filled/50/image--v1.png" alt="icon">
    <span class="file-name" id="file-name" style="display:block;">Bilder</span>
  </div>
  <span class="file-types">JPEG, PNG</span>
</label>

<!-- Render the UploadField (hidden wrapper with id="fileUpload") -->
$Form.FieldByName(Bilder)

### JS (forward label click to the hidden input + show file name)

<script>
(function(){
  // UploadField wrapper div (you set this id in PHP)
  const holder   = document.getElementById('fileUpload');
  const label    = document.querySelector('label[for="fileUpload"]');
  const fileName = document.getElementById('file-name');

  if (!holder || !label) return;

  // UploadField uses Dropzone; the real <input type="file"> lives inside the wrapper
  const getInput = () => holder.querySelector('input[type="file"]'); // usually .dz-hidden-input

  // Click label => open native picker
  label.addEventListener('click', function(e){
    e.preventDefault();
    const input = getInput();
    if (input) input.click();
  });

  // Update filename when a file is chosen
  function bindChangeOnce(input){
    if (input && !input.__wired) {
      input.addEventListener('change', function(e){
        const f = e.target.files && e.target.files[0];
        fileName.textContent = f ? f.name : 'Bilder';
      });
      input.__wired = true;
    }
  }

  // Input can be created dynamically; observe and bind when it appears
  const observer = new MutationObserver(() => bindChangeOnce(getInput()));
  observer.observe(holder, { childList: true, subtree: true });

  // If it already exists, bind now
  bindChangeOnce(getInput());
})();
</script>

> Why this works: `for="fileUpload"` targets your hidden **wrapper**; we intercept that click and programmatically click the real file input inside UploadField. We also watch the wrapper for dynamic changes (Dropzone adds the input), then bind a `change` listener to show the chosen filename.

## 3) Showing the saved image later

<% if $Bilder %>
  <img src="$Bilder.Fit(800,600).URL" alt="$Title.ATT">
<% end_if %>

## 4) Ensure it actually saves & publishes (controller)

public function save($data, SilverStripeFormsForm $form)
{
    $record = Profile::create();
    $form->saveInto($record); // sets BilderID from UploadField
    $record->write();

    if ($record->BilderID) {
        $img = $record->Bilder();
        if ($img && $img->exists() && $img->isDraft()) {
            $img->publishSingle();
        }
    }
    return $this->redirect($this->Link('?saved=1'));
}

If `$Form.FieldByName(Bilder)` doesn’t render in your template, use `$Form.Fields.dataFieldByName(Bilder)` instead.

User
public function step5() {
$form = $this->Step5Form();
$sessionData = $this->getRequest()->getSession()->get('MBData');
if($sessionData['InseriereAls'] == 'broker'){
$title = 'Firma omschrijving';
}else{
$title = 'Personaliche Angaben';
}

return $this->customise([
'Form' => $form,
'Title' => $title,
'Bilder' => $form->Fields()->dataFieldByName('Bilder'),
'Description' => $form->Fields()->dataFieldByName('Description')
])->renderWith(['Layout/RegistrationStep5', 'Page']);
}
above is the function that showing option for upload image

Assistant
Looks good! Two quick tweaks will make it rock-solid:

## 1) Make sure the UploadField has the wrapper id
In your `Step5Form()` (or wherever you build the form), set the id on the **UploadField wrapper** so your label/JS can target it:

UploadField::create('Bilder', 'Upload Image')
    ->setFolderName('profiles')
    ->setAllowedExtensions(['jpg','jpeg','png'])
    ->setIsMultiUpload(false)
    ->setAllowedMaxFileNumber(1)
    ->setAttribute('id', 'fileUpload'); // <-- wrapper div id

## 2) Render the form safely (CSRF + enctype) and wire the real input
Instead of a manual “, use the built-ins so Silverstripe adds `multipart/form-data` and the security token automatically:

$Form.OpenTag

  <!-- Your custom label/button -->
  <label class="upload-box" for="fileUpload">
    <div class="upload-left">
      <img src="https://img.icons8.com/ios-filled/50/image--v1.png" alt="icon">
      <span class="file-name" id="file-name" style="display:block;">Bilder</span>
    </div>
    <span class="file-types">JPEG, PNG</span>
  </label>

  <!-- Hidden UploadField wrapper -->
  $Bilder

  <!-- Other fields -->
  $Description

  $Form.Actions
$Form.CloseTag

If you want to keep your manual “, then **also include** the token:

$Form.SecurityToken

## 3) JS: click-through + filename (target the real “ inside UploadField)

<script>
(function(){
  const holder   = document.getElementById('fileUpload');          // UploadField wrapper div
  const label    = document.querySelector('label[for="fileUpload"]');
  const fileName = document.getElementById('file-name');

  if (!holder || !label) return;

  // Real file input lives inside the wrapper (Dropzone creates it)
  const getInput = () => holder.querySelector('input[type="file"]');

  label.addEventListener('click', function(e){
    e.preventDefault();
    const input = getInput();
    if (input) input.click();
  });

  function bindChangeOnce(input){
    if (input && !input.__wired) {
      input.addEventListener('change', function(e){
        const f = e.target.files && e.target.files[0];
        fileName.textContent = f ? f.name : 'Bilder';
      });
      input.__wired = true;
    }
  }

  // Input can be added later; observe then bind
  const obs = new MutationObserver(() => bindChangeOnce(getInput()));
  obs.observe(holder, { childList: true, subtree: true });

  // Bind immediately if already present
  bindChangeOnce(getInput());
})();
</script>

## 4) Save & publish on submit (controller action)

public function doStep5($data, SilverStripeFormsForm $form)
{
    $record = YourDataObject::create();
    $form->saveInto($record); // sets BilderID + Description
    $record->write();

    if ($record->BilderID && $record->Bilder()->isDraft()) {
        $record->Bilder()->publishSingle();
    }
    return $this->redirect($this->Link('step5') . '?saved=1');
}

That’s it—your label will open the native picker, the filename shows up, the form posts with the right `enctype` and CSRF, and the image gets saved + published.

User
public function doStep5(HTTPRequest $request) {
$data = $request->postVars();

$sessionData = $this->getRequest()->getSession()->get('MBData');
if($sessionData['InseriereAls'] == 'broker'){
$session = $this->getRequest()->getSession();

$allData = array_merge(
$session->get('BrokerCompanyData') ?: [],
$data
);

$hash = $request->getSession()->get('HashValue');
$memberID = $this->getMemberIDByField('TempIDHash', $hash);

if ($memberID) {
$companyData = MemberCompanyData::get()->filter('MemberID', $memberID)->first();
}

if (empty($companyData) || !$companyData->exists()) {
$companyData = new MemberCompanyData();
$companyData->MemberID = $memberID;
}

foreach ($allData as $key => $value) {
if ($companyData->hasField($key)) {
$companyData->$key = $value;
}
}

if (!empty($data['Bilder'])) {
$companyData->ImageID = $data['Bilder'];
}

$companyData->write();
$session->clear('BrokerCompanyData');

return $this->redirect('/public/registration/step6');
}else{
$session = $this->getRequest()->getSession();

$allData = array_merge(
$session->get('PersonalInfo') ?: [],
$data
);

$hash = $request->getSession()->get('HashValue');
$memberID = $this->getMemberIDByField('TempIDHash', $hash);

if ($memberID) {
$personalInfo = PersonalInformation::get()->filter('MemberID', $memberID)->first();
}

if (empty($personalInfo) || !$personalInfo->exists()) {
$personalInfo = new PersonalInformation();
$personalInfo->MemberID = $memberID;
}

//var_dump($data);

if (!empty($data['Bilder'])) {
$personalInfo->ImageID = $data['Bilder'];
}

foreach ($allData as $key => $value) {
if ($personalInfo->hasField($key)) {
$personalInfo->$key = $value;
}
}

$personalInfo->write();
$session->clear('PersonalInfo');

// Login script start //
$authenticator = new MemberAuthenticator();

$userName = $request->getSession()->get('userName');
$userPsd = $request->getSession()->get('userPsd');
$member = $authenticator->authenticate([
'Email' => $userName,
'Password' => $userPsd
], $request);

if ($member && $member->exists()) {
$memberBasicData = MemberBasicData::get()->filter('MemberID', $member->ID)->first();

if ($memberBasicData) {
$InseriereAls = $memberBasicData->InseriereAls;
$firstName = $memberBasicData->FirstName;
$lastName = $memberBasicData->LastName;

$request->getSession()->set('UserType', $InseriereAls);
$request->getSession()->set('CUFirstName', $firstName);
$request->getSession()->set('CULastName', $lastName);

$identityStore = Injector::inst()->get(IdentityStore::class);
$identityStore->logIn($member, false, $request);
}
}
// Login script end //

return $this->redirect('/public/registration/thankyou');
}
}

Assistant
You’re almost there—the only blocker is the **field name mismatch**.
Your `DataObject` uses `ImageID`, but your form field is named `Bilder`. With Silverstripe, the UploadField’s **name must match the has_one** to let `$form->saveInto()` wire it up.

## Fix (recommended)
1) In `Step5Form()` change:

UploadField::create('Image', 'Bilder')   // name = Image, label = Bilder
    ->setAllowedExtensions(['jpg','jpeg','png'])
    ->setIsMultiUpload(false)
    ->setAllowedMaxFileNumber(1)
    ->setFolderName('profiles')
    ->setAttribute('id', 'fileUpload')
    ->setAttribute('accept', 'image/jpeg, image/png')
    ->setAttribute('style', 'display:none;');

2) In the template, render the field by its **name**:

$Form.FieldByName(Image)

(Keep your custom label/JS as-is; it still targets `#fileUpload`.)

3) Update `doStep5()` to use the form to save and **publish** the image. No need to manually read `$data['Bilder']` anymore.

use SilverStripeFormsForm;

public function doStep5(SilverStripeControlHTTPRequest $request)
{
    $data = $request->postVars();
    $form = $this->Step5Form();
    $form->loadDataFrom($data); // make sure validators/transformers run

    $session = $this->getRequest()->getSession();
    $sessionData = $session->get('MBData');

    $hash = $session->get('HashValue');
    $memberID = $this->getMemberIDByField('TempIDHash', $hash);

    if ($sessionData['InseriereAls'] === 'broker') {
        $companyData = MemberCompanyData::get()->filter('MemberID', $memberID)->first() ?: MemberCompanyData::create(['MemberID' => $memberID]);

        // Save all posted fields (incl. Image) onto the object
        $form->saveInto($companyData);

        // If you still need to merge session fields:
        $allData = array_merge($session->get('BrokerCompanyData') ?: [], $data);
        foreach ($allData as $key => $value) {
            if ($companyData->hasField($key)) {
                $companyData->$key = $value;
            }
        }

        $companyData->write();

        // Publish the file so it’s visible to guests
        if ($companyData->ImageID && $companyData->Image()->isDraft()) {
            $companyData->Image()->publishSingle();
        }

        $session->clear('BrokerCompanyData');
        return $this->redirect('/public/registration/step6');

    } else {
        $personalInfo = PersonalInformation::get()->filter('MemberID', $memberID)->first() ?: PersonalInformation::create(['MemberID' => $memberID]);

        $form->saveInto($personalInfo);

        $allData = array_merge($session->get('PersonalInfo') ?: [], $data);
        foreach ($allData as $key => $value) {
            if ($personalInfo->hasField($key)) {
                $personalInfo->$key = $value;
            }
        }

        $personalInfo->write();

        if ($personalInfo->ImageID && $personalInfo->Image()->isDraft()) {
            $personalInfo->Image()->publishSingle();
        }

        // (Your login script unchanged)
        $authenticator = new MemberAuthenticator();
        $member = $authenticator->authenticate([
            'Email' => $session->get('userName'),
            'Password' => $session->get('userPsd')
        ], $request);

        if ($member && $member->exists()) {
            $memberBasicData = MemberBasicData::get()->filter('MemberID', $member->ID)->first();
            if ($memberBasicData) {
                $identityStore = Injector::inst()->get(IdentityStore::class);
                $identityStore->logIn($member, false, $request);
                $session->set('UserType', $memberBasicData->InseriereAls);
                $session->set('CUFirstName', $memberBasicData->FirstName);
                $session->set('CULastName', $memberBasicData->LastName);
            }
        }

        return $this->redirect('/public/registration/thankyou');
    }
}

## Bonus (optional, but helpful)
– In both `MemberCompanyData` and `PersonalInformation` models:

private static $has_one = [
      'Image' => SilverStripeAssetsImage::class,
  ];
  private static $owns = ['Image']; // auto-publish with parent (if versioned)

– After any code changes, do `?flush`.

### If you must keep the field name `Bilder`
Then map it manually and publish:

$imageID = (int)($data['Bilder'] ?? 0);           // might need to handle array shapes too
if ($imageID) {
    if ($file = SilverStripeAssetsImage::get()->byID($imageID)) {
        if ($file->isDraft()) $file->publishSingle();
        $companyData->ImageID = $file->ID;        // or $personalInfo->ImageID
    }
}

…but the clean way is to **rename the UploadField to `Image`** so `$form->saveInto()` just works.

User
but I want image name should be Bilder
Assistant
Totally fine—you can keep the **form field name = `Bilder`** and still save into your DB field `ImageID`. Just map it on submit.

## What to change (minimal)

1) Add a tiny helper to extract the uploaded file ID from UploadField (it can post as an int or array):

use SilverStripeAssetsImage;

private function extractUploadID($value): int
{
    if (!$value) return 0;
    if (is_numeric($value)) return (int)$value;

    if (is_array($value)) {
        if (isset($value['Files']) && is_array($value['Files']) && !empty($value['Files'])) {
            return (int)$value['Files'][0];
        }
        if (isset($value['id'])) return (int)$value['id'];
        if (isset($value[0])) return (int)$value[0];
    }
    return 0;
}

2) In your `doStep5()` keep `Bilder` as the field name, but map it to `ImageID` and publish:

### Broker branch

$imgID = $this->extractUploadID($data['Bilder'] ?? null);
if ($imgID) {
    if ($file = Image::get()->byID($imgID)) {
        $file->publishSingle();               // make it visible to guests
        $companyData->ImageID = $file->ID;    // map Bilder -> ImageID
    }
}

### Personal branch

$imgID = $this->extractUploadID($data['Bilder'] ?? null);
if ($imgID) {
    if ($file = Image::get()->byID($imgID)) {
        $file->publishSingle();
        $personalInfo->ImageID = $file->ID;
    }
}

> Keep the rest of your merging and `write()` calls as-is.

That’s it—**field shown in the form is `Bilder`**, your template keeps using `$Form.FieldByName(Bilder)`, and the saved relation remains `ImageID` on your objects.

### Optional (DB-level German naming)
If you want the **DB relation** to also be German, rename your `has_one` to:

private static $has_one = [
    'Bilder' => Image::class,
];
private static $owns = ['Bilder'];

…then `saveInto()` will work automatically with `UploadField::create('Bilder', …)`.
But this requires a data migration from `ImageID` → `BilderID` and a `/dev/build?flush`. If you don’t want schema changes, stick to the simple mapping above.

User
if ($record->BilderID && $record->Bilder()->isDraft()) {
$record->Bilder()->publishSingle();
}
want to save like this
So tell How I will show image at frontend
Assistant
Perfect—since you’re saving to a **has_one `Bilder`** and publishing it:

if ($record->BilderID && $record->Bilder()->isDraft()) {
    $record->Bilder()->publishSingle();
}

you can show it on the frontend like this.

# In a template for that object

<% if $Bilder %>
  <img src="$Bilder.Fit(800,600).URL" alt="$Title.ATT">
<% else %>
  <p>No image uploaded.</p>
<% end_if %>

Common variants:

$Bilder.URL                     <!-- original -->
$Bilder.Fill(600,400).URL       <!-- crop to exact size -->
$Bilder.Fit(600,400).URL        <!-- fit inside box -->
$Bilder.ScaleMax(1200,800).URL  <!-- keep aspect ratio, max bounds -->

Optional responsive example:

<img
  src="$Bilder.ScaleMax(600,400).URL"
  srcset="$Bilder.ScaleMax(600,400).URL 600w,
          $Bilder.ScaleMax(900,600).URL 900w,
          $Bilder.ScaleMax(1200,800).URL 1200w"
  sizes="(max-width: 700px) 100vw, 700px"
  alt="$Title.ATT">

# If you’re passing a record to the view
Example (Step 6 / Thank You page):

public function step6()
{
    $memberID = Security::getCurrentUser()?->ID;
    $company = MemberCompanyData::get()->filter('MemberID', $memberID)->first();

    return $this->customise(['Company' => $company])
                ->renderWith(['Layout/RegistrationStep6','Page']);
}

Template:

<% if $Company && $Company.Bilder %>
  <img src="$Company.Bilder.Fit(800,600).URL" alt="$Company.Title.ATT">
<% end_if %>

# Model tip (optional but nice)
In `MemberCompanyData` / `PersonalInformation`:

private static $has_one = ['Bilder' => SilverStripeAssetsImage::class];
private static $owns   = ['Bilder']; // auto-publishes with parent if versioned

You’re done—the image will render anywhere you output `$Bilder` (or `$Object.Bilder`) as above.

User
HOw to use in this function
public function doStep5(HTTPRequest $request) {
$data = $request->postVars();

$sessionData = $this->getRequest()->getSession()->get('MBData');
if($sessionData['InseriereAls'] == 'broker'){
$session = $this->getRequest()->getSession();

$allData = array_merge(
$session->get('BrokerCompanyData') ?: [],
$data
);

$hash = $request->getSession()->get('HashValue');
$memberID = $this->getMemberIDByField('TempIDHash', $hash);

if ($memberID) {
$companyData = MemberCompanyData::get()->filter('MemberID', $memberID)->first();
}

if (empty($companyData) || !$companyData->exists()) {
$companyData = new MemberCompanyData();
$companyData->MemberID = $memberID;
}

foreach ($allData as $key => $value) {
if ($companyData->hasField($key)) {
$companyData->$key = $value;
}
}

if (!empty($data['Bilder'])) {
$companyData->ImageID = $data['Bilder'];
}

$companyData->write();
$session->clear('BrokerCompanyData');

return $this->redirect('/public/registration/step6');
}else{
$session = $this->getRequest()->getSession();

$allData = array_merge(
$session->get('PersonalInfo') ?: [],
$data
);

$hash = $request->getSession()->get('HashValue');
$memberID = $this->getMemberIDByField('TempIDHash', $hash);

if ($memberID) {
$personalInfo = PersonalInformation::get()->filter('MemberID', $memberID)->first();
}

if (empty($personalInfo) || !$personalInfo->exists()) {
$personalInfo = new PersonalInformation();
$personalInfo->MemberID = $memberID;
}

//var_dump($data);

if (!empty($data['Bilder'])) {
$personalInfo->ImageID = $data['Bilder'];
}

foreach ($allData as $key => $value) {
if ($personalInfo->hasField($key)) {
$personalInfo->$key = $value;
}
}

$personalInfo->write();
$session->clear('PersonalInfo');

// Login script start //
$authenticator = new MemberAuthenticator();

$userName = $request->getSession()->get('userName');
$userPsd = $request->getSession()->get('userPsd');
$member = $authenticator->authenticate([
'Email' => $userName,
'Password' => $userPsd
], $request);

if ($member && $member->exists()) {
$memberBasicData = MemberBasicData::get()->filter('MemberID', $member->ID)->first();

if ($memberBasicData) {
$InseriereAls = $memberBasicData->InseriereAls;
$firstName = $memberBasicData->FirstName;
$lastName = $memberBasicData->LastName;

$request->getSession()->set('UserType', $InseriereAls);
$request->getSession()->set('CUFirstName', $firstName);
$request->getSession()->set('CULastName', $lastName);

$identityStore = Injector::inst()->get(IdentityStore::class);
$identityStore->logIn($member, false, $request);
}
}
// Login script end //

return $this->redirect('/public/registration/thankyou');
}
}

Assistant
Here’s a **drop-in update** for your `doStep5()` that keeps the form field name **`Bilder`**, saves it to a **has_one `Bilder`**, and publishes the image so it’s visible on the frontend.

### Prereqs (in both models)

// MemberCompanyData / PersonalInformation
use SilverStripeAssetsImage;

private static $has_one = [
    'Bilder' => Image::class,
];

private static $owns = [
    'Bilder',
];

Run `/dev/build?flush`.

### Controller helper (put inside your controller class)

use SilverStripeAssetsImage;

private function extractUploadID($value): int
{
    if (!$value) return 0;
    if (is_numeric($value)) return (int)$value;

    if (is_array($value)) {
        if (!empty($value['Files']) && is_array($value['Files'])) {
            return (int)$value['Files'][0];
        }
        if (isset($value['id'])) return (int)$value['id'];
        if (isset($value[0]))   return (int)$value[0];
    }
    return 0;
}

### Updated `doStep5()` (only the changed bits)

public function doStep5(HTTPRequest $request) {
    $data = $request->postVars();

    $sessionData = $this->getRequest()->getSession()->get('MBData');
    if ($sessionData['InseriereAls'] == 'broker') {
        $session = $this->getRequest()->getSession();

        $allData = array_merge($session->get('BrokerCompanyData') ?: [], $data);

        $hash = $session->get('HashValue');
        $memberID = $this->getMemberIDByField('TempIDHash', $hash);

        if ($memberID) {
            $companyData = MemberCompanyData::get()->filter('MemberID', $memberID)->first();
        }
        if (empty($companyData) || !$companyData->exists()) {
            $companyData = new MemberCompanyData();
            $companyData->MemberID = $memberID;
        }

        // Save other scalar fields
        foreach ($allData as $key => $value) {
            if ($companyData->hasField($key)) {
                $companyData->$key = $value;
            }
        }

        // Map form field "Bilder" -> relation "BilderID" and publish
        $imgID = $this->extractUploadID($data['Bilder'] ?? null);
        if ($imgID) {
            if ($img = Image::get()->byID($imgID)) {
                if ($img->isDraft()) {
                    $img->publishSingle();
                }
                $companyData->BilderID = $img->ID;
            }
        }

        $companyData->write();
        $session->clear('BrokerCompanyData');

        return $this->redirect('/public/registration/step6');
    } else {
        $session = $this->getRequest()->getSession();

        $allData = array_merge($session->get('PersonalInfo') ?: [], $data);

        $hash = $session->get('HashValue');
        $memberID = $this->getMemberIDByField('TempIDHash', $hash);

        if ($memberID) {
            $personalInfo = PersonalInformation::get()->filter('MemberID', $memberID)->first();
        }
        if (empty($personalInfo) || !$personalInfo->exists()) {
            $personalInfo = new PersonalInformation();
            $personalInfo->MemberID = $memberID;
        }

        // Save other scalar fields
        foreach ($allData as $key => $value) {
            if ($personalInfo->hasField($key)) {
                $personalInfo->$key = $value;
            }
        }

        // Map "Bilder" -> "BilderID" and publish
        $imgID = $this->extractUploadID($data['Bilder'] ?? null);
        if ($imgID) {
            if ($img = Image::get()->byID($imgID)) {
                if ($img->isDraft()) {
                    $img->publishSingle();
                }
                $personalInfo->BilderID = $img->ID;
            }
        }

        $personalInfo->write();
        $session->clear('PersonalInfo');

        // (Your login script unchanged)
        $authenticator = new MemberAuthenticator();
        $member = $authenticator->authenticate([
            'Email' => $session->get('userName'),
            'Password' => $session->get('userPsd')
        ], $request);

        if ($member && $member->exists()) {
            $memberBasicData = MemberBasicData::get()->filter('MemberID', $member->ID)->first();
            if ($memberBasicData) {
                $request->getSession()->set('UserType', $memberBasicData->InseriereAls);
                $request->getSession()->set('CUFirstName', $memberBasicData->FirstName);
                $request->getSession()->set('CULastName', $memberBasicData->LastName);
                $identityStore = Injector::inst()->get(IdentityStore::class);
                $identityStore->logIn($member, false, $request);
            }
        }

        return $this->redirect('/public/registration/thankyou');
    }
}

### Frontend display
Anywhere in your template where you have the object:

<% if $Bilder %>
  <img src="$Bilder.Fit(800,600).URL" alt="$Title.ATT">
<% end_if %>

This keeps your **form field name = `Bilder`**, saves to the **relation `Bilder`**, publishes the file, and makes it show up at `$Bilder.*` on the frontend.

User
we have MemberCompanyData db table which has column ImagedID
Assistant
Gotcha — since your DB column is **`ImagedID`**, just align your code to that and (optionally) add a small alias so you can still use `$Bilder` in templates.

## 1) Model: map the relation to `ImagedID` and add a `$Bilder` alias

use SilverStripeORMDataObject;
use SilverStripeAssetsImage;

class MemberCompanyData extends DataObject
{
    // ... your $db etc.

    private static $has_one = [
        'Imaged' => Image::class,   // matches column ImagedID
    ];

    private static $owns = [
        'Imaged',
    ];

    // Optional: let templates use $Bilder even though DB is ImagedID
    public function getBilder(): ?Image
    {
        return $this->Imaged();
    }
}

Run `/dev/build?flush`.

## 2) Form field can stay as `Bilder`

UploadField::create('Bilder', 'Upload Image')
  ->setAllowedExtensions(['jpg','jpeg','png'])
  ->setIsMultiUpload(false)
  ->setAllowedMaxFileNumber(1)
  ->setFolderName('profiles')
  ->setAttribute('id', 'fileUpload')
  ->setAttribute('accept', 'image/jpeg, image/png')
  ->setAttribute('style', 'display:none;');

## 3) Controller: map `Bilder` → `ImagedID` and publish
Add this helper inside your controller (once):

use SilverStripeAssetsImage;

private function extractUploadID($value): int {
    if (!$value) return 0;
    if (is_numeric($value)) return (int)$value;
    if (is_array($value)) {
        if (!empty($value['Files'])) return (int)$value['Files'][0];
        if (isset($value['id'])) return (int)$value['id'];
        if (isset($value[0])) return (int)$value[0];
    }
    return 0;
}

Then in your `doStep5()` **broker** branch, replace your image bit with:

$imgID = $this->extractUploadID($data['Bilder'] ?? null);
if ($imgID) {
    if ($img = Image::get()->byID($imgID)) {
        if ($img->isDraft()) {
            $img->publishSingle();
        }
        $companyData->ImagedID = $img->ID;  // <-- map to ImagedID
    }
}

(Keep the rest of your code as-is.)

If your **personal** branch also wants to store to `ImagedID`, do the same there; otherwise keep whatever column it already uses.

## 4) Frontend display
You now have two choices:

– Using the alias (cleanest in templates):

<% if $Bilder %>
  <img src="$Bilder.Fit(800,600).URL" alt="$Title.ATT">
<% end_if %>

– Or directly by relation name:

<% if $Imaged %>
  <img src="$Imaged.Fit(800,600).URL" alt="$Title.ATT">
<% end_if %>

That’s it — keep the form field name **`Bilder`**, save to **`ImagedID`**, publish the file, and render via `$Bilder` (alias) or `$Imaged`.

User
Undefined array key "Fax"
GET /public/dashboard/updateinfo/
Line 149 in /home/wmb/public_html/app/src/DashboardController.php
what if Fax is empty and optional in form but still says this error
TextField::create('Fax', 'Fax')->setAttribute('placeholder', 'Fax')->setValue($companyData['Fax']),
Assistant
You’re seeing that warning because you’re indexing an array key that may not exist. Just give it a safe default.

## Quick fix (one-liner)

TextField::create('Fax', 'Fax')
    ->setAttribute('placeholder', 'Fax')
    ->setValue($companyData['Fax'] ?? '');

`?? ''` prevents “Undefined array key 'Fax'”.

## If `$companyData` can be a DataObject (not an array)

$faxVal = is_array($companyData)
    ? ($companyData['Fax'] ?? '')
    : (($companyData && $companyData->hasField('Fax')) ? ($companyData->Fax ?? '') : '');

TextField::create('Fax', 'Fax')
    ->setAttribute('placeholder', 'Fax')
    ->setValue($faxVal);

## Best practice (no `setValue` per field)
Let Silverstripe populate everything:

$fields = FieldList::create(
    TextField::create('Fax', 'Fax')->setAttribute('placeholder','Fax'),
    // ... other fields
);

$form = Form::create($this, 'UpdateInfoForm', $fields, $actions);

// Works with either a DataObject or an array:
if ($companyData) {
    $form->loadDataFrom($companyData);
}

This avoids all “undefined key” warnings for optional fields.

User
MemberCompanyData
User
$imgID = $this->extractUploadID($data['Bilder'] ?? null);
if ($imgID) {
if ($img = Image::get()->byID($imgID)) {
if ($img->isDraft()) {
$img->publishSingle();
}
$companyData->ImageID = $img->ID;
}
}
this still not saving image
Assistant
If the image still isn’t saving, it’s usually one of these:
– the UploadField never posts an ID (AJAX upload didn’t run / token missing / field hidden),
– the posted value shape isn’t what you expect,
– or you’re not handling the raw `$_FILES` fallback.

Here’s a robust, drop-in fix that:
1) reads the ID from `Bilder` when UploadField posts it, and
2) falls back to creating the `Image` from `$_FILES` if no ID was posted.

Use this with your existing **has_one `Image`** (so DB column = `ImageID`) and form field name **`Bilder`**.

### 1) Add helpers in your controller

use SilverStripeAssetsImage;
use SilverStripeAssetsUpload;

/**
 * Extract an uploaded file ID from UploadField’s various post shapes.
 */
private function extractUploadID($value): int {
    if (!$value) return 0;
    if (is_numeric($value)) return (int)$value;

    if (is_array($value)) {
        if (!empty($value['Files']) && is_array($value['Files'])) {
            return (int)$value['Files'][0];
        }
        if (isset($value['id'])) return (int)$value['id'];
        if (isset($value[0]))   return (int)$value[0];
    }
    return 0;
}

/**
 * Ensure we get an Image either from posted ID or raw $_FILES (fallback).
 */
private function getImageFromRequest(SilverStripeControlHTTPRequest $request, $postedValue, string $folder = 'profiles'): ?Image {
    // 1) Try ID from UploadField
    $id = $this->extractUploadID($postedValue);
    if ($id) {
        if ($img = Image::get()->byID($id)) {
            return $img;
        }
    }

    // 2) Fallback to raw files if AJAX attach didn’t happen
    $files = $request->getFiles();
    $uf = $files['Bilder'] ?? null; // name matches your field

    if ($uf) {
        // UploadField usually nests as Bilder[Files][0]
        if (isset($uf['tmp_name']['Files'][0])) {
            $flat = [
                'name'     => $uf['name']['Files'][0],
                'type'     => $uf['type']['Files'][0],
                'tmp_name' => $uf['tmp_name']['Files'][0],
                'error'    => $uf['error']['Files'][0],
                'size'     => $uf['size']['Files'][0],
            ];
        } elseif (isset($uf['tmp_name']) && is_string($uf['tmp_name'])) {
            // Simple (non-nested) case
            $flat = $uf;
        } else {
            $flat = null;
        }

        if ($flat && is_uploaded_file($flat['tmp_name'])) {
            $upload = Upload::create();
            $upload->setAllowedExtensions(['jpg','jpeg','png','webp']);

            $image = Image::create();
            // This writes the file record + moves the file to assets/$folder
            if ($upload->loadIntoFile($flat, $image, $folder)) {
                return $image;
            }
        }
    }

    return null;
}

### 2) Use it inside your `doStep5()` where you save the company data
Replace your current image block with this (broker branch shown; repeat similarly for personal):

// Map + publish image from form field "Bilder"
if ($image = $this->getImageFromRequest($request, $data['Bilder'] ?? null, 'profiles')) {
    if ($image->isDraft()) {
        $image->publishSingle();
    }
    $companyData->ImageID = $image->ID; // your has_one is 'Image' => Image::class
}

Do the same in the personal branch if you also save there:

if ($image = $this->getImageFromRequest($request, $data['Bilder'] ?? null, 'profiles')) {
    if ($image->isDraft()) $image->publishSingle();
    $personalInfo->ImageID = $image->ID;
}

Then `write()` the record as you already do.

### 3) Frontend checklist (prevents silent failures)
– Make sure the form includes the security token **if you render fields manually**:

<form $Form.AttributesHTML enctype="multipart/form-data">
    $Form.SecurityToken
    <!-- your fields -->
  </form>

– Keep `UploadField` **in the form DOM**. Avoid `style="display:none"` on the whole wrapper; prefer visually hiding via CSS (opacity/position) so the UploadField JS can initialize:

.upload-hidden { position:absolute; left:-9999px; width:1px; height:1px; overflow:hidden; }

And in PHP:

UploadField::create('Bilder', 'Upload Image')
      ->setIsMultiUpload(false)
      ->setAllowedMaxFileNumber(1)
      ->setAllowedExtensions(['jpg','jpeg','png'])
      ->setFolderName('profiles')
      ->setAttribute('id', 'fileUpload')
      ->addExtraClass('upload-hidden');

– Ensure your label/button triggers the **real** file input inside the UploadField (as we wired earlier).

### 4) Displaying the image
Once saved, show it in templates:

<% if $Image %>
  <img src="$Image.Fit(800,600).URL" alt="$Firmaname.ATT">
<% end_if %>

This approach makes your save path resilient: it uses the ID when UploadField’s AJAX succeeds, and seamlessly falls back to processing the raw upload when it doesn’t—so the image always gets stored, published, and linked to `ImageID`.

User
$Bilder

<script>
const fileInput = document.getElementById('fileUpload');
					const fileName = document.getElementById('file-name');

					fileInput.addEventListener('change', function () {
						if (this.files.length > 0) {
							fileName.textContent = this.files[0].name;
						} else {
							fileName.textContent = 'Bilder';
						}
					});
</script>

$Description

$Form.Actions

enctype="multipart/form-data" is not aplying in front end its replaced by enctype="application/x-www-form-urlencoded"

Assistant
`enctype` must be set on the **Form object** (server-side). Adding it in the template after `$Form.AttributesHTML` won’t override the value Silverstripe already put there, so you end up with `application/x-www-form-urlencoded`.

Do one of these:

# Option A (recommended): use `$Form.OpenTag` / `$Form.CloseTag`
Silverstripe will output the correct `enctype` if you set it on the form.

$Form.OpenTag
  <!-- your custom layout -->
  $Bilder
  $Description
  $Form.Actions
$Form.CloseTag

In your `Step5Form()`:

public function Step5Form()
{
    $fields = FieldList::create(
        UploadField::create('Bilder', 'Upload Image')
            ->setAllowedExtensions(['jpg','jpeg','png'])
            ->setIsMultiUpload(false)
            ->setAllowedMaxFileNumber(1)
            ->setFolderName('profiles'),
        // other fields...
    );

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

    $form = Form::create($this, 'Step5Form', $fields, $actions);

    // Set enctype on the form object:
    if (method_exists($form, 'setEncType')) {
        $form->setEncType('multipart/form-data');           // SS4/SS5
    } else {
        $form->setAttribute('enctype', 'multipart/form-data');
    }

    return $form;
}

# Option B: keep your manual “
If you must keep:

<form $Form.AttributesHTML>
  $Form.SecurityToken
  $Bilder
  $Description
  $Form.Actions
</form>

Then set the enctype **server-side** exactly as above in `Step5Form()`:

$form->setEncType('multipart/form-data'); // or ->setAttribute('enctype', 'multipart/form-data')

Don’t add another `enctype` in the template—`$Form.AttributesHTML` already prints one.

## Quick checks
– Ensure the upload field is actually inside the form DOM you submit.
– Include `$Form.SecurityToken` if you use a manual “; missing token can block UploadField’s attach.
– Avoid `display:none` on the entire UploadField wrapper; prefer off-screen CSS if you’re hiding it, so its JS can initialise.

After this change, view source: you should see `enctype="multipart/form-data"` on the rendered “, and uploads will post correctly.

User
print_r($_FILES);
die;
SHowing empty array
Assistant
`$_FILES` being empty is **normal** with Silverstripe’s **UploadField** on the front end. UploadField uploads the file **via AJAX before form submit**, then the form submit only posts the **file IDs** (e.g. `Bilder[Files][0] = 123`). So you won’t see the raw file in `$_FILES` during `doStep5()`.

Here are two solid ways forward—pick one:

# Option A — Keep `UploadField` (recommended)
Use the posted ID(s), then publish and save.

1) Make sure your form is built like this (server-side):

$form = Form::create($this, 'Step5Form', $fields, $actions);
$form->setEncType('multipart/form-data'); // important

…and render with `$Form.OpenTag` / `$Form.CloseTag` **or** include `$Form.SecurityToken` if you use a manual “ tag.

2) In your controller, read the ID from `$data['Bilder']` and map it to your relation:

use SilverStripeAssetsImage;

private function extractUploadID($value): int {
    if (!$value) return 0;
    if (is_numeric($value)) return (int)$value;
    if (is_array($value)) {
        if (!empty($value['Files']) && is_array($value['Files'])) return (int)$value['Files'][0];
        if (isset($value['id'])) return (int)$value['id'];
        if (isset($value[0]))   return (int)$value[0];
    }
    return 0;
}
$imgID = $this->extractUploadID($data['Bilder'] ?? null);
if ($imgID) {
    if ($img = Image::get()->byID($imgID)) {
        if ($img->isDraft()) {
            $img->publishSingle();
        }
        $companyData->ImageID = $img->ID;   // or ImagedID if that’s your column
    }
}

3) Quick sanity checks if you still get nothing in `$data['Bilder']`:
– Ensure `$Bilder` is **inside** the form that’s being submitted.
– Include `$Form.SecurityToken` in your template if using a manual “.
– Don’t hide the UploadField wrapper with `display:none;` before it initializes. If you must hide, move it off-screen with CSS (so Dropzone JS can still attach).
– In DevTools → Network, after selecting a file, you should see an **XHR** to an assets/upload endpoint (200 OK). If it’s **403**, you likely need to allow front-end uploads (see note below).

> ⚠️ Front-end permission note: by default, anonymous users may be blocked from uploading. If your XHR is 403, add a small extension to let front-end users create files, or handle uploads via Option B below.

# Option B — Use `FileField` (classic non-AJAX)
If you prefer raw `$_FILES` on submit, replace `UploadField` with `FileField`:

**Form**

use SilverStripeFormsFileField;

FileField::create('Bilder', 'Upload Image')

**Controller**

use SilverStripeAssetsImage;
use SilverStripeAssetsUpload;

$files = $request->getFiles();
if (!empty($files['Bilder']['tmp_name'])) {
    $upload = Upload::create();
    $upload->setAllowedExtensions(['jpg','jpeg','png','webp']);

    $image = Image::create();
    if ($upload->loadIntoFile($files['Bilder'], $image, 'profiles')) {
        $image->publishSingle();
        $companyData->ImageID = $image->ID; // or ImagedID
    } else {
        // handle $upload->getErrors()
    }
}

# Showing the image on the front end
Once saved:

<% if $Image %>
  <img src="$Image.Fit(800,600).URL" alt="$Firmaname.ATT">
<% end_if %>

(or `$Imaged` / `$Bilder` if you use those names)

## If your UploadField AJAX is failing (403)
Allow front-end uploads by granting create permission on `File` (scoped as you see fit):

**app/src/Extensions/FrontendFileCreateExtension.php**

namespace AppExtensions;

use SilverStripeCoreExtension;

class FrontendFileCreateExtension extends Extension
{
    public function canCreate($member = null, $context = [])
    {
        // TODO: tighten this to your registration route/session check
        return true;
    }
}

**app/_config/app.yml**

SilverStripeAssetsFile:
  extensions:
    - AppExtensionsFrontendFileCreateExtension

Then `?flush`.

**Bottom line:** With UploadField, expect `$_FILES` to be empty on submit—use the posted **ID** in `$data['Bilder']`. If you need `$_FILES`, switch to `FileField`.

User
use classic
Assistant
Perfect—let’s switch to the **classic (non-AJAX)** path using `FileField`, so the file comes in via `$_FILES['Bilder']`.

## 1) Build the form with `FileField` and set the enctype

use SilverStripeFormsFieldList;
use SilverStripeFormsForm;
use SilverStripeFormsFormAction;
use SilverStripeFormsFileField;
use SilverStripeFormsTextAreaField; // example for Description

public function Step5Form()
{
    $fields = FieldList::create(
        FileField::create('Bilder', 'Upload Image')
            ->setAttribute('id', 'bilderFile') // so a <label for="bilderFile"> works
            ->setAttribute('accept', 'image/jpeg,image/png'),
        TextAreaField::create('Description', 'Beschreibung')
    );

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

    $form = Form::create($this, 'Step5Form', $fields, $actions);

    // IMPORTANT: classic uploads need multipart/form-data
    if (method_exists($form, 'setEncType')) {
        $form->setEncType('multipart/form-data');
    } else {
        $form->setAttribute('enctype', 'multipart/form-data');
    }

    return $form;
}

### Template (use the form’s own tags)

$Form.OpenTag
  $Bilder
  $Description
  $Form.Actions
$Form.CloseTag

If you keep a manual “, include `$Form.SecurityToken` inside it. Don’t add your own enctype; it’s already set on the form.

## 2) Save the file in `doStep5()` (classic way)
Use `Upload::loadIntoFile()` with the raw `$_FILES['Bilder']`, then publish and attach to your record.

use SilverStripeAssetsImage;
use SilverStripeAssetsUpload;

private function attachImageFromFiles(array $files, string $fieldName = 'Bilder', string $folder = 'profiles'): ?Image
{
    if (empty($files[$fieldName]) || empty($files[$fieldName]['tmp_name'])) {
        return null; // nothing uploaded
    }

    $upload = Upload::create();
    $upload->setAllowedExtensions(['jpg','jpeg','png','webp']); // adjust if needed

    $image = Image::create();
    if ($upload->loadIntoFile($files[$fieldName], $image, $folder)) {
        return $image; // not published yet
    }

    // Optionally log or surface $upload->getErrors()
    return null;
}

private function setImageRelation($record, Image $img): void
{
    // If your DB column is ImageID (from has_one 'Image' => Image::class)
    if ($record->hasField('ImageID')) {
        $record->ImageID = $img->ID;
        return;
    }
    // If your DB column is ImagedID (older schema)
    if ($record->hasField('ImagedID')) {
        $record->ImagedID = $img->ID;
        return;
    }
    // If you actually have a has_one Bilder => Image::class
    if ($record->hasField('BilderID')) {
        $record->BilderID = $img->ID;
        return;
    }
}

### Drop this into your existing `doStep5()` at the appropriate spots
**Broker branch (MemberCompanyData):**

$files = $request->getFiles();
if ($img = $this->attachImageFromFiles($files, 'Bilder', 'profiles')) {
    $img->publishSingle();
    $this->setImageRelation($companyData, $img); // sets ImageID/ImagedID/BilderID as available
}
$companyData->write();

**Personal branch (PersonalInformation):**

$files = $request->getFiles();
if ($img = $this->attachImageFromFiles($files, 'Bilder', 'profiles')) {
    $img->publishSingle();
    $this->setImageRelation($personalInfo, $img);
}
$personalInfo->write();

> This path does **not** rely on UploadField’s AJAX. You’ll now see `$_FILES['Bilder']` populated, and the image will be created in `assets/profiles/`, published, and linked to your record.

## 3) Show it on the frontend
Given your current model (`MemberCompanyData` has `has_one 'Image' => Image::class`):

<% if $Image %>
  <img src="$Image.Fit(800,600).URL" alt="$Firmaname.ATT">
<% end_if %>

If your DB actually uses `ImagedID`, either render `$Imaged` or keep a small alias:

public function getBilder() { return $this->Image ?: $this->Imaged(); }

then in template:

<% if $Bilder %><img src="$Bilder.Fit(800,600).URL" alt="$Firmaname.ATT"><% end_if %>

## Quick gotchas checklist
– Make sure `php.ini` allows the sizes you need (`upload_max_filesize`, `post_max_size`).
– If the field is **optional**, this code safely skips when no file is chosen.
– If you previously had `UploadField` JS in the page, remove it (no longer needed).

That’s it—classic upload enabled, saved, published, and ready to display.

User
undefine method getFiles
Assistant
Right — `SilverStripeControlHTTPRequest` doesn’t have `getFiles()`.
For **classic uploads**, just read from PHP’s `$_FILES`.

Here’s the minimal, working setup:

## 1) Use `FileField` in the form and set enctype

use SilverStripeFormsFileField;

public function Step5Form() {
    // ...
    $fields = FieldList::create(
        FileField::create('Bilder', 'Upload Image')
            ->setAttribute('accept', 'image/jpeg,image/png')
    );
    // ...
    $form = Form::create($this, 'Step5Form', $fields, $actions);
    $form->setEncType('multipart/form-data');
    return $form;
}

## 2) In `doStep5(…)`, read `$_FILES` (no getFiles)
Keep your current signature if you want (`HTTPRequest $request`)—just don’t call `getFiles()`.

use SilverStripeAssetsImage;
use SilverStripeAssetsUpload;

private function attachImageFromFiles(string $field = 'Bilder', string $folder = 'profiles'): ?Image
{
    if (empty($_FILES[$field]) || empty($_FILES[$field]['tmp_name'])) {
        return null; // no file chosen
    }

    $upload = Upload::create();
    $upload->setAllowedExtensions(['jpg','jpeg','png','webp']);

    $image = Image::create();
    if ($upload->loadIntoFile($_FILES[$field], $image, $folder)) {
        return $image; // not published yet
    }
    // Optional: inspect $upload->getErrors()
    return null;
}

Use it in both branches:

// broker branch
if ($img = $this->attachImageFromFiles('Bilder', 'profiles')) {
    $img->publishSingle();
    // set the correct relation column you have:
    if ($companyData->hasField('ImageID'))  $companyData->ImageID  = $img->ID;
    if ($companyData->hasField('ImagedID')) $companyData->ImagedID = $img->ID;
    if ($companyData->hasField('BilderID')) $companyData->BilderID = $img->ID;
}
$companyData->write();

// personal branch
if ($img = $this->attachImageFromFiles('Bilder', 'profiles')) {
    $img->publishSingle();
    if ($personalInfo->hasField('ImageID'))  $personalInfo->ImageID  = $img->ID;
    if ($personalInfo->hasField('ImagedID')) $personalInfo->ImagedID = $img->ID;
    if ($personalInfo->hasField('BilderID')) $personalInfo->BilderID = $img->ID;
}
$personalInfo->write();

## 3) Frontend display

<% if $Image %>
  <img src="$Image.Fit(800,600).URL" alt="$Firmaname.ATT">
<% end_if %>

(or `$Imaged` / `$Bilder` depending on your relation)

### Quick checklist
– Ensure the rendered form uses `$Form.OpenTag`/`$Form.CloseTag` **or** includes `$Form.SecurityToken` if you output a manual “.
– Confirm the HTML shows `enctype="multipart/form-data"`.
– Remove any old `UploadField` JS; it’s not needed for classic uploads.

This removes the `getFiles()` call entirely and gets your classic upload working.

User
[Emergency] Uncaught BadMethodCallException: Object->__call(): the method 'setAllowedExtensions' does not exist on 'SilverStripeAssetsUpload'
POST /public/registration/doStep5
Line 57 in /home/wmb/public_html/vendor/silverstripe/framework/src/Core/CustomMethods.php
Assistant
You’re calling a method that doesn’t exist on `Upload`. Use the **validator** on the `Upload` instance.

### Fix: replace this

$upload = Upload::create();
$upload->setAllowedExtensions(['jpg','jpeg','png','webp']); // ❌ causes BadMethodCallException

### With this

use SilverStripeAssetsImage;
use SilverStripeAssetsUpload;

$upload = Upload::create();
$upload->getValidator()->setAllowedExtensions(['jpg','jpeg','png','webp']); // ✅

### Full classic-upload snippet (drop-in)

private function attachImageFromFiles(string $field = 'Bilder', string $folder = 'profiles'): ?Image
{
    if (empty($_FILES[$field]) || empty($_FILES[$field]['tmp_name'])) {
        return null;
    }

    $upload = Upload::create();
    $upload->getValidator()->setAllowedExtensions(['jpg','jpeg','png','webp']);

    $image = Image::create();
    if ($upload->loadIntoFile($_FILES[$field], $image, $folder)) {
        return $image; // not published yet
    }

    // Optional: inspect $upload->getErrors() for why it failed
    return null;
}

Then in `doStep5()`:

if ($img = $this->attachImageFromFiles('Bilder', 'profiles')) {
    $img->publishSingle();
    // set whichever relation column you actually have:
    if ($companyData->hasField('ImageID'))  $companyData->ImageID  = $img->ID;
    if ($companyData->hasField('ImagedID')) $companyData->ImagedID = $img->ID;
    if ($companyData->hasField('BilderID')) $companyData->BilderID = $img->ID;
}
$companyData->write();

### (Optional) Site-wide config instead of per-request

# app/_config/assets.yml
SilverStripeAssetsFile:
  allowed_extensions:
    - jpg
    - jpeg
    - png
    - webp

Then you can skip the validator line entirely.

This change removes the exception and gets your classic file upload working.

User
okay now we have successully saved image and their id in db couln how We will show it on front end now
Assistant
Awesome — since the image is now saved (and you’re publishing it), showing it is simple.

## 1) Make sure the relation exists
You already have it:

// MemberCompanyData
private static $has_one = [
  'Image' => SilverStripeAssetsImage::class,
];
private static $owns = ['Image']; // optional but nice

## 2) Pass the record to your template
Example (e.g., in `step6()` or wherever you render the confirmation page):

use SilverStripeSecuritySecurity;

public function step6()
{
    $memberID = Security::getCurrentUser()?->ID; // or however you resolve it
    $company  = AppModelMemberCompanyData::get()
                 ->filter('MemberID', $memberID)
                 ->first();

    return $this->customise(['Company' => $company])
                ->renderWith(['Layout/RegistrationStep6','Page']);
}

## 3) Render in the `.ss` template

<% if $Company && $Company.Image %>
  <img
    src="$Company.Image.ScaleMax(800,600).URL"
    alt="$Company.Firmaname.ATT">
<% else %>
  <p>No image uploaded.</p>
<% end_if %>

### Popular variants
– Original: `$Company.Image.URL`
– Crop to exact size: `$Company.Image.Fill(600,400).URL`
– Fit inside box: `$Company.Image.Fit(600,400).URL`
– Max bounds keep ratio: `$Company.Image.ScaleMax(1200,800).URL`

### Simple responsive example

<% if $Company.Image %>
  <img
    src="$Company.Image.ScaleMax(600,400).URL"
    srcset="
      $Company.Image.ScaleMax(600,400).URL 600w,
      $Company.Image.ScaleMax(900,600).URL 900w,
      $Company.Image.ScaleMax(1200,800).URL 1200w"
    sizes="(max-width: 700px) 100vw, 700px"
    alt="$Company.Firmaname.ATT">
<% end_if %>

## 4) If your DB column is different (e.g., `ImagedID`)
Either:
– change the relation to match:

private static $has_one = ['Imaged' => Image::class];

and in template use `$Company.Imaged…`, **or**
– add an alias so templates can still use `$Image`:

public function getImage() { return $this->Imaged(); }

As long as the relation exists and the file is published (you already call `publishSingle()`), `$Company.Image.*` will work on the frontend.

User
these two function are used

public function updateinfo(HTTPRequest $request){
$firstName = $request->getSession()->get('CUFirstName');
$lastName = $request->getSession()->get('CULastName');

$form = $this->UpdateCompanyForm();

$session = $this->getRequest()->getSession();
$formSuccess = $session->get('FormSuccess');
$errorMessage = $session->get('FormError');

$session->clear('FormError');
$session->clear('FormSuccess');

return $this->customise([
'Title' => 'Broker-Informationen',
'Name' => $firstName.' '.$lastName,
'FormError' => $errorMessage,
'FormSuccess' => $formSuccess,
'Form' => $form,
'MemberID' => $form->Fields()->dataFieldByName('MemberID'),
'Firmaname' => $form->Fields()->dataFieldByName('Firmaname'),
'HRBHRA' => $form->Fields()->dataFieldByName('HRBHRA'),
'Address' => $form->Fields()->dataFieldByName('Address'),
'CountryCode' => $form->Fields()->dataFieldByName('CountryCode'),
'Telefon' => $form->Fields()->dataFieldByName('Telefon'),
'Email' => $form->Fields()->dataFieldByName('Email'),
'Website' => $form->Fields()->dataFieldByName('Website'),
'Fax' => $form->Fields()->dataFieldByName('Fax'),
'Description' => $form->Fields()->dataFieldByName('Description')
])->renderWith(['Layout/Broker/UpdateInfo', 'Page']);
}

public function UpdateCompanyForm(){

$member = Security::getCurrentUser();

$records = MemberCompanyData::get()
->filter('MemberID', $member->ID)
->first();

if ($records) {
$companyData = $records->toMap();
}

$fields = FieldList::create(
HiddenField::create('MemberID', 'MemberID')->setValue($member->ID),
TextField::create('Firmaname', 'Firmaname')->setAttribute('placeholder', 'Firmaname*')->setValue($companyData['Firmaname']),
TextField::create('HRBHRA', 'HRB / HRA')->setAttribute('placeholder', 'HRB / HRA*')->setValue($companyData['HRBHRA']),
TextareaField::create('Address', 'Adresse')->setAttribute('placeholder', 'Adresse*')->setValue($companyData['Firmaname']),
DropdownField::create('CountryCode', 'Country Code', [
'+49' => 'Deutschland (+49)',
'+43' => 'Österreich (+43)',
'+41' => 'Schweiz (+41)'
])->setValue('+49')->setEmptyString('Ländervorwahl auswählen*')->setValue($companyData['CountryCode']),
TextField::create('Telefon', 'Telefon')->setAttribute('placeholder', 'Telefon*')->setValue($companyData['Telefon']),
EmailField::create('Email', 'Emailadresse')->setAttribute('placeholder', 'Emailadresse*')->setValue($companyData['Email']),
TextField::create('Website', 'Website')->setAttribute('placeholder', 'Website')->setValue($companyData['Website']),
TextField::create('Fax', 'Fax')->setAttribute('placeholder', 'Fax')->setValue($companyData['Fax'] ?? ''),
TextareaField::create('Description', 'Company Description')->setAttribute('placeholder', '')->addExtraClass('short_content')->setValue($companyData['Description']),
);

$actions = FieldList::create(
FormAction::create('doRegister', 'um zu sehen')
);

$validator = RequiredFields::create(['Firmaname', 'HRBHRA', 'Address', 'CountryCode', 'Telefon', 'Email']);

$form = Form::create($this, 'UpdateCompanyForm', $fields, $actions, $validator);
$form->setFormAction('/public/dashboard/doUpdateCompany');
return $form;
}

Assistant
Great—since you’re on the **classic upload** path and have saved the image (ID in DB), here’s how to wire it cleanly into your **update** screen:

## 1) Update the form to (a) show current image preview, (b) allow replacing it, and (c) set `enctype`

use SilverStripeFormsFieldList;
use SilverStripeFormsForm;
use SilverStripeFormsFormAction;
use SilverStripeFormsHiddenField;
use SilverStripeFormsTextField;
use SilverStripeFormsTextareaField;
use SilverStripeFormsEmailField;
use SilverStripeFormsDropdownField;
use SilverStripeFormsFileField;
use SilverStripeFormsRequiredFields;
use SilverStripeSecuritySecurity;

public function UpdateCompanyForm()
{
    $member  = Security::getCurrentUser();
    $record  = AppModelMemberCompanyData::get()->filter('MemberID', $member->ID)->first();

    $fields = FieldList::create(
        HiddenField::create('MemberID')->setValue($member->ID),

        // — Optional: current image preview (if any)
        SilverStripeFormsLiteralField::create(
            'ImagePreview',
            $record && $record->ImageID
                ? sprintf(
                    '<div class="mb-3"><img src="%s" alt="Current image" style="max-width:160px;height:auto;border-radius:8px;" /></div>',
                    $record->Image()->ScaleMax(320, 320)->URL()
                )
                : '<div class="mb-3" style="color:#666;">(Kein Bild hochgeladen)</div>'
        ),

        // — Classic file input to upload/replace
        FileField::create('Bilder', 'Neues Bild hochladen')
            ->setAttribute('accept', 'image/jpeg,image/png,image/webp'),

        TextField::create('Firmaname', 'Firmaname')->setAttribute('placeholder', 'Firmaname*'),
        TextField::create('HRBHRA', 'HRB / HRA')->setAttribute('placeholder', 'HRB / HRA*'),
        TextareaField::create('Address', 'Adresse')->setAttribute('placeholder', 'Adresse*'),
        DropdownField::create('CountryCode', 'Country Code', [
            '+49' => 'Deutschland (+49)',
            '+43' => 'Österreich (+43)',
            '+41' => 'Schweiz (+41)'
        ])->setEmptyString('Ländervorwahl auswählen*'),
        TextField::create('Telefon', 'Telefon')->setAttribute('placeholder', 'Telefon*'),
        EmailField::create('Email', 'Emailadresse')->setAttribute('placeholder', 'Emailadresse*'),
        TextField::create('Website', 'Website')->setAttribute('placeholder', 'Website'),
        TextField::create('Fax', 'Fax')->setAttribute('placeholder', 'Fax'),
        TextareaField::create('Description', 'Company Description')->addExtraClass('short_content')
    );

    $actions   = FieldList::create(FormAction::create('doUpdateCompany', 'Speichern'));
    $validator = RequiredFields::create(['Firmaname','HRBHRA','Address','CountryCode','Telefon','Email']);

    $form = Form::create($this, 'UpdateCompanyForm', $fields, $actions, $validator);
    $form->setEncType('multipart/form-data');                       // ← important for classic
    $form->setFormAction('/public/dashboard/doUpdateCompany');

    // Let Silverstripe populate values safely (no undefined index warnings):
    if ($record) {
        $form->loadDataFrom($record);
    } else {
        // Sensible defaults
        $form->setData(['CountryCode' => '+49']);
    }

    return $form;
}

> Note: You had a small typo before: `Address` was being set from `Firmaname`. Using `loadDataFrom($record)` avoids all those per-field `setValue()` issues.

## 2) Save handler: update fields + handle classic file upload + publish
Add this action (path must match your `setFormAction`):

use SilverStripeAssetsUpload;
use SilverStripeAssetsImage;
use SilverStripeSecuritySecurity;

public function doUpdateCompany(SilverStripeControlHTTPRequest $request)
{
    $member = Security::getCurrentUser();
    if (!$member) { return $this->httpError(403); }

    $record = AppModelMemberCompanyData::get()->filter('MemberID', $member->ID)->first()
        ?: AppModelMemberCompanyData::create(['MemberID' => $member->ID]);

    // 1) Update scalar fields from POST safely
    $form = $this->UpdateCompanyForm();           // reuse field/validation context
    $form->loadDataFrom($request->postVars());
    $form->saveInto($record);

    // 2) Classic file upload (optional field)
    if (!empty($_FILES['Bilder']) && !empty($_FILES['Bilder']['tmp_name'])) {
        $upload = Upload::create();
        $upload->getValidator()->setAllowedExtensions(['jpg','jpeg','png','webp']);

        $image = Image::create();
        if ($upload->loadIntoFile($_FILES['Bilder'], $image, 'profiles')) {
            $image->publishSingle();              // make it visible to guests
            $record->ImageID = $image->ID;        // your has_one is 'Image'
        } else {
            // You can surface $upload->getErrors() if needed
        }
    }

    $record->write();

    // Flash + redirect
    $session = $request->getSession();
    $session->set('FormSuccess', 'Daten gespeichert.');
    return $this->redirect('/public/dashboard/updateinfo');
}

## 3) Template
Render the form using its own tags so the right `enctype` is output:

$Form.OpenTag
  $Form.Fields
  $Form.Actions
$Form.CloseTag

If you prefer your custom layout, still use `$Form.OpenTag`/`$Form.CloseTag` and place fields individually:

$Form.OpenTag
  $ImagePreview        <!-- LiteralField -->
  $Bilder              <!-- FileField -->
  $Firmaname
  $HRBHRA
  $Address
  $CountryCode
  $Telefon
  $Email
  $Website
  $Fax
  $Description
  $Form.Actions
$Form.CloseTag

## 4) Show image anywhere on frontend
Given your `has_one 'Image'`:

<% if $Image %>
  <img src="$Image.Fit(800,600).URL" alt="$Firmaname.ATT">
<% end_if %>

That’s it: the update screen shows the current image, lets users upload a new one, and persists + publishes it.

User
NO jsut want to show image on respective page
public function updateinfo(HTTPRequest $request){
$firstName = $request->getSession()->get('CUFirstName');
$lastName = $request->getSession()->get('CULastName');

$form = $this->UpdateCompanyForm();

$session = $this->getRequest()->getSession();
$formSuccess = $session->get('FormSuccess');
$errorMessage = $session->get('FormError');

$session->clear('FormError');
$session->clear('FormSuccess');

return $this->customise([
'Title' => 'Broker-Informationen',
'Name' => $firstName.' '.$lastName,
'FormError' => $errorMessage,
'FormSuccess' => $formSuccess,
'Form' => $form,
'MemberID' => $form->Fields()->dataFieldByName('MemberID'),
'Firmaname' => $form->Fields()->dataFieldByName('Firmaname'),
'HRBHRA' => $form->Fields()->dataFieldByName('HRBHRA'),
'Address' => $form->Fields()->dataFieldByName('Address'),
'CountryCode' => $form->Fields()->dataFieldByName('CountryCode'),
'Telefon' => $form->Fields()->dataFieldByName('Telefon'),
'Email' => $form->Fields()->dataFieldByName('Email'),
'Website' => $form->Fields()->dataFieldByName('Website'),
'Fax' => $form->Fields()->dataFieldByName('Fax'),
'Description' => $form->Fields()->dataFieldByName('Description')
])->renderWith(['Layout/Broker/UpdateInfo', 'Page']);
}

Assistant
Got it — just pass the company record to the view and render its related image.

## Controller (updateinfo)
Add the company fetch and pass it to `customise`:

use SilverStripeSecuritySecurity;
use AppModelMemberCompanyData;

public function updateinfo(HTTPRequest $request)
{
    $firstName = $request->getSession()->get('CUFirstName');
    $lastName  = $request->getSession()->get('CULastName');

    $form = $this->UpdateCompanyForm();

    $session      = $this->getRequest()->getSession();
    $formSuccess  = $session->get('FormSuccess');
    $errorMessage = $session->get('FormError');
    $session->clear('FormError');
    $session->clear('FormSuccess');

    $member  = Security::getCurrentUser();
    $company = MemberCompanyData::get()->filter('MemberID', $member->ID)->first();

    return $this->customise([
        'Title'       => 'Broker-Informationen',
        'Name'        => $firstName.' '.$lastName,
        'FormError'   => $errorMessage,
        'FormSuccess' => $formSuccess,
        'Form'        => $form,

        // existing field handles...
        'MemberID'    => $form->Fields()->dataFieldByName('MemberID'),
        'Firmaname'   => $form->Fields()->dataFieldByName('Firmaname'),
        'HRBHRA'      => $form->Fields()->dataFieldByName('HRBHRA'),
        'Address'     => $form->Fields()->dataFieldByName('Address'),
        'CountryCode' => $form->Fields()->dataFieldByName('CountryCode'),
        'Telefon'     => $form->Fields()->dataFieldByName('Telefon'),
        'Email'       => $form->Fields()->dataFieldByName('Email'),
        'Website'     => $form->Fields()->dataFieldByName('Website'),
        'Fax'         => $form->Fields()->dataFieldByName('Fax'),
        'Description' => $form->Fields()->dataFieldByName('Description'),

        // add the record so template can access $Company.Image
        'Company'     => $company,
    ])->renderWith(['Layout/Broker/UpdateInfo', 'Page']);
}

## Template (`Layout/Broker/UpdateInfo.ss`)
Where you want the image to appear:

<% if $Company && $Company.Image %>
  <img src="$Company.Image.ScaleMax(800,600).URL" alt="$Company.Firmaname.ATT">
<% end_if %>

(Use `.Fill(w,h)`, `.Fit(w,h)`, or `.URL` as you prefer.)

> Note: Make sure you publish the file when saving (you already call `publishSingle()`); otherwise anonymous users won’t see it.

User
$Company.Image This is showin g image directly
but this $Company.Image.ScaleMax(800,600).URL not get url
Assistant
Got it. A few quick points to make this work reliably:

## Use `Link` (or `AbsoluteURL`) on the resized variant
Sometimes `.URL` on a *manipulated* image returns empty depending on setup. Use `.Link` instead.

<% if $Company.Image %>
  <% with $Company.Image %>
    <img src="$ScaleMax(800,600).Link" alt="$Up.Firmaname.ATT">
  <% end_with %>
<% end_if %>

Variants you can try:
– Original: `$Company.Image.URL` (or `$Company.Image.Link`)
– Resized: `$Company.Image.ScaleMax(800,600).Link`
– Absolute: `$Company.Image.ScaleMax(800,600).AbsoluteURL`

## Defensive fallback (if manipulation fails)

<% if $Company.Image %>
  <% with $Company.Image %>
    <% if $ScaleMax(800,600) %>
      <img src="$ScaleMax(800,600).Link" alt="$Up.Firmaname.ATT">
    <% else %>
      <img src="$Link" alt="$Up.Firmaname.ATT">
    <% end_if %>
  <% end_with %>
<% end_if %>

## If it’s still blank
– Ensure the image is **published** (you’re calling `publishSingle()` — good).
– Make sure PHP has **GD or Imagick** enabled; manipulations need one of them. Without it, `$ScaleMax(…)` can be empty.
– `?flush` after changing code/config, and (if needed) clear generated variants (`assets/_resampled` in SS4, or let SS regenerate).

This should give you a working resized URL on the frontend.

Leave a Comment

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