<p>It's actually quite simple.
First you need a form:</p>

<pre><code>&lt;form method="post" id="myForm"&gt;
    &lt;!-- insert your route as an action parameter in camelCase --&gt;
    &lt;!-- pluginName/controllerName/methodName --&gt;
    &lt;input type="hidden" name="action" value="craftMailchimped/submittal/receiveEmail"&gt;
    &lt;input type="text" name="email"&gt;
    &lt;input type="button" id="submit" value="Submit"&gt;
&lt;/form&gt;
</code></pre>

<p>Then you have your javascript (I'll use jQuery ajax for that)</p>

<pre><code>$("#submit").click(function(e){
    e.preventDefault();
    $.ajax({
        type: "post",
        url: '', //&lt;- leave the url blank.. always...
        data: $("#myForm").serialize(),
        success: function(data){
            console.log(data);
            if(data.success === true){
                alert(data.message);
            }else{
                //display your data.errors here
            }
        },
        error: function (XMLHttpRequest, textStatus) {
            console.log("Status: " + textStatus);
        }
    });
});
</code></pre>

<p>And your controller and this <a href="https://gist.github.com/Anubarak/3a972ba498f1578a0eb658a8be80c9f8" rel="nofollow noreferrer">model</a></p>

<pre><code>public function actionReceiveEmail() {
    $response = [
        'success'   =&gt; false,
        'message'   =&gt; Craft::t('something went wrong')
    ];

    $emailModel = new CraftMailchimped_EmailModel();
    $emailModel-&gt;email = craft()-&gt;request-&gt;getParam('email');

    if(craft()-&gt;yourServiceName-&gt;subscribe($emailModel)){
        $response['success'] = true;
        $response['message'] = Craft::t('wuhu great :D');
    }else{
        $response['errors'] = $emailModel-&gt;getErrors();
    }

    $this-&gt;returnJson($response);
}
</code></pre>

<p>Your service could contain this method</p>

<pre><code>public function subscribe(CraftMailchimped_EmailModel $emailModel){
    if($success = $emailModel-&gt;validate()){
        //make your API calls
        $response = ......;
        if($response['error'] === 444){
            $emailModel-&gt;addError('email', Craft::t('Email is already taken'));
            $success = false;
        }
    }

    return $success;
}
</code></pre>

<p>So you are totally right with your points. In case you want to see how to manage records in your database take a look at this plugin <a href="https://github.com/Anubarak/usernotifications" rel="nofollow noreferrer">Click</a> I created it for learning purposes for someone else in <a href="https://craftcms.stackexchange.com/a/23129/5557">this thread</a>. Maybe you'll find it useful to learn some stuff like fetching objects from the database and inserting.</p>

<p><strong>Edit</strong><br>
to resume </p>

<ol>
<li>You should always leave the url blank, define an action parameter for your route. The request type does not matter, it's the same for ajax and normal requests</li>
<li>Your Route is always <code>pluginHandle/controllerName/functionName</code> in camelCase</li>
<li><p>Your messages and responses should always be defined in your Controllers, your Services are just for logic that return true or false (or some objects like <code>craft()-&gt;entries-&gt;getEntryById()</code>), you can create models with validations for error messages you can use them like that: (validators will provide the translated messages)</p>

<pre><code>// in your controller
$mailChimpModel;
if(craft()-&gt;mailchimp-&gt;subscribe($mailChimpModel)){
    $response['success'] = true;
}else{
    $response['errors'] = $mailChimpModel-&gt;getErrors();
}
</code></pre>

<p><code>$response['errors']</code> is an array with all field handles and the corresponding translated error messages like <code>'email' =&gt; ['This Mail is already in the list']</code> </p></li>
<li>Crafts <code>RequestService</code> has all the methods you need to access the request variables. Those values are all safely escaped and secure, so you can be sure there won't be security measures. You can access parameters with <code>craft()-&gt;request-&gt;getParam('key', default value);</code> </li>
</ol>

CC BY-SA 3.0
2017-12-18T01:19:57.647Z
Back to work tomorrow. I can give this a read over then, when I'm actually looking at my real code. Thanks again, and will vote on this asap.
Dan Zuzevich
CC BY-SA 3.0
2017-12-18T14:49:05.983Z
https://craftcms.com/docs/plugins/controllers#allowing-anonymous-access-to-actions
Robin Schambach
CC BY-SA 3.0
2017-12-18T15:22:18.220Z
Thanks man. I used something close to this. Excellent, and in-depth answer as usual.
Dan Zuzevich
CC BY-SA 3.0
2017-12-18T15:24:08.967Z
Does it work for you now? If not we can continue our conversation in a chat if you like. Btw don't worry once you get used to it, it is much faster than regular PHP
Robin Schambach
CC BY-SA 3.0
2017-12-18T15:35:02.287Z
No idea, how to message people on here.
Dan Zuzevich
CC BY-SA 3.0
2017-12-18T15:39:22.340Z
Can you join this room? https://chat.stackexchange.com/rooms/70444/plugin-developement
Robin Schambach
CC BY-SA 3.0
2017-12-18T15:43:46.677Z
Let us [continue this discussion in chat](http://chat.stackexchange.com/rooms/70446/discussion-between-robin-schambach-and-daniel-zuzevich).
Robin Schambach
CC BY-SA 3.0
2017-12-15T18:13:51.717Z
2017-12-16T10:06:25.807Z
2017-12-16T10:06:25.807Z
Robin Schambach
<p>I am making some progress with creating a custom plugin, and am curious as to whether I am following proper "Craft standards". Here is my scenario:</p>

<p>A user needs to submit a one field form that contains their email address. Upon button click, I would like to prevent the default action, and send the email address via AJAX to my plugin for processing.</p>

<p>After reading through the Craft Plugin Docs, I am under the impression that my plugin requires the following functionality(and in this order).</p>

<ol>
<li>Send email address via AJAX to a Controller.</li>
<li>The controller will then extract the email, and send it off to a 
Service.</li>
<li>The Service, is where I should write my code that connects to the MailChimp API</li>
<li>Send the result of whether the Mailchimp API request was successful from the Service, back to the Controller.</li>
<li>The Controller will then send back the response to my JavaScript, where I will ultimately display a success or error message to the user.</li>
</ol>

<p><strong>I have been successful</strong> in sending an AJAX request from my JavaScript code to my Controller via the following code, and receiving some dumby test text.</p>

<pre><code>function sendAjax() {
    var xhr = new XMLHttpRequest()
    xhr.open('POST', siteUrl + 'ajax/ajax-mailchimp.html')
    xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8')

    xhr.onload = function() {
      if(xhr.status === 200) {
        console.log(xhr.responseText)
      }
    }
    xhr.send(encodeURI('action=/craftMailchimped/submittal/receiveEmail&amp;email=fakeemailaddress@yahoo.com'))
  }
</code></pre>

<p>In my controller, I have the following:</p>

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

class CraftMailchimped_SubmittalController extends BaseController {

    public function actionReceiveEmail() {
        echo 'Wuzup?';
    }
}
</code></pre>

<p><strong>In case you are wondering</strong> what '<em>ajax/ajax-mailchimp.html</em>' is, its an empty template file, with no code in it. I did this, because I didn't really know what to put in as the URL in the xhr.POST method in my JavaScript code.</p>

<p>I am concerned I am not going about this in the right way, as I wouldn't even know how I would extract the email address inside my controller.</p>

<p>Any help on this?</p>

<p>My Form HTML for reference:</p>

<pre><code>&lt;form id="updates" class="mchimp"&gt;
    &lt;p class="newsletter"&gt;
      {{ entry.connectNewsletterCta }}
    &lt;/p&gt;
    &lt;div class="elements-wrapper"&gt;
      &lt;input type="email" placeholder="Enter your email" required&gt;
      &lt;button class="btn"&gt;
        {{ entry.connectNewsletterButtonText }}
      &lt;/button&gt;
    &lt;/div&gt;
  &lt;/form&gt;
</code></pre>

<plugin-development>
How to Properly Use Controller and Service in Custom Plugin
# How to Properly Use Controller and Service in Custom Plugin

(Asked by: username_0 on 2017-12-15)

I am making some progress with creating a custom plugin, and am curious as to whether I am following proper "Craft standards". Here is my scenario:
A user needs to submit a one field form that contains their email address. Upon button click, I would like to prevent the default action, and send the email address via AJAX to my plugin for processing.
After reading through the Craft Plugin Docs, I am under the impression that my plugin requires the following functionality(and in this order).

Send email address via AJAX to a Controller.
The controller will then extract the email, and send it off to a 
Service.
The Service, is where I should write my code that connects to the MailChimp API
Send the result of whether the Mailchimp API request was successful from the Service, back to the Controller.
The Controller will then send back the response to my JavaScript, where I will ultimately display a success or error message to the user.

I have been successful in sending an AJAX request from my JavaScript code to my Controller via the following code, and receiving some dumby test text.
function sendAjax() {
    var xhr = new XMLHttpRequest()
    xhr.open('POST', siteUrl + 'ajax/ajax-mailchimp.html')
    xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8')

    xhr.onload = function() {
      if(xhr.status === 200) {
        console.log(xhr.responseText)
      }
    }
    xhr.send(encodeURI('action=/craftMailchimped/submittal/receiveEmail&email=fakeemailaddress@yahoo.com'))
  }

In my controller, I have the following:

In case you are wondering what 'ajax/ajax-mailchimp.html' is, its an empty template file, with no code in it. I did this, because I didn't really know what to put in as the URL in the xhr.POST method in my JavaScript code.
I am concerned I am not going about this in the right way, as I wouldn't even know how I would extract the email address inside my controller.
Any help on this?
My Form HTML for reference:

    
      {{ entry.connectNewsletterCta }}
    
    
      
      
        {{ entry.connectNewsletterButtonText }}

**Tags:** plugin-development

---

## 1 answers

### Answer by username_1 on 2017-12-15. Score: 1 | Accepted answer

It's actually quite simple.
First you need a form:

    
    
    
    
    


Then you have your javascript (I'll use jQuery ajax for that)
$("#submit").click(function(e){
    e.preventDefault();
    $.ajax({
        type: "post",
        url: '', //<- leave the url blank.. always...
        data: $("#myForm").serialize(),
        success: function(data){
            console.log(data);
            if(data.success === true){
                alert(data.message);
            }else{
                //display your data.errors here
            }
        },
        error: function (XMLHttpRequest, textStatus) {
            console.log("Status: " + textStatus);
        }
    });
});

And your controller and this model
public function actionReceiveEmail() {
    $response = [
        'success'   => false,
        'message'   => Craft::t('something went wrong')
    ];

    $emailModel = new CraftMailchimped_EmailModel();
    $emailModel->email = craft()->request->getParam('email');

    if(craft()->yourServiceName->subscribe($emailModel)){
        $response['success'] = true;
        $response['message'] = Craft::t('wuhu great :D');
    }else{
        $response['errors'] = $emailModel->getErrors();
    }

    $this->returnJson($response);
}

Your service could contain this method
public function subscribe(CraftMailchimped_EmailModel $emailModel){
    if($success = $emailModel->validate()){
        //make your API calls
        $response = ......;
        if($response['error'] === 444){
            $emailModel->addError('email', Craft::t('Email is already taken'));
            $success = false;
        }
    }

    return $success;
}

So you are totally right with your points. In case you want to see how to manage records in your database take a look at this plugin Click I created it for learning purposes for someone else in this thread. Maybe you'll find it useful to learn some stuff like fetching objects from the database and inserting.
Edit
to resume 

You should always leave the url blank, define an action parameter for your route. The request type does not matter, it's the same for ajax and normal requests
Your Route is always pluginHandle/controllerName/functionName in camelCase
Your messages and responses should always be defined in your Controllers, your Services are just for logic that return true or false (or some objects like craft()->entries->getEntryById()), you can create models with validations for error messages you can use them like that: (validators will provide the translated messages)
// in your controller
$mailChimpModel;
if(craft()->mailchimp->subscribe($mailChimpModel)){
    $response['success'] = true;
}else{
    $response['errors'] = $mailChimpModel->getErrors();
}

$response['errors'] is an array with all field handles and the corresponding translated error messages like 'email' => ['This Mail is already in the list'] 
Crafts RequestService has all the methods you need to access the request variables. Those values are all safely escaped and secure, so you can be sure there won't be security measures. You can access parameters with craft()->request->getParam('key', default value);

> **Comments:**
> **username_0**: Back to work tomorrow. I can give this a read over then, when I'm actually looking at my real code. Thanks again, and will vote on this asap.  
> **username_1**: https://craftcms.com/docs/plugins/controllers#allowing-anonymous-access-to-actions  
> **username_0**: Thanks man. I used something close to this. Excellent, and in-depth answer as usual.  
> **username_1**: Does it work for you now? If not we can continue our conversation in a chat if you like. Btw don't worry once you get used to it, it is much faster than regular PHP  
> **username_0**: No idea, how to message people on here.  
> **username_1**: Can you join this room? https://chat.stackexchange.com/rooms/70444/plugin-developement  
> **username_1**: Let us [continue this discussion in chat](http://chat.stackexchange.com/rooms/70446/discussion-between-robin-schambach-and-daniel-zuzevich).  

---

