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

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

<pre><code>public function actionName()
{   
    $templateVars = array();

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

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

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

<p>And then <code>plugins/myform/templates/forms/name.html</code> is like this:</p>

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

    &lt;!-- Just a quick example of error output. ---&gt;
    {% if errors is defined %}
        {% if errors.firstname is defined %}
            {{ errors.firstname[0] }}
        {% endif %}
        {% if errors.surname is defined %}
            {{ errors.surname[0] }}
        {% endif %}
    {% endif %}

    &lt;p&gt;First name: &lt;input type="text" name="firstname" value="{% if nameModel is defined %}{{ nameModel.firstname }}{% endif %}"&gt;&lt;/p&gt;
    &lt;p&gt;Surname: &lt;input type="text" name="surname" value="{% if nameModel is defined %}{{ nameModel.surname }}{% endif %}"&gt;&lt;/p&gt;

    &lt;input type="submit" value="Submit"&gt;
&lt;/form&gt;
</code></pre>

<p>This seems to work fine but feels wrong in a few little ways:</p>

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

CC BY-SA 4.0
2021-08-11T16:08:40.187Z
Thank you for the comment! There is also the `$this->requirePostRequest()` method which may save you from writing the conditional. I believe the `actionUrl` should be used with the `action` input. The redirect input could be `myForm/forms/dob` but redirecting in the controller works too.
Clark Nelson
CC BY-SA 3.0
2015-08-26T21:12:35.487Z
2015-08-26T21:12:35.487Z
Phil Gyford
<p>I'm getting confused with how to submit forms to a plugin controller as shown briefly <a href="http://buildwithcraft.com/docs/plugins/controllers" rel="nofollow">in the docs</a>.</p>

<p>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.</p>

<p>But I don't understand how to do the:</p>

<ol>
<li>Display form</li>
<li>POST form</li>
<li>Either:

<ul>
<li>Validation passes, so save the data and redirect to the next page</li>
<li>Or, fail validation and display the same form again</li>
</ul></li>
</ol>

<p>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 <code>plugins/myform/models/myForm_NameModel.php</code>:</p>

<pre><code>&lt;?php
namespace Craft;

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

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

<p>Then I have <code>plugins/myform/controllers/myForm_FormController.php</code></p>

<pre><code>&lt;?php
namespace Craft;

class MyForm_FormController extends BaseController
{
    protected $allowAnonymous = true;

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

    public function actionSaveName()
    {
        $this-&gt;requirePostRequest();

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

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

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

<p>And in <code>plugins/myform/templates/forms/name.html</code>:</p>

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

    &lt;p&gt;First name: &lt;input type="text" name="firstname" value="{% if nameModel is defined %}{{ nameModel.firstname }}{% endif %}"&gt;&lt;/p&gt;
    &lt;p&gt;Surname: &lt;input type="text" name="surname" value="{% if nameModel is defined %}{{ nameModel.surname }}{% endif %}"&gt;&lt;/p&gt;

    &lt;input type="submit" value="Submit"&gt;
&lt;/form&gt;
</code></pre>

<p>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 <code>action</code> and <code>redirect</code> in the form template, and exactly what the controller actions should be doing.</p>

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

CC BY-SA 3.0
2015-08-26T17:06:18.110Z
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
CC BY-SA 3.0
2015-08-26T17:36:42.727Z
I think the action input should have `value="myform/form/saveName"` for it to hit your action, at least.
megatrond
CC BY-SA 3.0
2015-08-26T19:23:14.557Z
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
CC BY-SA 3.0
2015-08-26T19:25:10.010Z
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
CC BY-SA 3.0
2015-08-26T19:31:37.463Z
Hmm, I could give it a URL like `/actions/myForm/form/dob` but that doesn't do anything different either.
Phil Gyford
CC BY-SA 3.0
2015-08-26T20:48:41.503Z
Is there a reason you're saving the template with a `.php` extension and not `.twig` or `.html`?  Pretty sure that's not going to work.
Brad Bell
CC BY-SA 3.0
2015-08-26T21:01:06.277Z
Ugh, sorry, that's just me making the example code; my templates are all `.html`.
Phil Gyford
<plugin-development><form><controller>
Plugin Controller actions for entering data and redisplaying form or redirecting
# Plugin Controller actions for entering data and redisplaying form or redirecting

(Asked by: username_0 on 2015-08-26)

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:

Display form
POST form
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:
 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
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:

    {{ getCsrfInput() }}
    
    

    First name: 
    Surname: 

    


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?

**Tags:** plugin-development, form, controller
> **Comments:**
> **username_0**: 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.  
> **username_1**: I think the action input should have `value="myform/form/saveName"` for it to hit your action, at least.  
> **username_0**: 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.  
> **username_1**: 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.  
> **username_0**: Hmm, I could give it a URL like `/actions/myForm/form/dob` but that doesn't do anything different either.  
> **username_2**: Is there a reason you're saving the template with a `.php` extension and not `.twig` or `.html`?  Pretty sure that's not going to work.  
> **username_0**: Ugh, sorry, that's just me making the example code; my templates are all `.html`.  

---

## 1 answers

### Answer by username_0 on 2015-08-26. Score: 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:

    {{ getCsrfInput() }}
    
    

    
    {% if errors is defined %}
        {% if errors.firstname is defined %}
            {{ errors.firstname[0] }}
        {% endif %}
        {% if errors.surname is defined %}
            {{ errors.surname[0] }}
        {% endif %}
    {% endif %}

    First name: 
    Surname: 

    


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 .

> **Comments:**
> **username_3**: Thank you for the comment! There is also the `$this->requirePostRequest()` method which may save you from writing the conditional. I believe the `actionUrl` should be used with the `action` input. The redirect input could be `myForm/forms/dob` but redirecting in the controller works too.  

---

