Kentico CMS 7.0 Developer's Guide

Resolving macros using the API

Resolving macros using the API

Previous topic Next topic Mail us feedback on this topic!  

Resolving macros using the API

Previous topic Next topic JavaScript is required for the print function Mail us feedback on this topic!  

If you need to resolve text containing macro expressions in your custom code, you can do so by using the following code:

 

[C#]

 

string CMS.CMSHelper.CMSContext.CurrentResolver.ResolveMacros(string inputText)

 

As you can see, macros are processed by calling the ResolveMacros static method of an appropriate resolver object, typically of the CMS.CMSHelper.ContextResolver class.

 

If you wish to add custom functionality to the resolving process, you can create a new resolver, load additonal data into it and then use it to resolve the macro expression text. This is shown in the following example:

 

[C#]

 

using CMS.SiteProvider;

using CMS.CMSHelper;

 

private void CustomResolverExample()

{

  string resolvedText = "";

 

  // Create child resolver of ContextResolver

  ContextResolver resolver = CMSContext.CurrentResolver.CreateContextChild();

 

  // Fill the resolver with custom data

   resolver.SetNamedSourceData("MyUser", UserInfoProvider.GetUserInfo("administrator"));

   resolver.SourceParameters = new object[,] { { "MySimpleValue", "RESOLVED Simple value!" }, { "MySecondSimpleValue", "RESOLVED Second simple value!" } };

 

  // Use the resolver to resolve macros in text

   resolvedText = resolver.ResolveMacros("The name of my user is (in upper case): {% MyUser.UserName.ToUpper() %}. First eight characters of the first simple value: {% MySimpleValue.Substring(0, 8) %}");

}

 

There are several ways to register new items into macro resolvers. The SetNameSourceData method adds a single new macro, with the first parameter specifying the name of the macro and the second one providing the object that will be returned when the macro is resolved. The SourceParameters property may be used to add multiple pairs of this type simultaneously through a two dimensional array of objects.

 

Alternatively, you can define the value of a macro using a callback:

 

[C#]

 

using CMS.CMSHelper;
using CMS.GlobalHelper;

 
private object MyPropertyEvaluator(MacroResolver resolver)
{
  return "Macro return value";
}

 
private void CustomResolverExample()
{
  string resolvedText = "";

 
  ContextResolver resolver = CMSContext.CurrentResolver.CreateContextChild();

 
  // Fill the resolver with custom data
   resolver.SetNamedSourceDataCallback("MyProperty", MyPropertyEvaluator);

 
  // Use the resolver to resolve macros in text
   resolvedText = resolver.ResolveMacros("Example: {% MyProperty %}";
}

 

This approach allows you to implement a separate method that will return the macro's value instead of having to specify an object directly. The example above is only meant as a demonstration of the basic principles. The method can be as complex as required.

 

Please note that the callback is executed for every occurrence of the custom macro in an expression. If the evaluator method contains any computationally intensive logic, it is recommended to optimize performance by implementing a caching mechanism for the result.

 

 

InfoBox_Tip

 

Resolving localization macros

 

If you only need to resolve a localization macro, you may use the following static method instead:

 

string CMS.GlobalHelper.ResHelper.LocalizeString(string inputText)

 

 

Adding custom macros to the global resolver

 

The techniques described above may also be used to define additional macro properties for existing resolvers. Macro resolvers are organized in a hierarchy that allows child resolvers to inherit all macro options defined for their parent. You can create a child resolver by calling the CreateContextChild() method of an existing resolver, as shown in the examples above.

 

The following step-by-step example demonstrates how custom macros can be added to the global resolver, i.e. the parent of all other resolvers. By adding data items into the global resolver, you can create new macros that will be available in all parts of the system.

 

1. Open your web project in Visual Studio, expand the App_Code folder (or Old_App_Code if you installed the project as a web application) and add a new class called GlobalResolverExtender.cs.

 

2. Edit the class and add the following references:

 

[C#]

 

using CMS.SettingsProvider;
using CMS.GlobalHelper;
using CMS.CMSHelper;
using CMS.SiteProvider;

 

3. Next, delete the default class declaration and its content. Instead extend the CMSModuleLoader partial class and define an attribute for it as shown below:

 
[C#]

 

[GlobalResolverExtender]
public partial class CMSModuleLoader
{
  /// <summary>
  /// Module registration
  /// </summary>
  private class GlobalResolverExtenderAttribute : CMSLoaderAttribute
   {
       ...
   }
}

 

4. Then enter the following code into the GlobalResolverExtenderAttribute class:

 

[C#]

 

/// <summary>
/// Called automatically when the application starts
/// </summary>
public override void Init()
{
  ContextResolver.GlobalResolver.SetNamedSourceDataCallback("MyAge", MyAgeEvaluator);          
}

 
private object MyAgeEvaluator(MacroResolver resolver)
{          
   System.DateTime dateOfBirth = CMSContext.CurrentUser.UserSettings.UserDateOfBirth;
   System.DateTime now = DateTime.Now;

 
  int age = now.Year - dateOfBirth.Year;
  if (dateOfBirth > now.AddYears(-age))
   {
       age--;
   }
  return age;
}

 

The code in the override of the Init() method (executed automatically when the application starts) is used to add the MyAge macro property into the global resolver. The value of this macro is retrieved via callback by the private MyAgeEvaluator method.

 

5. Save the file and Build the project if it is installed as a web application. You can now try entering the {% MyAge %} expression in any part of the system where macros are supported. It will automatically be offered in the autocompletion box, as well as the object tree provided by the macro selection control.

 

devguide_clip1617

 

As you can see, the custom property is displayed in the high priority section at the top of the list. By default, all items registered through the SetNameSourceData or SetNameSourceDataCallback methods are prioritized. If you wish to add a property with normal priority, you can use an overload of the methods that includes the isPrioritized boolean parameter and set it as false. For example:

 

[C#]

 

ContextResolver.GlobalResolver.SetNamedSourceDataCallback("MyAge", MyAgeEvaluator, false);