-
Notifications
You must be signed in to change notification settings - Fork 3
/
IntranetContext.cs
343 lines (278 loc) · 14.3 KB
/
IntranetContext.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Runtime.Caching;
using Chimote.Tridion.Templating.Intranet.Common;
using Chimote.Tridion.Templating.Intranet.Configurations;
using Tridion.ContentManager;
using Tridion.ContentManager.CommunicationManagement;
using Tridion.ContentManager.ContentManagement;
using Tridion.ContentManager.ContentManagement.Fields;
using Tridion.ContentManager.Templating;
using XView;
namespace Chimote.Tridion.Templating.Intranet.Controllers
{
/// <summary>
/// Represents the Context Object for the Tridion blueprint in which the Controller
/// is handling Compound Templates.
///
/// Every implementation/blueprint should provide a Context class deriving from the
/// XView's TridionContext class. This Context class defines properties and methods
/// expressing the rules/behaviours and configurations that are applicable to the
/// blueprint this Context class is created for.
///
/// An extended TridionContext class is not mandatory. Instead, you can use the TridionContext
/// provided by XView as-is if that's sufficient for your need. This can be the case
/// if you're dealing with a very small Tridion implementation.
/// </summary>
public class IntranetContext : TridionContext
{
private PublicationConfiguration configuration;
private EnvironmentConfiguration environment;
private IDictionary<string, string> labels;
private TemplatingLogger logger;
public EnvironmentConfiguration Environment
{
get
{
if (this.environment == null)
{
const string environmentConfigurationCacheKey = "environment-configuration";
if (this.Cache.Contains(environmentConfigurationCacheKey))
{
this.environment = (EnvironmentConfiguration)this.Cache.Get(environmentConfigurationCacheKey);
}
else
{
var systemKeywordWebDavUrl = this.Publication.WebDavUrl + "/System/Configuration.tkw";
var systemKeyword = this.Engine.GetObject<Keyword>(systemKeywordWebDavUrl);
if (systemKeyword == null)
{
var errorMessage =
string.Format(
"Could not find the Configuration keyword {0} to determine the environment",
systemKeywordWebDavUrl);
throw new Exception(errorMessage);
}
var environmentValue = systemKeyword.GetMetadataField<TextField>("environment").Value;
this.environment = new EnvironmentConfiguration(environmentValue);
this.Cache.Set(environmentConfigurationCacheKey, this.environment,
new CacheItemPolicy { AbsoluteExpiration = DateTimeOffset.Now.AddHours(24.0) });
}
}
return this.environment;
}
}
private TemplatingLogger Logger
{
get { return this.logger ?? (this.logger = TemplatingLogger.GetLogger(this.GetType())); }
}
private IDictionary<string, string> Labels
{
get { return this.labels ?? (this.labels = this.GetContextLabels()); }
}
public PublicationConfiguration Configuration
{
get
{
// The code below demonstrates the usage of the ContextScope.
// PublicationConfiguration can be cached in the ContextScope so it can
// be used by multiple templates rendered in the same publish transaction
// within a publication.
// If your situation allows you to you can decide to cache the PublicationConfiguration
// object in the cache using this.Cache for significant performance gain.
// Default cache life time is 15 minutes, but you can change this for each cache item.
if (this.configuration != null)
{
return this.configuration;
}
const string publicationConfigurationKey = "publicationconfiguration";
if (this.ContextScope.ContainsKey(publicationConfigurationKey))
{
this.configuration = (PublicationConfiguration)this.ContextScope[publicationConfigurationKey];
}
else
{
this.configuration =
new PublicationConfiguration(
this.Publication.GetMetadataField<ComponentLinkField>("publication_configuration").Value);
this.ContextScope.Add(publicationConfigurationKey, this.configuration);
}
return this.configuration;
}
}
public bool IsPageContext
{
get { return this.Page != null; }
}
public bool IsDynamicTemplate(Template template)
{
if (template is PageTemplate)
{
// Define implementation specific logic to determine whether a Page is
// dynamic or not.
// A PT in Tridion is static by nature. However, in some implementations some
// specific PTs are designated to publish dynamic pages containing dynamic
// component presentations. In such case the definition of a "dynamic" PT
// can vary. Therefore apply appropriate logic below to determine a dynamic PT.
// The code sample below says a PT that has the extension "somedynamicextension"
// is a dynamic PT.
return ((PageTemplate)template).FileExtension.Equals("somedynamicextension");
}
return ((ComponentTemplate)template).IsRepositoryPublishable;
}
/// <summary>
/// Shortcut to Engine.PublishingContext.RenderedItem.AddBinary(Component multimediaComponent).Url;
/// </summary>
/// <param name="multimediaComponent">Multimedia component.</param>
/// <returns>String represents the URL.</returns>
public string PublishBinaryAndReturnUrl(Component multimediaComponent)
{
Guard.Requires(multimediaComponent != null);
Guard.Requires(multimediaComponent.ComponentType == ComponentType.Multimedia);
return this.Engine.PublishingContext.RenderedItem.AddBinary(multimediaComponent).Url;
}
public string TranslateLabel(string label)
{
Guard.Requires(!string.IsNullOrEmpty(label));
if (this.Labels.ContainsKey(label))
{
return this.Labels[label];
}
throw new Exception(string.Format("Label \"{0}\" does not exist", label));
}
/// <summary>
/// Creates and returns a ComponentImage object for the given multimediaComponent.
/// </summary>
/// <param name="multimediaComponent">Multimedia component containing an image.</param>
/// <param name="forceDownloadExternal">Force an external image to be downloaded and published.</param>
/// <returns>ComponentImage object.</returns>
public ComponentImage CreateImage(Component multimediaComponent, bool forceDownloadExternal = false)
{
Guard.ArgumentIsNotNull(multimediaComponent, "multimediaComponent");
return new ComponentImage(multimediaComponent, this.Engine.PublishingContext.RenderedItem, forceDownloadExternal);
}
public MultimediaItem CreateMultimediaItem(Component multimediaItem, bool forceDownloadExternal = false)
{
Guard.ArgumentIsNotNull(multimediaItem, "multimediaItem");
return new MultimediaItem(multimediaItem, this.Engine.PublishingContext.RenderedItem, forceDownloadExternal);
}
public MultimediaItem CreateCachedMultimediaItem(Component multimediaComponent)
{
Guard.ArgumentIsNotNull(multimediaComponent, "multimediaComponent");
var cacheKey = this.GenerateCacheKey(multimediaComponent, keyPrefix: "multimedia", publicationTargetRelevant: true);
if (this.Cache.Contains(cacheKey))
{
this.Logger.Debug(string.Format("Cache: get multimedia item with key {0} from cache.", cacheKey));
return (MultimediaItem)this.Cache.Get(cacheKey);
}
var multimediaItem = this.CreateMultimediaItem(multimediaComponent);
this.Logger.Debug(string.Format("Cache: set multimedia item with key {0} into cache.", cacheKey));
this.Cache.Set(cacheKey, multimediaItem);
return multimediaItem;
}
public T GetContextIdentifiableObject<T>(string uri) where T : IdentifiableObject
{
return this.GetContextIdentifiableObject<T>(new TcmUri(uri));
}
public T GetContextIdentifiableObject<T>(IdentifiableObject identifiableObject) where T : IdentifiableObject
{
return this.GetContextIdentifiableObject<T>(identifiableObject.Id);
}
public T GetContextIdentifiableObject<T>(TcmUri tcmUri) where T : IdentifiableObject
{
var contextTcmUri = TemplateUtilities.CreateTcmUriForPublication(this.Publication.Id.ItemId, tcmUri);
return this.Engine.GetObject<T>(contextTcmUri);
}
/// <summary>
/// This custom PageScope makes PageScope data sharing possible among PT and all
/// DCPs on the same Page in a dynamic publishing scenario.
///
/// If your Tridion implementation does not deal with DCPs or does not have the need
/// for sharing data among PT and dynamic templates residing on the same Page, then omit
/// this method. The default PageScope provided by XView should be sufficient in that case.
/// </summary>
/// <returns>IDictionary{string, object} representing the PageScope.</returns>
protected override IDictionary<string, object> GetCustomPageScope()
{
const string pageScopeKeyPrefix = "custompagescope|{5F9B1A11-C541-42E1-89D2-AB8CE91AAFA7}|";
var pageScopeKey = this.Page != null
? string.Format("{0}|{1}", pageScopeKeyPrefix, this.Page.Id.GetVersionlessUri())
: string.Format("{0}|{1}|{2}", pageScopeKeyPrefix, this.Component.Id, this.Template.Id);
IDictionary<string, object> pageScope;
if (this.ContextScope.ContainsKey(pageScopeKey))
{
pageScope = (IDictionary<string, object>)this.ContextScope[pageScopeKey];
}
else
{
pageScope = new Dictionary<string, object>();
this.ContextScope.Add(pageScopeKey, pageScope);
}
if (!(this.Template is PageTemplate) || this.Page == null)
{
return pageScope;
}
foreach (var presentation in this.Page.ComponentPresentations)
{
if (!this.IsDynamicTemplate(presentation.ComponentTemplate))
{
continue;
}
var presentationPageScopeKey = string.Format("{0}|{1}|{2}", pageScopeKeyPrefix, presentation.Component.Id,
presentation.ComponentTemplate.Id);
this.ContextScope.Add(presentationPageScopeKey, pageScope);
}
return pageScope;
}
/// <summary>
/// Example of how to generate a cache key for a cache item representing resolved
/// data that is associated with a VersionedItem. (Example of VersionedItems are: Page,
/// Component, ComponentTemplate, PageTemplate, etc.).
/// </summary>
/// <param name="versionedItem">VersionItem object.</param>
/// <param name="keyPrefix">Optional cache key prefix.</param>
/// <param name="publicationTargetRelevant">Should cache key be associated with a PublicationTarget?</param>
/// <returns>String representing the cache key.</returns>
private string GenerateCacheKey(VersionedItem versionedItem, string keyPrefix = null,
bool publicationTargetRelevant = false)
{
keyPrefix = keyPrefix ?? "versioneditem";
var objectId = versionedItem.Id.GetVersionlessUri().ToString();
var versionId = versionedItem.Version.ToString(CultureInfo.InvariantCulture);
if (!publicationTargetRelevant)
{
return string.Format("{0}|{1}|{2}", keyPrefix, objectId, versionId);
}
var targetId = this.IsPublishing && this.Engine.PublishingContext.PublicationTarget != null
? this.Engine.PublishingContext.PublicationTarget.Id.ToString()
: "preview";
return string.Format("{0}|{1}|{2}|{3}", keyPrefix, objectId, versionId, targetId);
}
private IDictionary<string, string> GetContextLabels()
{
var cacheKey = string.Format("labels|{0}", this.Configuration.LanguageCode);
if (this.Cache.Contains(cacheKey))
{
return (IDictionary<string, string>)this.Cache.Get(cacheKey);
}
var labelsFolderWebDavUrl = this.Publication.WebDavUrl + "/folder/containing/label/components";
var labelsFolder = (Folder)this.Engine.GetObject(labelsFolderWebDavUrl);
var filter = new OrganizationalItemItemsFilter(this.Engine.GetSession());
filter.ItemTypes = new List<ItemType> { ItemType.Component };
filter.Recursive = false;
var labelComponents = labelsFolder.GetItems(filter).OfType<Component>();
var contextLabels = new Dictionary<string, string>();
foreach (var labelComponent in labelComponents)
{
if (labelComponent.Schema.Title == "Label")
{
contextLabels.Add(labelComponent.Title, labelComponent.GetText("value"));
}
}
this.Cache.Set(cacheKey, contextLabels);
return contextLabels;
}
}
}