Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating a module for Orchard that stores data from the front-end

Code will come later as soon as i am in front of my development machine, though hoping in the meantime someone can help....

I am trying to develop on Orchard CMS v1.6.1. At the moment I am in the midst of trying to develop a module that will essentially allow me to place a Newsletter subscription view within the footer (or anywhere else i choose) on the front end.

I have followed several tutorials and they all seem to show how to store data from the Admin only - I need to store data on the FRONT end as well as the admin... This is what I am looking for help on...

So, so far, my module has all the "usual" driver/handler/editorTemplates view/migrations/contentpart/contentpartrecord and i can create a subscription entry in the admin - I have my content Type setup and see my module in the admin.

Pick any tutorial on modules you like and that's the path i followed - they all seem to be the same in terms of creating a module and storing data via the admin....

With answers from other questions I managed to get the module to display on the front-end - this is by way of overriding Display in my driver and using the shapeHelper.DisplayTemplate() method.

Some strange things though - when the front-end (with my form now displayed thanks to Placement.info) page first loads I get a blank entry in my database table (subscriptions table) - this happens without actually posting back. I have little to no idea what part of code is causing this to happen. This needs to not happen - i only want to store data when the user fills out the form and clicks submit.

Secondly, I need a little guidance in actually storing the data the user enters in on the front end..

Typically what should I have in my module to store data entered in the front end?

I'm not after actual code - just an idea of what i should be doing. I develop in web forms typically, so MVC is a little new to me.

should i have a controller/route etc?

should the form i display on the front-end be somewhat separate from the module i have created?

Can someone point me in the right direction of what you do to store data inside of Orchard?

I guess at this point any help would be great...

Update

Thank you for the answers given so far. In this case I could use custom forms, though don't want to. I ideally want the data stored in it's own table.

Also, this module will give me the basis i need to create more complex modules that will store data from the front-end. I just can't seem to get my head around how Orchard stitches this all together.. I.E storing data via the controller into the orchard system..what code would i need to create a new row in my table?

like image 821
Darren Wainwright Avatar asked Jan 13 '23 17:01

Darren Wainwright


1 Answers

Well, what you are doing in the admin is creating a content type. I'm not sure you really need to be storing subscription in such a way. But maybe I don't understand your scenario so if this is how you wish to proceed, you may want to check out Orchard Custom Forms. I admit, it is initially unclear how to create content types from the front end. You can look at this tutorial on how to use Orchard Custom Forms. http://devdirective.com/post/160/how-to-create-custom-forms-in-orchard-cms-with-email-and-recaptcha The example they are creating there is a contact form. It is pretty simple actually, and very powerful. I believe it is included in the core. For 1.7 at least.

However, for your situation with a newsletter subscription I would say you may want a different approach, and simply store a list of emails that are subscribed to your newsletter in their own table.

For this you will need to create your own widget, with a part that displays a form linking to your own custom controller that submits their email and then saves it. This would all be done using simple MVC and you would want to check out tutorials on that.

If your users have to be logged in to subscribe to your newsletter you could be even more clever and attach a part to the user and update this when they say they want to subscribe to your newsletter. But now I am babbling.

I have sort of just thrown very vague ideas on how to go about creating your own widget to display a form. I'd be happy to provide some more detail if you think this is a route you may want to go down. Else...I'm too lazy ^_^

UPDATE:

Okay, so I see Nick has given you some pointers on how to go about this. I started reading but got bored, think it sounds pretty much fine though. Thought I'd just add my two pennies worth. I'm no expert in Orchard but this is how it all seems to me. Corrections to my nonsense much appreciated.

Parts are stitched onto Content Types. A part consists over several parts... You see what I mean.

  • The driver: this is basically a controller. It displays the view people will see on the front end and the editor that will be shown when you create the content item. It also handles the postback when a content item is created, validation etc.
  • The model: this is where you will store data about your part. So if you have any settings related to the part. This inherits from something that gives it an id connecting it to the content item. Cant remember the name.
  • The handler: this basically "handles" the creation of your content item. It will chuck your data into a repository and can do other clever stuff. You can drop custom logic into the services it provides. But don't worry about it, just leave it to do its stuff.
  • The views: Content parts have several views associated with them. Editor views and display views. These are stored in separate folders. EditorTemplates/Parts/... is where your editor will be stored (shown when you create the content item). Parts/... is where you store your views that show front end stuff.
  • The placement: this file contains information about where your part will be displayed within the content item. It is pretty cool.

