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
Pingback: Sitecore Proxy Filter | Paul's Sitecore Musings