Extending Custom Form Module ItemController

Topics: Customizing Orchard, Writing modules
Aug 6, 2013 at 8:32 AM
Hi,

I've created a new Custom Form using the Orchard Custom Form Module, which works fine. However, additional processing needs to be done on the form submission, before the page redirects.

To achieve this, I have implemented a new Module and added a Route with a higher priority that is triggered when the form is posted. The form's custom code runs, which includes a Web Request, and then the usual Custom Form submission code should run, which will add the information into form’s Submissions.

The problem is, I can't figure out how to trigger the Custom Form's ItemController to perform its usual process. I've tried to inherit the new Module’s Controller from the Custom Form's ItemController, but I then get a build error: 'Orchard.CustomForms.Controllers.ItemController' does not contain a constructor that takes 0 arguments.

Has anyone attempted anything similar to this and have any tips and pointers, or is there a different approach to handling this? I'm sure this could be done with Workflow, but I'd prefer to handle it directly via code.

This is the code I've created:
public class SubscribeController : Orchard.CustomForms.Controllers.ItemController
    {
        private readonly IContentManager _contentManager;
        private readonly ITransactionManager _transactionManager;
        private readonly IRulesManager _rulesManager;
        private readonly ITokenizer _tokenizer;

        public SubscribeController(IOrchardServices orchardServices, IContentManager contentManager, ITransactionManager transactionManager,
            IShapeFactory shapeFactory, IRulesManager rulesManager, ITokenizer tokenizer) 
        {
            Services = orchardServices;
            _contentManager = contentManager;
            _transactionManager = transactionManager;
            _rulesManager = rulesManager;
            _tokenizer = tokenizer;
            T = NullLocalizer.Instance;
            Logger = NullLogger.Instance;
            Shape = shapeFactory;
        }

        dynamic Shape { get; set; }
        public IOrchardServices Services { get; private set; }

        [HttpPost]
        [Themed]
        public void DoSomething()
        {
             // Custom Code occurs here...
            // Custom Forms Module code should occur/be called here...
        }
    }
Coordinator
Aug 6, 2013 at 9:18 AM
I think you're trying to do this backwards. Looks like you could let the regular controller handle it, and handle the publication event for the form.
Aug 9, 2013 at 3:50 AM
Hi Bertrand,

Thanks for the quick response. Following your suggestion, I've changed approach and added a SubscribeHandler in, with an OnCreated Event. The reason for the Created event is because the Web Request should only ever occur once. After some debugging, it seems the CustomForm stores the fields in a ContentPart:
        public SubscribeHandler()
        {
            OnCreated<ContentPart>((context, part) => 
                {
                    if (context.ContentType == "SubscribeForm")
                        this.PostWebRequest(context, part);
                }
            );
        }
However, when the above functional gets triggered, the ContentPart does not include any of the Fields. After some further debugging, it seems that the Fields are stored in an entirely different ContentPart, at the third index. See below:
context.ContentItem.Parts
Count = 5
    [0]: {Orchard.ContentManagement.ContentPart<Orchard.Core.Common.Models.CommonPartVersionRecord>}
    [1]: {Orchard.Projections.Models.FieldIndexPart}
    [2]: {Orchard.Core.Common.Models.CommonPart}
    [3]: {Orchard.ContentManagement.ContentPart}
    [4]: {Orchard.ContentManagement.FieldStorage.InfosetStorage.InfosetPart}
Using context.ContentItem.As<ContentPart>(); only seems to retrieve the ContentPart at the first index. Is there a way to retrieve the ContentPart at the third index? Or am I taking the wrong approach to solving this problem? Should the handler actually be tapping in at the Published event or another location in the Events Lifecycle?
Coordinator
Aug 9, 2013 at 5:49 PM
Don't do As in this case. Instead, do something like dynamic ci = part.ContentItem; ci.SubscribeForm.NameOfTheField.
Coordinator
Aug 10, 2013 at 5:58 PM
The Created event is triggered when the object is newly constructed, before the Updated one which is when data has been populated. If you want to intercept a form submission you will need to check for Created AND THEN Updated. In the handler flag the content item when it's in Created, and only trigger your Updated for this content item.

If you are using 1.7 you can also use the Workflow module. I have changed the Created activity to have this behavior by default.