0

I'm getting confused with how to submit forms to a plugin controller as shown briefly in the docs.

I'm making a multi-page form, which saves the data on each page to the session, sending it elsewhere at the end of the process. None of the data is related to things (Entries, etc) in Craft.

But I don't understand how to do the:

  1. Display form
  2. POST form
  3. Either:
    • Validation passes, so save the data and redirect to the next page
    • Or, fail validation and display the same form again

Let's say the first page asks for firstname and surname, and the second for date of birth. I have a model per form page, for validation, so there's plugins/myform/models/myForm_NameModel.php:

<?php
namespace Craft;

class MyForm_NameModel extends BaseModel
{
    protected function defineAttributes()
    {
        return array(
            'firstname' => array(AttributeType::Name, 'maxLength' => 100),
            'surname' => array(AttributeType::Name, 'maxLength' => 100),
        );
    }
}

And I'll have a similar model for the form on the date of birth page.

Then I have plugins/myform/controllers/myForm_FormController.php

<?php
namespace Craft;

class MyForm_FormController extends BaseController
{
    protected $allowAnonymous = true;

    // Display name form.
    public function actionName()
    {
        $this->renderTemplate('myForm/forms/name');
    }

    public function actionSaveName()
    {
        $this->requirePostRequest();

        $post = craft()->request->getPost();
        $nameModel = MyForm_NameModel::populateModel($post);

        if ($nameModel->validate()) {
            // TODO: Store in session.
            $this->redirectToPostedUrl();
        }
        else
        {
            craft()->userSession->setError('Error!');
            craft()->urlManager->setRouteVariables(array(
                'nameModel' => $nameModel
            ));
        }
    }

    // Display date of birth form.
    public function actionDob()
    {
        $this->renderTemplate('myForm/forms/dob');
    }
}

And in plugins/myform/templates/forms/name.html:

<form method="post" action="" accept-charset="UTF-8">
    {{ getCsrfInput() }}
    <input type="hidden" name="action" value="myForm/form/name">
    <input type="hidden" name="redirect" value="myForm/form/dob">

    <p>First name: <input type="text" name="firstname" value="{% if nameModel is defined %}{{ nameModel.firstname }}{% endif %}"></p>
    <p>Surname: <input type="text" name="surname" value="{% if nameModel is defined %}{{ nameModel.surname }}{% endif %}"></p>

    <input type="submit" value="Submit">
</form>

I'm missing something at the moment because all I get is the name form, and submitting it simply refreshes the page; no errors, no submitted values displayed. I think I'm confused by the action and redirect in the form template, and exactly what the controller actions should be doing.

I'm also not sure if using AttributeType::foo is correct when defining these models, seeing as they're not things that will be saved in the database?

  • Man, sorry that's a bit long. I'm just baffled at the moment; it feels like the docs are missing a crucial bit of explanation for me. – Phil Gyford Aug 26 '15 at 17:06
  • I think the action input should have value="myform/form/saveName" for it to hit your action, at least. – megatrond Aug 26 '15 at 17:36
  • You'd think so... but I can put anything for that value, even complete gibberish, and I get the same result; the page refreshes and shows the form again. – Phil Gyford Aug 26 '15 at 19:23
  • Have you tried changing the redirect param to a template? I don't think controller actions are valid for redirects, so that might resolve to nothing, and reload the current url instead. – megatrond Aug 26 '15 at 19:25
  • Hmm, I could give it a URL like /actions/myForm/form/dob but that doesn't do anything different either. – Phil Gyford Aug 26 '15 at 19:31
1

I have something working, although I'm not sure it's the "correct" way of doing this.

I've got rid of the actionSaveName() method and my actionName() method in the Controller is now like this:

public function actionName()
{   
    $templateVars = array();

    if (craft()->request->isPostRequest())
    {
        // The form was submitted.
        $post = craft()->request->getPost();
        $nameModel = MyForm_NameModel::populateModel($post);

        if ($nameModel->validate()) {
            // Successfully posted the name.
            // TODO: Store in session.
            $this->redirectToPostedUrl();
        }
        else
        {
            // Something was wrong with the submitted names.
            $templateVars['errors'] = $nameModel->getErrors();
            $templateVars['nameModel'] = $nameModel;
        }
    }

    // Either the first time viewing the form, or there were errors.
    $this->renderTemplate('myForm/forms/dob', $templateVars);
}

And then plugins/myform/templates/forms/name.html is like this:

<form method="post" action="" accept-charset="UTF-8">
    {{ getCsrfInput() }}
    <input type="hidden" name="action" value="myForm/form/name">
    <input type="hidden" name="redirect" value="{{ actionUrl('myForm/form/dob') }}">

    <!-- Just a quick example of error output. --->
    {% if errors is defined %}
        {% if errors.firstname is defined %}
            {{ errors.firstname[0] }}
        {% endif %}
        {% if errors.surname is defined %}
            {{ errors.surname[0] }}
        {% endif %}
    {% endif %}

    <p>First name: <input type="text" name="firstname" value="{% if nameModel is defined %}{{ nameModel.firstname }}{% endif %}"></p>
    <p>Surname: <input type="text" name="surname" value="{% if nameModel is defined %}{{ nameModel.surname }}{% endif %}"></p>

    <input type="submit" value="Submit">
</form>

This seems to work fine but feels wrong in a few little ways:

  • The hidden action input is ignored; I can put anything in that and nothing changes; I really don't understand how that is supposed to be used.
  • If the submission is successful the URL redirected to is like /index.php?p=actions/myForm/form/dob rather than /actions/myForm/dob.
  • Mainly, that it feels quite different from the description in http://buildwithcraft.com/docs/plugins/controllers .

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.