Sitecore Proxy Filter POC Implementation

Here is my proof-of-concept code for the Sitecore Proxy Filter. We never ended up implementing it.  Disclaimer: I pull this code from an old SVN branch and haven’t verified that I have all the parts or that it works still. You have been warned :)

1. Extend the “SqlProxyDataProvider” class


using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Text;

using Sitecore.Configuration;
using Sitecore.Data;
using Sitecore.Data.DataProviders.Sql;
using Sitecore.Data.Items;
using Sitecore.Data.Proxies;
using Sitecore.Data.SqlServer;

using BaseIDs = Drexel.FieldIDs.Base;
using Drexel.Extensions;

namespace Drexel.Data.SqlServer
{
public class SqlServerProxyDataProvider : SqlProxyDataProvider
{
private string _connectionString = string.Empty;
private Dictionary<string, bool> _validIdLookup = new Dictionary<string, bool>();

private Database _db;
private Database ContextDb
{
get
{
if (_db == null)
{
try
{
ConnectionStringSettings css = ConfigurationManager.ConnectionStrings
.Cast<ConnectionStringSettings>()
.SingleOrDefault(x => x.ConnectionString == _connectionString);
_db = Factory.GetDatabase(css.Name);
}
catch (Exception ex)
{
Drexel.Logging.Log.Error("Failed to resolve connection string", ex);
_db = Factory.GetDatabase("master"); // Default to master DB
}
}
return _db;
}
}
private SqlServerDataApi API { get; set; }
public SqlServerProxyDataProvider(string connectionString)
: this(new SqlServerDataApi(connectionString), true)
{
_connectionString = connectionString;
}
private SqlServerProxyDataProvider(SqlServerDataApi api, bool foo)
: base(api)
{
this.API = api;
}
public override ID GetVirtualId(ID itemId, ID proxyId, bool generateIfNotFound)
{
ID proxySourceItemID;
string vcProxyFilterQuery;
bool valid = true;

if (!_validIdLookup.TryGetValue(itemId.ToString(), out valid))
{
valid = true; // if TryGetValue fails, it sets valid=false...
GetProxyFilterInfo(proxyId, out proxySourceItemID, out vcProxyFilterQuery);

if (!string.IsNullOrEmpty(vcProxyFilterQuery) && !proxySourceItemID.IsNull)
{
using (new ProxyDisabler())
{
string[] validIds = GetValidProxyIds(proxyId, proxySourceItemID, vcProxyFilterQuery);
valid = validIds.Contains(itemId.ToString());
}
}

_validIdLookup.Add(itemId.ToString(), valid);
}

if (valid)
return base.GetVirtualId(itemId, proxyId, generateIfNotFound);
else
{
// See if this proxied item was already shadowed... if so, then remove it
ID shadowId = base.GetVirtualId(itemId, proxyId, false);
if (shadowId != (ID)null)
this.RemoveShadow(shadowId);
return ID.Null;
}

}

private string[] GetValidProxyIds(ID proxyId, ID proxySourceItemID, string vcProxyFilterQuery)
{
System.Web.Caching.Cache cache = System.Web.HttpContext.Current.Cache;
Item proxyItem = ContextDb.GetItem(proxyId);
string vcCacheKey = "ValidProxyIdsFor-" + proxySourceItemID.ToString() + "-" + GetItemTimestamp(proxyItem);

string[] list = (string[])cache[vcCacheKey];
if (list == null)
{
Item i = ContextDb.GetItem(proxySourceItemID);
list = i.Axes.SelectItems(vcProxyFilterQuery).Select<Item, string>(x => x.ID.ToString()).ToArray();
cache.Insert(vcCacheKey, list, null, DateTime.Now.AddMinutes(10.0), System.Web.Caching.Cache.NoSlidingExpiration);
}
return list;
}
private string GetItemTimestamp(Item i)
{
ID[] fields = new ID[] { Sitecore.FieldIDs.Updated, Sitecore.FieldIDs.Created };
return Sitecore.DateUtil.IsoDateToDateTime(i.FieldCoalesce(fields).Value, DateTime.MinValue).ToString("yyyyMMddHHmmss");
}
private void GetProxyFilterInfo(ID proxyId, out ID ProxySourceItemID, out string vcProxyFilterQuery)
{
ProxySourceItemID = ID.Null;
vcProxyFilterQuery = string.Empty;
string sql = @"select f.{0}FieldID{1}, f.{0}Value{1} from {0}Items{1} i inner join {0}Fields{1} f on f.{0}ItemId{1} = i.{0}ID{1} " +
@"where i.{0}ID{1} = {2}proxyId{3} and f.{0}FieldID{1} in ({2}queryFieldId{3}, {2}proxySourceItemFieldId{3})";

object[] parameters = new object[] { "proxyId", proxyId,
"queryFieldId", BaseIDs.ProxyFilter.Query,
"proxySourceItemFieldId", Sitecore.FieldIDs.ProxySourceItem };

using (DataProviderReader reader = this.API.CreateReader(sql, parameters))
{
while (reader.Read())
{
ID id = this.API.GetId(0, reader);
if (id == Sitecore.FieldIDs.ProxySourceItem)
ProxySourceItemID = ID.Parse(this.API.GetString(1, reader));
else if (id == BaseIDs.ProxyFilter.Query)
vcProxyFilterQuery = this.API.GetString(1, reader);
}
}
}

private void RemoveShadow(ID shadowId)
{
string sql = " DELETE FROM {0}Shadows{1} WHERE {0}ShadowID{1} = {2}shadowId{3}";
this.API.Execute(sql, new object[] { "shadowId", shadowId });
}

}
}

