Programmatically Rendering an Express Form

Rendering an Express form in a custom template or custom PHP code is easy. First, we retrieve the Express object we want to work with. First, get the Express object manager:

$express = \Core::make('express');

in the top of the PHP script.

 note: \Core::make() is deprecated . Use app() (since 8.5.2) or \Concrete\Core\Support\Facade\Application::getFacadeApplication() . See this tutorial for more details.
$entity = $express->getObjectByHandle('student');

Then, get the Express form:

$forms = $entity->getForms();
$form = $forms[0];

If you have more than one form you might want to iterate through to find the one you want:

$forms = $entity->getForms();
foreach($forms as $expressForm) {
    if ($expressForm->getName() == 'Frontend') {
        $form = $expressForm;
        break;
    }
}

Now, we have an object of the Concrete\Core\Entity\Express\Form in the $form variable. Next, we instantiate an object for the context that applies to where we're showing the form. Since we're rendering the form on the front-end of the site, let's create an instance of the Concrete\Core\Express\Form\Context\FrontendFormContext class.

$context = new FrontendFormContext();

Finally, let's create the renderer given our controller and our context. Import the Concrete\Core\Express\Form\Renderer class at the top of the script:

use Concrete\Core\Express\Form\Renderer;

And create an instance of it with the context and the form object:

$renderer = new Renderer($context, $form);

Now you can render the form like so:

print $renderer->render();

Built-In Context Reference

The following context objects exist in the core for rendering express forms.

  • Concrete\Core\Express\Form\Context\DashboardFormContext
  • Concrete\Core\Express\Form\Context\DashboardViewContext
  • Concrete\Core\Express\Form\Context\FormContext
  • Concrete\Core\Express\Form\Context\FrontendFormContext
  • Concrete\Core\Express\Form\Context\FrontendViewContext
  • Concrete\Core\Express\Form\Context\ViewContext

In general, if you're rendering a form in the Dashboard, use a Dashboard form context; if you're rendering it on the front-end, use the FrontendFormContext. Same goes for rendering views as well (which show the form values, but in a read only state.)

Dynamically Retrieving the Appropriate Context

In the example above, we pass the Concrete\Core\Express\Form\Context\FrontendFormContext object to the form renderer. However, it's possible to dynamically bind custom context objects that you define to Concrete CMS's implementation. This makes it possible to deliver a custom context object any time Concrete calls its own internal FrontendFormContext, for example. This is done using a combination of the Express Form Controller, and the Concrete\Core\Express\Form\Context\ContextFactory object, and enables full control over form customization without using any custom templates. To use the context factory to retrieve the appropriate context, first retrieve the controller from the Express Entity you're working with:

$controller = $express->getEntityController($entity);

Next, retrieve the appropriate context using Concrete\Core\Form\Context\ContextFactory:

$factory = new ContextFactory($controller);
$context = $factory->getContext(new FrontendFormContext());

In most cases this will simply pass you back the Concrete\Core\Express\Form\Context\FrontendFormContext that you passed in. However, you can dynamically bind a custom subclass of the Concrete\Core\Express\Form\Context\FrontendFormContext class at runtime – and this custom implementation will be used instead of the built-in Concrete\Core\Express\Form\Context\FrontendFormContext class.

This enables us to use the same form rendering and processing code everywhere, and lets developers bind their own implementations without hacking this core controller code to pass in their own context objects.