Rendering an Express Form programmatically

Permalink
Hello,

I am trying to follow the instructions on this page:

https://documentation.concrete5.org/developers/express/express-forms...

So I added this to the top of my template file:

use Concrete\Core\Express\Form\Renderer;
use Concrete\Core\Attribute\Context\FrontendFormContext;


Further down I added this:

$express = \Core::make('express');
$entity = $express->getObjectByHandle('contact');
$forms = $entity->getForms();
$form = $forms[0];
$context = new FrontendFormContext();
$renderer = new Renderer($context, $form);
print $renderer->render();


By what I can tell this is what the instructions tell me to do (except the second "use" line, which I added; not sure if that is correct, as the documentation doesn't mention it).

With the above code I get this error:

Argument 1 passed to Concrete\Core\Express\Form\Renderer::__construct() must be an instance of Concrete\Core\Express\Form\Context\ContextInterface, instance of Concrete\Core\Attribute\Context\FrontendFormContext given, called in [...]

What am I overlooking?

Thanks in advance for your help.

ObiWan
 
mnakalay replied on at Permalink Best Answer Reply
mnakalay
The second Use should be
use Concrete\Core\Express\Form\Context\FrontendFormContext;
ObiWan replied on at Permalink Reply
ObiWan
Hello,

sorry for responding so late (unforeseen trouble). :-(

Thank you for your help! That line fixed it.

On to the next issue. :-) My ultimate goal is to be able to place form fields next to each other with floats and custom classes .

I have followed this documentation to learn how to go about this:https://documentation.concrete5.org/developers/express/express-forms...

All this tutorial does is change the class of a form field from "ext-muted" to "label". By what I can tell I have followed the instructions to the letter, but don't seem to get a result. So either I missed something or - as in the case above - the tutorial is missing something. The only change I made is to replace "MySite" to the name of my project.

How could I debug this? Or is there something in the tutorial that doesn't quite work with the latest version anymore?
mnakalay replied on at Permalink Reply
mnakalay
Look at this tutorial instead
https://documentation.concrete5.org/developers/express/express-forms...

What you will have to wrap your head around to achieve what you want is you have 3 layers or markup to customize:
1- the form itself
2- a wrapper around each field
3- the fields

1 is explained under "Copy and Modify the Outer Template Files"
2 is explained under "Copy The Custom Control Templates"
3 is explained under "Create the Attribute Form Templates"

These 3 parts I'm referring to are only what makes the view. You still have to do the whole controller thing to make it work.

That tutorial is pretty complete but a bit vague sometimes. Still everything you need is there.
ObiWan replied on at Permalink Reply
ObiWan
Thank you for your reply. I understand what you mean with the layers. I think I have a handle on that. The execution is the issue.

I followed your suggested tutorial in the past, but felt it was too complex, because it doesn't only require me to understand forms and Express, but the packaging system on top.

On your recommendation I gave it another shot, though. I get no errors, but no results either. Here what I have (the length of this post will attribute to the complexity of adding some CSS to a form).

I created a package "public/packages/my_packaged_site". This is the package controller:

<?php
namespace Concrete\Package\MyPackagedSite;
defined('C5_EXECUTE') or die('Access Denied.');
use \Concrete\Core\Package\Package;
class Controller extends Package
{
    protected $pkgHandle = 'my_packaged_site';
    protected $appVersionRequired = '8.5.0';
    protected $pkgVersion = '0.1';
    protected $pkgAutoloaderRegistries = array(
        'src/MyPackagedSite' => '\MyPackagedSite',
    );
    public function getPackageDescription()
    {
        return t('Enables the Packaged Site.');

"contact" is the handle of the form.

I actually need to adress one form only, but for now this will do.

Now to the custom form controller in public\packages\my_packaged_site\src\MyPackagedSite\Express\Controller\FormController.php:
<?php
namespace MyPackagedSite\Express\Controller;
use Concrete\Core\Express\Controller\StandardController;
use Concrete\Core\Express\Form\Context\FrontendFormContext as CoreFrontendFormContext;
use MyPackagedSite\Express\Form\Context\FrontendFormContext;
use Concrete\Core\Form\Context\Registry\ContextRegistry;
class FormController extends StandardController
{
    public function getContextRegistry()
    {
        return new ContextRegistry([
            CoreFrontendFormContext::class => new FrontendFormContext()
        ]);
    }
}


Next I created the custom context registry in public\packages\my_packaged_site\src\MyPackagedSite\Express\Form\Context\FrontendFormContext.php:
<?php
namespace MyPackagedSite\Express\Form\Context;
use Concrete\Core\Express\Form\Context\FrontendFormContext as CoreFrontendFormContext;
use Concrete\Core\Filesystem\TemplateLocator;
class FrontendFormContext extends CoreFrontendFormContext
{
    public function setLocation(TemplateLocator $locator)
    {
        $locator = parent::setLocation($locator);
        $locator->prependLocation([DIRNAME_ELEMENTS .
            DIRECTORY_SEPARATOR .
            DIRNAME_EXPRESS .
            DIRECTORY_SEPARATOR .
            DIRNAME_EXPRESS_FORM_CONTROLS .
            DIRECTORY_SEPARATOR .

Note that my editor tells me here that "Method 'MyPackagedSite\Express\Form\Context\FrontendFormContext::setLocation()' is not compatible with method 'Concrete\Core\Express\Form\Context\FrontendFormContext::setLocation()'. I am not sure if that matters.

Next I copied public\concrete\elements\express\form\form\form.php to public\packages\my_packaged_site\elements\express\form\form.php. Apart from adding a test-string I left the file unchanged.

On to allowing attrribute customization. I created the Express form context in public\packages\my_packaged_site\src\MyPackagedSite\Attribute\Context\FrontendFormContext.php
<?php
namespace MyPackagedSite\Attribute\Context;
use Concrete\Core\Attribute\Context\FrontendFormContext as BaseFrontendFormContext;
use Concrete\Core\Filesystem\TemplateLocator;
class FrontendFormContext extends BaseFrontendFormContext
{
    public function __construct()
    {
        parent::__construct();
        $this->preferTemplateIfAvailable('site', 'my_packaged_site');
    }
    public function setLocation(TemplateLocator $locator)
    {
        $locator->setTemplate(['site', 'my_packaged_site']);
        return $locator;


I get the same notice as above about non-compatibility with the core method.

Now I copied the content of
public\concrete\elements\form\bootstrap3.php to public\packages\my_packaged_site\elements\form\site.php

as well as the content of
public\concrete\elements\form\grouped\bootstrap3.php to public\packages\my_packaged_site\elements\form\grouped\site.php

Next is an attribute form template for text fields in public\packages\my_packaged_site\attributes\text\site.php
<?php
defined('C5_EXECUTE') or die("Access Denied.");
?>
<div class="field">
    <?php
    print $form->text(
        $this->field('value'),
        $value,
        [
            'placeholder' => $this->akTextPlaceholder
        ]
    );
    ?>
</div>


I installed this package, which it does without problems. Yet, I see no changes to the form. I should/want to see at least the
<div class="field"></div>
around my text fields, but somewhere the above does not get recognized.

Thank you for looking at this. :-)
mnakalay replied on at Permalink Reply
mnakalay
in public\packages\my_packaged_site\src\MyPackagedSite\Express\Form\Context\FrontendFormContext.php

You need to add

use Concrete\Core\Filesystem\TemplateLocator;

That's why your editor is not happy

You also have to add it in public\packages\my_packaged_site\src\MyPackagedSite\Attribute\Context\FrontendFormContext.php

That's the only errors I could see and they're actually important, so that might fix it.
ObiWan replied on at Permalink Reply
ObiWan
Thank you for your reply.

I added the lines you noticed (and updated the above post accordingly). I also reviewed my code again and made sure that the package I created installs without any errors (to be sure I did this on a completely fresh install of Concrete5). The package and its theme installs as intended. I get no discernible errors.

Sadly the problem remains and the rendered form stays untouched by any of the code. So the Express form keeps rendering in its "naked" state. I am running out of ideas. Do you (plural ;-)) still have one or two? I really do not want to give up on this.
mnakalay replied on at Permalink Reply
mnakalay
If you want send me your package by PM and I'll have a look
ObiWan replied on at Permalink Reply
ObiWan
Thank you for the offer. Will likely take you up on that. :-)
mnakalay replied on at Permalink Reply
mnakalay
so the problem is the file elements\form\form.php should actually be in elements\express\form\form\form.php
move it there and it will automagically work :)