So the first thing we need is to create the part itself. You can write it all yourself. But it is tedious and easy to forget something when you are new. I always forget something important. There are vs templates available from... somewhere. I usually just use a cool little code generation module. So go to the gallery and download and enable Code Generation Extensions by piotr szmyd. You can now run the command line application Orchard.exe. This is stored in the bin folder within Orchard.Web. Check this blog post for details on how to use this module. http://www.szmyd.com.pl/blog/generating-orchard-content-parts-via-command-line

Right so we will create a part called NewsletterPart using this command.

codegen part YourModuleName NewsletterPart

This will generate all the necessary bits and bobs, drivers etc. Your part shouldn't really need any settings. Maybe in the future when it needs to be simple so for now we will leave the models blank. We will store your list of newsletter subscribers in a different table. In a bit. First lets get it to display your part. There should be a NewsletterPart.cshtml file in your Views/Parts/ folder. Write some random words in here so we know it is displaying. Then go to the Placement.info file and make sure it has a line in there that tells your part to be displayed. eg:

< Place Parts_NewsletterPart="Content:5" />

Now we actually need to create your part and make a widget that you can display your part in. This is done with the migrations file.

    using System;
using Orchard.ContentManagement;
using Orchard.ContentManagement.MetaData;
using Orchard.Core.Contents.Extensions;
using Orchard.Data.Migration;
using Orchard.Environment.Extensions;

namespace MyModule {
    public class Migrations : DataMigrationImpl {

        public Migrations() {

        }

        public int Create() {
        // Create Newsletter part table
            SchemaBuilder.CreateTable("NewsletterPartRecord", table => table
                .ContentPartRecord()
            );

        // Create the part and make it attachable to content items
            ContentDefinitionManager.AlterPartDefinition("NewsletterPart", builder => builder.Attachable());

        return 1;
    }

    public int UpdateFrom1() {
        // Create Widget
        ContentDefinitionManager.AlterTypeDefinition("NewsletterWidget", cfg => cfg
                .WithPart("NewsletterPart")
                .WithPart("WidgetPart")
                .WithPart("CommonPart")
                .WithSetting("Stereotype", "Widget"));

            return 2;   
    }
    }

    }

You should now be able to create a widget on the dashboard and it will appear in footer.

Now we need to create a little form to display some stuff. The form will look something like this. Chuck it into the parts display view instead of whatever you wrote before.

@model dynamic

@using (Html.BeginForm("Subscribe", "Subscription", FormMethod.Post))
{
    <fieldset>
        @Html.AntiForgeryTokenOrchard()    

        <label >
            Email:</label>
        @Html.TextBox("Email")<br />


        <button class="primaryAction" type="submit">@T("Submit")</button>
    </fieldset>
}

Now lets make the model for this form to work. Create a file in the models folder called Subscription Model with something like the following:

using System;

namespace MyModule.Models
{
    public class SubscriptionModel
    {
        public SubscriptionModel() 
        {

        }

        public virtual int Id { get; set; }

        public virtual string Email { get; set; }


    }
}

This will store your email subscribers. Now you need to actually do something with this. We can create the controller that will handle everything. Create a folder called Controllers and then add a file called SubscriptionController.cs. Add a method called Subscribe that can look something like this:

public class SubscriptionController : Controller {

   private readonly IRepository<EmailModel> emailRepository;

   public SubscriptionController(IRepository<EmailModel> emailRepository) {


    this.emailRepository = emailRepository;

        [HttpPost]
        public ActionResult Subscribe(string email)
        {
            var record = new EmailRecord() {
        Email = email
        };

        this.emailRepository.Create(record);


            //return to return url
        }
   }
}

All that is left to do is to create your emailrecord table in the db. Back to migrations and add a new method.

public int UpdateFrom2() {
   SchemaBuilder.CreateTable("EmailModel", table => table
                .Column<string>("Email")
                .Column<int>("Id", column => column.PrimaryKey()));

   return 3;
}

Just samples I wrote in notepad so probably will not compile. Got a bit longer than I expected...my blunderings.

like image 154
Hazza Avatar answered Jan 15 '23 20:01

Hazza