diff --git a/Perplex.Umbraco.Forms/App_Plugins/PerplexUmbracoForms/PerplexUmbracoForms.config b/Perplex.Umbraco.Forms/App_Plugins/PerplexUmbracoForms/PerplexUmbracoForms.config
index 0e560b1..7b24969 100644
--- a/Perplex.Umbraco.Forms/App_Plugins/PerplexUmbracoForms/PerplexUmbracoForms.config
+++ b/Perplex.Umbraco.Forms/App_Plugins/PerplexUmbracoForms/PerplexUmbracoForms.config
@@ -44,4 +44,8 @@
+
+ true
+ 10
+
\ No newline at end of file
diff --git a/Perplex.Umbraco.Forms/Code/Configuration/PerplexCacheConfig.cs b/Perplex.Umbraco.Forms/Code/Configuration/PerplexCacheConfig.cs
new file mode 100644
index 0000000..0d2a328
--- /dev/null
+++ b/Perplex.Umbraco.Forms/Code/Configuration/PerplexCacheConfig.cs
@@ -0,0 +1,14 @@
+using System.Xml.Serialization;
+
+namespace PerplexUmbraco.Forms.Code.Configuration
+{
+ [XmlType("PerplexCacheConfig")]
+ public class PerplexCacheConfig
+ {
+ [XmlElement("CacheDurationInMinutes")]
+ public int CacheDurationInMinutes { get; set; }
+
+ [XmlElement("EnableCache")]
+ public bool EnableCache { get; set; }
+ }
+}
diff --git a/Perplex.Umbraco.Forms/Code/Configuration/PerplexUmbracoFormsConfig.cs b/Perplex.Umbraco.Forms/Code/Configuration/PerplexUmbracoFormsConfig.cs
index 6c876da..27fc3ce 100644
--- a/Perplex.Umbraco.Forms/Code/Configuration/PerplexUmbracoFormsConfig.cs
+++ b/Perplex.Umbraco.Forms/Code/Configuration/PerplexUmbracoFormsConfig.cs
@@ -1,11 +1,9 @@
using System;
using System.Collections.Generic;
using System.IO;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
using System.Web.Hosting;
using System.Xml.Serialization;
+
using static PerplexUmbraco.Forms.Code.Constants;
namespace PerplexUmbraco.Forms.Code.Configuration
@@ -73,6 +71,8 @@ public static void CreateIfNotExists()
public PerplexRecaptchaConfig PerplexRecaptchaConfig { get; set; }
+ public PerplexCacheConfig PerplexCacheConfig { get; set; }
+
private static string GetFilePath()
{
return HostingEnvironment.MapPath(Constants.CONFIGURATION_FILE_PATH);
@@ -139,6 +139,12 @@ private static string GetFilePath()
PerplexRecaptchaConfig = new PerplexRecaptchaConfig
{
ErrorMessage = ""
+ },
+
+ PerplexCacheConfig = new PerplexCacheConfig
+ {
+ EnableCache = false,
+ CacheDurationInMinutes = 10
}
};
}
diff --git a/Perplex.Umbraco.Forms/Code/UmbracoEvents.cs b/Perplex.Umbraco.Forms/Code/UmbracoEvents.cs
index 69214d2..c223061 100644
--- a/Perplex.Umbraco.Forms/Code/UmbracoEvents.cs
+++ b/Perplex.Umbraco.Forms/Code/UmbracoEvents.cs
@@ -1,12 +1,14 @@
-using System.Linq;
+using System;
+using System.Linq;
using System.Web;
+
+using PerplexUmbraco.Forms.Code.Configuration;
+
using Umbraco.Core;
using Umbraco.Core.Logging;
-using PerplexUmbraco.Forms.Code.Configuration;
-using Umbraco.Web;
-using Umbraco.Forms.Data.Storage;
-using System;
using Umbraco.Forms.Core;
+using Umbraco.Forms.Data.Storage;
+using Umbraco.Web;
namespace PerplexUmbraco.Forms.Code
{
@@ -64,6 +66,8 @@ void FormStorage_Created(object sender, FormEventArgs e)
folder.Forms.Add(form.Id.ToString());
PerplexFolder.SaveAll();
+
+ ClearFormsCache(folderId.ToString());
}
void FormStorage_Deleted(object sender, FormEventArgs e)
@@ -75,7 +79,23 @@ void FormStorage_Deleted(object sender, FormEventArgs e)
{
folder.Forms.Remove(form.Id.ToString());
PerplexFolder.SaveAll();
+
+ ClearFormsCache(folder.Id);
+ }
+ }
+
+ void ClearFormsCache(string folderId)
+ {
+ var cacheConfig = PerplexUmbracoFormsConfig.Get.PerplexCacheConfig;
+
+ if (cacheConfig.EnableCache)
+ {
+ var cacheKey = $"PerplexFormTreeController_GetTreeNodes_id:{folderId}";
+ var rtCache = ApplicationContext.Current.ApplicationCache.RuntimeCache;
+
+ if (rtCache.GetCacheItemsByKeySearch(cacheKey).Any())
+ rtCache.ClearCacheByKeySearch(cacheKey);
}
}
}
-}
\ No newline at end of file
+}
diff --git a/Perplex.Umbraco.Forms/Controllers/PerplexFormTreeController.cs b/Perplex.Umbraco.Forms/Controllers/PerplexFormTreeController.cs
index 7ee2956..23e5149 100644
--- a/Perplex.Umbraco.Forms/Controllers/PerplexFormTreeController.cs
+++ b/Perplex.Umbraco.Forms/Controllers/PerplexFormTreeController.cs
@@ -1,23 +1,18 @@
-using Newtonsoft.Json;
-using PerplexUmbraco.Forms.Code;
-using System;
-using System.Collections.Generic;
-using System.IO;
+using System;
using System.Linq;
using System.Net.Http.Formatting;
-using System.Text;
-using System.Threading.Tasks;
using System.Web;
-using System.Web.Hosting;
-using System.Web.Http;
-using Umbraco.Forms.Data;
+
+using PerplexUmbraco.Forms.Code;
+using PerplexUmbraco.Forms.Code.Configuration;
+
+using umbraco;
+using umbraco.BusinessLogic.Actions;
using Umbraco.Forms.Web.Trees;
+using Umbraco.Web;
using Umbraco.Web.Models.Trees;
using Umbraco.Web.Mvc;
using Umbraco.Web.Trees;
-using Umbraco.Web;
-using umbraco.BusinessLogic.Actions;
-using umbraco;
namespace PerplexUmbraco.Forms.Controllers
{
@@ -41,92 +36,126 @@ public class PerplexFormTreeController : FormTreeController
{
// We load our custom menu actions from our own folder
private const string VIEWS_ROOT = "/App_Plugins/PerplexUmbracoForms/views/";
+ private readonly PerplexCacheConfig _cacheConfig;
- public PerplexFormTreeController() { }
+ public PerplexFormTreeController()
+ {
+ _cacheConfig = PerplexUmbracoFormsConfig.Get.PerplexCacheConfig;
+ }
- protected override Umbraco.Web.Models.Trees.TreeNodeCollection GetTreeNodes(string id, System.Net.Http.Formatting.FormDataCollection queryStrings)
+ protected override TreeNodeCollection GetTreeNodes(string id, FormDataCollection queryStrings)
{
+ var cacheKey = $"PerplexFormTreeController_GetTreeNodes_id:{queryStrings["id"]}";
+ var rtCache = ApplicationContext.ApplicationCache.RuntimeCache;
+
// If this is a form, use Umbraco's default behavior
var folder = PerplexFolder.Get(id);
if (folder == null)
{
- return base.GetTreeNodes(id, queryStrings);
- }
+ var treeNodeCollection = _cacheConfig.EnableCache ? (TreeNodeCollection)rtCache.GetCacheItem(cacheKey) : (TreeNodeCollection)null;
- // This is a folder
+ if (treeNodeCollection == null)
+ {
+ treeNodeCollection = base.GetTreeNodes(id, queryStrings);
- // We require all forms, and apply filtering based on folders later
- var baseTreeNodes = base.GetTreeNodes("-1", queryStrings);
+ if (_cacheConfig.EnableCache)
+ {
+ if (rtCache.GetCacheItemsByKeySearch(cacheKey).Any())
+ rtCache.ClearCacheByKeySearch(cacheKey);
- // Sanity check; make sure there are no orphan forms around
- // (forms not contained within any folder). If so, move them to the root folder
- var orphans = baseTreeNodes.Where(n => PerplexFolder.Get(f => f.Forms.Any(formId => formId == n.Id.ToString())) == null).ToList();
- if(orphans.Count > 0)
- {
- foreach (var orphan in orphans)
- {
- PerplexFolder.GetRootFolder().Forms.Add(orphan.Id.ToString());
+ rtCache.InsertCacheItem(cacheKey, () => treeNodeCollection, new TimeSpan(0, _cacheConfig.CacheDurationInMinutes, 0), true);
+ }
}
- PerplexFolder.SaveAll();
+ return treeNodeCollection;
}
- // Hide all Forms that are not contained within this folder
- // If this folder itself is disabled (due to the user not having access),
- // we also hide all its forms
- baseTreeNodes.RemoveAll(n =>
- !folder.Forms.Contains(n.Id.ToString()) ||
- (folder.Disabled && folder.Forms.Contains(n.Id.ToString()))
- );
+ // This is a folder
+ var baseTreeNodes = _cacheConfig.EnableCache ? (TreeNodeCollection)rtCache.GetCacheItem(cacheKey) : (TreeNodeCollection)null;
- // Sort the forms of this folder in the order as defined by the folder
- baseTreeNodes.Sort((x, y) =>
+ if (baseTreeNodes == null)
{
- int idxX, idxY;
+ // We require all forms, and apply filtering based on folders later
+ baseTreeNodes = base.GetTreeNodes("-1", queryStrings);
- idxX = folder.Forms.IndexOf(x.Id.ToString());
- idxY = folder.Forms.IndexOf(y.Id.ToString());
+ // Sanity check; make sure there are no orphan forms around
+ // (forms not contained within any folder). If so, move them to the root folder
+ var orphans = baseTreeNodes.Where(n => PerplexFolder.Get(f => f.Forms.Any(formId => formId == n.Id.ToString())) == null).ToList();
+ if (orphans.Count > 0)
+ {
+ foreach (var orphan in orphans)
+ {
+ PerplexFolder.GetRootFolder().Forms.Add(orphan.Id.ToString());
+ }
- return idxX.CompareTo(idxY);
- });
+ PerplexFolder.SaveAll();
+ }
- // Add any subfolders of this node
- // We loop through the list in reverse as we add every folder at the start of the list (before forms)
- foreach (var subFolder in folder.Folders.Reverse())
- {
- // If this subfolder is disabled, and it is not on a path towards
- // a folder that is NOT disabled, it should not be listed at all.
- // When multiple start nodes are defined, it is possible for a disabled
- // folder to be displayed in the tree, when one of its descendant folders is enabled.
- if (subFolder.Disabled)
+ // Hide all Forms that are not contained within this folder
+ // If this folder itself is disabled (due to the user not having access),
+ // we also hide all its forms
+ baseTreeNodes.RemoveAll(n =>
+ !folder.Forms.Contains(n.Id.ToString()) ||
+ (folder.Disabled && folder.Forms.Contains(n.Id.ToString()))
+ );
+
+ // Sort the forms of this folder in the order as defined by the folder
+ baseTreeNodes.Sort((x, y) =>
+ {
+ int idxX, idxY;
+
+ idxX = folder.Forms.IndexOf(x.Id.ToString());
+ idxY = folder.Forms.IndexOf(y.Id.ToString());
+
+ return idxX.CompareTo(idxY);
+ });
+
+ // Add any subfolders of this node
+ // We loop through the list in reverse as we add every folder at the start of the list (before forms)
+ foreach (var subFolder in folder.Folders.Reverse())
{
- var startFolders = PerplexFolder.GetStartFoldersForCurrentUser();
+ // If this subfolder is disabled, and it is not on a path towards
+ // a folder that is NOT disabled, it should not be listed at all.
+ // When multiple start nodes are defined, it is possible for a disabled
+ // folder to be displayed in the tree, when one of its descendant folders is enabled.
+ if (subFolder.Disabled)
+ {
+ var startFolders = PerplexFolder.GetStartFoldersForCurrentUser();
+
+ bool isOnPathTowardsStartFolder = startFolders.Any(sf => sf.Path.Any(fid => fid == subFolder.Id));
+ if (!isOnPathTowardsStartFolder)
+ {
+ continue;
+ }
+ }
- bool isOnPathTowardsStartFolder = startFolders.Any(sf => sf.Path.Any(fid => fid == subFolder.Id));
- if (!isOnPathTowardsStartFolder)
+ var treeNode = CreateTreeNode(subFolder.Id, id, queryStrings, subFolder.Name);
+
+ // Clicking this folder will show the folder overview
+ // By default all nodes go to /forms/form/edit/, but this
+ // is only valid for forms. We direct to our custom folder view
+ treeNode.RoutePath = "forms/perplexForms/folder/" + treeNode.Id;
+ if (subFolder.Disabled)
{
- continue;
+ treeNode.CssClasses.Add("disabled");
}
- }
- var treeNode = CreateTreeNode(subFolder.Id, id, queryStrings, subFolder.Name);
+ // Folder has children if it has either forms or folders.
+ // If it is disabled, this is only true when it has subfolders
+ // since we do not show its forms.
+ treeNode.HasChildren = (subFolder.Disabled && subFolder.Folders.Any()) || (!subFolder.Disabled && (subFolder.Forms.Any() || subFolder.Folders.Any()));
- // Clicking this folder will show the folder overview
- // By default all nodes go to /forms/form/edit/, but this
- // is only valid for forms. We direct to our custom folder view
- treeNode.RoutePath = "forms/perplexForms/folder/" + treeNode.Id;
- if (subFolder.Disabled)
- {
- treeNode.CssClasses.Add("disabled");
+ // Folders are added at the top of the list, before forms
+ baseTreeNodes.Insert(0, treeNode);
}
- // Folder has children if it has either forms or folders.
- // If it is disabled, this is only true when it has subfolders
- // since we do not show its forms.
- treeNode.HasChildren = (subFolder.Disabled && subFolder.Folders.Any()) || (!subFolder.Disabled && (subFolder.Forms.Any() || subFolder.Folders.Any()));
+ if (_cacheConfig.EnableCache)
+ {
+ if (rtCache.GetCacheItemsByKeySearch(cacheKey).Any())
+ rtCache.ClearCacheByKeySearch(cacheKey);
- // Folders are added at the top of the list, before forms
- baseTreeNodes.Insert(0, treeNode);
+ rtCache.InsertCacheItem(cacheKey, () => baseTreeNodes, new TimeSpan(0, _cacheConfig.CacheDurationInMinutes, 0), true);
+ }
}
return baseTreeNodes;
@@ -139,7 +168,7 @@ protected override TreeNode CreateRootNode(FormDataCollection queryStrings)
// If none are set, all folders are allowed so we just use default behavior
// Likewise if the common ancestors of all allowed folders is the root.
- PerplexFolder commonAncestor = PerplexFolder.GetCommonAncestor(startFolders);
+ PerplexFolder commonAncestor = PerplexFolder.GetCommonAncestor(startFolders);
if (!startFolders.Any() || commonAncestor == PerplexFolder.GetRootFolder())
{
@@ -157,11 +186,11 @@ protected override TreeNode CreateRootNode(FormDataCollection queryStrings)
// if this is the common ancestor of this user's start nodes but not
// a start node itself. In that case it should also show as disabled in
// the UI, and we hide its URL.
- rootNode.RoutePath = "forms/perplexForms/folder/" + commonAncestor.Id;
- if(commonAncestor.Disabled)
+ rootNode.RoutePath = "forms/perplexForms/folder/" + commonAncestor.Id;
+ if (commonAncestor.Disabled)
{
rootNode.CssClasses.Add("disabled");
- }
+ }
// Folder has children if it has either forms or folders
rootNode.HasChildren = commonAncestor.Forms.Any() || commonAncestor.Folders.Any();
@@ -197,10 +226,10 @@ protected override MenuItemCollection GetMenuForNode(string id, FormDataCollecti
{
menu.Items.RemoveAll(m => m.Alias != ActionRefresh.Instance.Alias);
return menu;
- }
+ }
// Create Form (default Umbraco view, hence alias)
- AddMenuItem(menu, "Create Form", alias: "create", icon: "icon icon-add");
+ AddMenuItem(menu, "Create Form", alias: "create", icon: "icon icon-add");
// Create Folder
AddMenuItem(menu, "Create Folder", view: "createFolder", icon: "icon icon-folder");
@@ -239,7 +268,7 @@ protected override MenuItemCollection GetMenuForNode(string id, FormDataCollecti
var root = PerplexFolder.GetRootFolder();
// If the root folder is disabled, remove all menu actions except Reload
- if(root.Disabled)
+ if (root.Disabled)
{
menu.Items.RemoveAll(m => m.Alias != ActionRefresh.Instance.Alias);
return menu;
diff --git a/Perplex.Umbraco.Forms/Perplex.Umbraco.Forms.csproj b/Perplex.Umbraco.Forms/Perplex.Umbraco.Forms.csproj
index 23d0741..1409be6 100644
--- a/Perplex.Umbraco.Forms/Perplex.Umbraco.Forms.csproj
+++ b/Perplex.Umbraco.Forms/Perplex.Umbraco.Forms.csproj
@@ -230,6 +230,7 @@
+