Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Silverstripe Multiple Userforms on one page

Tags:

silverstripe

I am trying to create a single page that will display multiple userforms in a tabbed view. For example basic contact form, request a quote form etc.

I thought I could make a new page type and loop through the children to display the forms, but the $Form variable isn't rendering the form.

<% loop $Children %>
   <div>
     <h2>$Title</h2>
     $Form
   </div>
<% end_loop %>

Am I missing something here, or is there a different way to render a form using a its ID in a template file?

like image 875
stillfire Avatar asked Jan 19 '16 22:01

stillfire


2 Answers

You could try the following.

Create a function in your page holder controller to get the form from a specific child (must be a UserDefinedForm page). To do this you'll need to create the controller of this child page.

public function ChildForm($pageID) {
  $page = UserDefinedForm::get()->byID($pageID);
  $controller = UserDefinedForm_Controller::create($page);
  return $controller->Form();
}

afterwards you'll call this function in your loop and pass the current child id to it

<% loop $Children %>
   <div>
     <h2>$Title</h2>
     $Top.ChildForm($ID)
   </div>
<% end_loop %>

This should (code is untested) return the forms you want.

like image 140
csy_dot_io Avatar answered Sep 21 '22 12:09

csy_dot_io


The problem at play here is the difference between the DataObject/Page and the Controller. Looping over $Children returns you a DataObject whereas the Form function and template variable are part of UserDefinedForm's controller.

The other answer shows one working solution however it has some hair on it:

  • Jumping scope to your controller to pass an ID to get your form
  • Additional DB query
  • Requires all the child pages to be of type UserDefinedForm

We can implement a more generic solution that removes some of those elements and making your code a little more maintainable.

Take the following which would be added to the Page class (not the controller):

function getInLoopForm() {
    if (in_array('UserDefinedForm', $this->ClassAncestry)) {
        $controllerName = $this->ClassName . '_Controller';
        $controller = $controllerName::create($this);
        if ($controller->hasMethod('Form')) {
            return $controller->Form();
        }
    }
    return false;
}

The first part of that checks whether the current object has UserDefinedForm in its class ancestry. If it is, we then create the appropriate controller and return the form.

Your template code would look like this instead:

<% loop $Children %>
   <div>
     <h2>$Title</h2>
     $InLoopForm
   </div>
<% end_loop %>

This solution is generic for three reasons:

  • In our getInLoopForm function, the value "UserDefinedForm" can be replaced with any class that extends Page. It could even be brought out to a YML value if you were so inclined.
  • For SilverStripe, controller names for pages must match "{PageClassName}_Controller" so we can abuse that by working out the controller name dynamically. This allows for you to extend UserDefinedForm and its controller and we can still call the right function.
  • You only require your DataObject to access the form, you don't need your own controller.
like image 36
Turnerj Avatar answered Sep 19 '22 12:09

Turnerj