2. Extend “ItemProvider” class

using System;
using System.Collections.Generic;
using Sitecore;
using Sitecore.Collections;
using Sitecore.Data;
using Sitecore.Data.Items;
using Sitecore.Data.Proxies;
using Sitecore.Diagnostics;
using Sitecore.Globalization;
using Sitecore.Layouts;
using Sitecore.SecurityModel;
using Sitecore.StringExtensions;

namespace Drexel.Data.Managers
{
    public class ItemProvider : Sitecore.Data.Managers.ItemProvider
    {
        public ItemProvider() : base() { }

        public override ChildList GetChildren(Item item, SecurityCheck securityCheck)
        {
            Assert.ArgumentNotNull(item, "item");
            ItemList children = this.GetChildren(item);
            this.InsertVirtualChildren(children, item);
            children.RemoveAll(x => x == null); // remove nulls
            return new ChildList(item, this.ApplySecurity(children, securityCheck));
        }
    }
}

3. web.config changes..

    <proxyDataProviders>
      <main type="Drexel.Data.$(database).$(database)ProxyDataProvider, Sitecore.Drexel">
        <param connectionStringName="$(1)" />
        <Name>$(1)</Name>
      </main>
      <!--<main type="Sitecore.Data.$(database).$(database)ProxyDataProvider, Sitecore.Kernel">
        <param connectionStringName="$(1)" />
        <Name>$(1)</Name>
      </main>-->
    </proxyDataProviders>
...
 <itemManager defaultProvider="default">
      <providers>
        <clear />
        <add name="default" type="Drexel.Data.Managers.ItemProvider, Sitecore.Drexel" />
        <!--<add name="default" type="Sitecore.Data.Managers.ItemProvider, Sitecore.Kernel" />-->
      </providers>
    </itemManager>

Advertisement

About Paul Martin

I enjoy rock climbing, playing guitar, writing code...
This entry was posted in Proxy Items, Sitecore. Bookmark the permalink.

One Response to Sitecore Proxy Filter POC Implementation

  1. Pingback: Sitecore Proxy Filter | Paul's Sitecore Musings

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Connecting to %s