Is it possible to programmatically determine if the content of a block uses personalization?
I need to know in order to handle caching correctly when the content of a block can be personalized for different visitor groups.
In order to make decision about personalization you will need to get access to ContentAreaItem instance itself.
The most easiest way to get access to ContentAreaItem is to hook into rendering pipeline. You may need to swap out ContentAreaRenderer (see AlloyTech sample site for code snippet) with your own implementation.
Then you can implement BeforeRenderContentAreaItemStartTag:
public class MyCustomContentAreaRenderer : ContentAreaRenderer
{
protected override void BeforeRenderContentAreaItemStartTag(TagBuilder tagBuilder, ContentAreaItem contentAreaItem)
{
var isPersonalizationApplied = contentAreaItem.AllowedRoles.Any();
}
}
Next question of course is how you will deliver this decision down to block type instance, as overridden ContentAreaRenderer method is far enough from the block instance inside content area.
#keithl8041, you can use VisitorGroupHelper to check whether current user matches particular role:
using EPiServer.Personalization.VisitorGroups;
using EPiServer.Security;
protected override void BeforeRenderContentAreaItemStartTag(TagBuilder tagBuilder, ContentAreaItem contentAreaItem)
{
var groupHelper = new VisitorGroupHelper();
var isPersonalizationApplied = contentAreaItem.AllowedRoles.Any();
var isCurrentUserInAnyOfGroups = contentAreaItem.AllowedRoles.Any(r => groupHelper.IsPrincipalInGroup(PrincipalInfo.CurrentPrincipal, r);
}
Related
I'm planning to create some pages which display data from an external SQL Server with Orchard CMS. It looks like I need to write a new module to implement this function. Is there any example or idea to implement this requirement?
Yes, you will need to write a new module, which provides a new content part and a content part driver. That driver will be responsible for fetching the data from the external SQL Server, which you will set to a property on the shape you will be returning from your driver. The shape's view will then display your data.
This tutorial will walk you through writing a custom content part: http://docs.orchardproject.net/en/latest/Documentation/Writing-a-content-part/
When you do, make sure not to create the content part Record type, since you will not be storing and loading data from the Orchard database - you want to load data from an external database. These are the steps you should follow:
Create a new module
Create a content part class
Have your part inherit from ContentPart, not ContentPart<TRecord> since there won't be any "TRecord".
Create a content part driver
On the Display method, return a shape by calling the ContentShape method. Make sure to add the SQL data access logic within the lambda. If you do it outside of that lambda, that data access code will be invoked every time the content item using your content part is invoked. Although that sounds as if that is exactly what you want, there's a subtlety here that involves Placement.info, which you can use to determine when your shape will actually be rendered or not. If the placement logic determines that your shape should not be rendered, then you don't want to access your external data for nothing.
Create a Placement.info file to configure the shape's placement (within the context of the content item being rendered).
Create the Razor view for the shape that you return in step 3.2.
Create a Migrations class that will define your custom content part, and any content types to which you want to add your part to. See http://docs.orchardproject.net/en/latest/Documentation/Understanding-data-access/ for more information on how to create migrations.
PS. Instead of implementing your data access code directly in the driver, I recommend you implement that in a separate class. Because you know, separation of concerns and such. You can then inject that service into your driver. To have your service class be registered with the service container, make sure that you define an interface for it, that itself derives from IDependency.
Some sample pseudo code:
Service code:
public interface IMyExternalDataStore : IDependency {
IList<MyExternalDataRecord> GetMyData();
}
public class MyExternalDataStore : IMyExternalDataStore {
public IList<MyExternalDataRecord> GetMyData() {
// Connect to your SQL Server database, perhaps using EF, load the data and return it. Could of course also be simply a DataSet.
}
}
Content Part:
public class MyExternalDataPart : ContentPart {
// Nothing here, unless you want to include some properties here that influence the data that you want to load. If so, you'll also want to implement the Editor methods in your content part driver, but I'm keeping it simple.
}
Content Part Driver:
public class MyExternalDataPartDriver : ContentPartDriver<MyExternalContentPart> {
private readonly IMyExternalDataStore _dataStore;
public MyExternalDataPartDriver(IMyExternalDataStore dataStore) {
_dataStore = dataStore;
}
protected override DriverResult Display(SlideShowProPart part, string displayType, dynamic shapeHelper) {
return ContentShape("Parts_MyExternalData", () => {
// Notice that we're performing the data access here within the lambda (the so called "shape factory method").
var data = _dataStore.GetMyData();
// Notice that I'm creating a property called "MyData"on the shape (which is a dynamic object).
return shapeHelper.Parts_MyExternalData(MyData: data));
}
}
}
Razor view for the Parts_MyExternalData shape:
Filename: Parts.MyExternalData.cshtml
#{
var records = (IList<MyExternalDataRecord>)Model.MyData;
}
<ul>
#foreach(var record in records) {
<li>#record.ToString()</li>
}
</ul>
Placement.info:
<Placement>
<Place Parts_MyExternalData="Content:0"/>
</Placement>
Migrations:
public class Migrations : DataMigrationImpl {
public int Create() {
// Define your content part so that you can attach it to any content type from the UI.
ContentDefinitionManager.AlterPartDefinition("MyExternalDataPart", part => part.Attachable());
// Optionally, define a new content type here programmatically or attach it to an existing type.
return 1;
}
}
In page edit mode I want to show a read-only text that is based on a page property value. The text could for example be "A content review reminder email will be sent 2015-10-10", where the date is based on the page published date + six months (a value that will be configurable and therefore can change anytime). So far I've tried to accomplish something like this by adding another property on the page.
I've added the property CurrentReviewReminderDate to an InformationPage class we use. In page edit mode the property name is shown, but it doesn't have a value. How do I do to show the value in page edit mode (preferably as a label)?
[CultureSpecific]
[Display(
Name = "Review reminder date",
Description = "On this date a reminder will be sent to the selected mail to remember to verify page content",
Order = 110)]
[Editable(false)]
public virtual string CurrentReviewReminderDate
{
get
{
var daysUntilFirstLevelReminder =
int.Parse(WebConfigurationManager.AppSettings["PageReviewReminder_DaysUntilFirstLevelReminder"]);
if (CheckPublishedStatus(PagePublishedStatus.Published))
{
return StartPublish.AddDays(daysUntilFirstLevelReminder).ToString();
}
return "";
}
set
{
this.SetPropertyValue(p => p.CurrentReviewReminderDate, value);
}
}
EPiServer internally uses the GetPropertyValue method (i.e. the opposite of SetPropertyValue) when retrieving content for the UI.
This makes sense, otherwise your "made-up" value would be stored as the real value whenever the content is saved. This would make fall-back values etc impossible to implement.
So, this is by-design (and quite wisely so) in EPiServer. :)
However, you can customize how properties work by:
Using custom editors by applying UI hints
Modifying property metadata (for example, to display a generated value as a watermark in a textbox without interfering with the actual value being saved)
I could be misunderstanding what you're trying to do, but off the top of my head it looks like a custom editor could be a viable option for your use case?
Another solution would be to hook into the LoadedPage-event and add the value from there. This might not be the best way performance-wise since you need to do a CreateWritableClone, but depending on the site it might not matter.
[InitializableModule]
[ModuleDependency(typeof(EPiServer.Web.InitializationModule))]
public class EventInitialization : IInitializableModule
{
public void Initialize(InitializationEngine context)
{
ServiceLocator.Current.GetInstance<IContentEvents>().LoadedContent += eventRegistry_LoadedContent;
}
void eventRegistry_LoadedContent(object sender, ContentEventArgs e)
{
var p = e.Content as EventPage;
if (p != null)
{
p = p.CreateWritableClone() as EventPage;
p.EventDate = p.StartPublish.AddDays(10);
e.Content = p;
}
}
}
My goal is to keep session size as small as possible. (Why?.. it's other topic).
What I have is Phase listener declared in faces-config.xml
<lifecycle>
<phase-listener>mypackage.listener.PhaseListener</phase-listener>
</lifecycle>
I want to save all other views, except the last one(maximum two) , in some memcache. Getting the session map:
Map<String, Object> sessionMap = event.getFacesContext().getExternalContext().getSessionMap();
in beforePhase(PhaseEvent event) method is giving me access to all views. So here I could save all views to the memcache and delete them from the session. The question is where in jsf these views that are still loaded in the browser are requested so that I can refill with this view if it's needed. Is it possible at all? Thank you.
To address the core of your question, implement a ViewHandler, within which you can take control of the RESTORE_VIEW and RENDER_RESPONSE phases/processes. You'll save the view during the RENDER_RESPONSE and selectively restore, during the RESTORE_VIEW phase. Your view handler could look something like the following
public class CustomViewHandlerImpl extends ViewHandlerWrapper{
#Inject ViewStore viewStore; //hypothetical storage for the views. Could be anything, like a ConcurrentHashMap
ViewHandler wrapped;
public CustomViewHandlerImpl(ViewHandler toWrap){
this.wrapped = toWrap;
}
public UIViewRoot restoreView(FacesContext context, String viewId) throws IOException{
//this assumes you've previously saved the view, using the viewId
UIViewRoot theView = viewStore.get(viewId);
if(theView == null){
theView = getWrapped().restoreView(context, viewId);
}
return theView;
}
public void renderView(FacesContext context, UIViewRoot viewToRender) throws IOException, FacesException{
viewStore.put(viewToRender.getId(),viewToRender);
getWrapped().renderView(context, viewToRender);
}
}
Simply plug in your custom viewhandler, using
<view-handler>com.you.customs.CustomViewHandlerImpl</view-handler>
Of course, you probably don't want to give this treatment to all your views; you're free to add any conditions to the logic above, to implement conditional view-saving and restoration.
You should also consider other options. It appears that you're conflating issues here. If your true concern is limit the overhead associated with view processing, you should consider
Stateless Views, new with JSF-2.2. The stateless view option allows you to exclude specific pages from the JSF view-saving mechanism, simply by specifying transient="true" on the f:view. Much cleaner than mangling the UIViewRoot by hand. The caveat here is that a stateless view cannot be backed by scopes that depend on state-saving, i.e. #ViewScoped. In a stateless view, the #ViewScoped bean is going to be recreated for every postback. Ajax functionality also suffers in this scenario, because state saving is the backbone of ajax-operations.
Selectively set mark components as transient The transient property is available for all UIComponents, which means, on a per-view basis, you can mark specific components with transient="true", effectively giving you the same benefits as 1) but on a much smaller scope. Without the downside of no ViewScoped
EDIT: For some reason, UIViewRoot#getViewId() is not returning the name of the current view (this might be a bug). Alternatively, you can use
ExternalContext extCtxt = FacesContext.getCurrentInstance().getExternalContext();
String viewName = ((HttpServletRequest)extCtxt.getRequest()).getRequestURI(); //use this id as the key to store your views instead
Both Java and Javascript allow for a different way of executing static code. Java allows you to have static code in the body of a class while JS allows you to execute static code outside class definitions. Examples:
Java:
public class MyClass {
private static Map<String,String> someMap = new HashMap<String,String();
static {
someMap.put("key1","value");
someMap.put("key2","value");
SomeOtherClass.someOtherStaticMethod();
System.out.println(someMap);
}
}
JS (basically any JS code outside a class):
var myint = 5;
callSomeMethod();
$(document).ready(function () {
$("#hiddenelement").hide();
});
However, it seems like Dart supports either of both ways. Declaring global variables and methods is supported, but calling methods and executing code like in JS is not. This can only be done in a main() method. Also, static code inside a class is not allowed either.
I know Dart has other ways to statically fill a Map like my first example, but there is another case that I can think of for which this is required.
Let's consider the following CarRegistry implementation that allows you to map strings of the car model to an instance of the corresponding class. F.e. when you get the car models from JSON data:
class CarRegistry {
static Map<String, Function> _factoryMethods = new HashMap<String, Function>();
static void registerFactory(String key, Car factory()) {
_factoryMethods[key] = factory;
}
static Car createInstance(String key) {
Function factory = _factoryMethods[key];
if(factory != null) {
return factory();
}
throw new Exception("Key not found: $key");
}
}
class TeslaModelS extends Car {
}
class TeslaModelX extends Car {
}
In order to be able to call CarRegistry.createInstance("teslamodelx");, the class must first be registered. In Java this could be done by adding the following line to each Car class: static { CarRegistry.registerFactory("teslamodelx" , () => new TeslaModelX()); }. What you don't want is to hard-code all cars into the registry, because it will lose it's function as a registry, and it increases coupling. You want to be able to add a new car by only adding one new file. In JS you could call the CarRegistry.registerFactory("teslamodelx" , () => new TeslaModelX()); line outside the class construct.
How could a similar thing be done in Dart?
Even if you would allow to edit multiple files to add a new car, it would not be possible if you are writing a library without a main() method. The only option then is to fill the map on the first call of the Registry.createInstance() method, but it's no longer a registry then, just a class containing a hard-coded list of cars.
EDIT: A small addition to the last statement I made here: filling this kind of registry in the createInstance() method is only an option if the registry resided in my own library. If, f.e. I want to register my own classes to a registry provided by a different library that I imported, that's no longer an option.
Why all the fuss about static?
You can create a getter that checks if the initialization was already done (_factoryMethods != null) if not do it and return the map.
As far a I understand it, this is all about at what time this code should be executed.
The approach I showed above is lazy initialization.
I think this is usually the preferred way I guess.
If you want to do initialization when the library is loaded
I don't know another way as calling an init() method of the library from main() and add initialization code this libraries init() method.
Here is a discussion about this topic executing code at library initialization time
I encountered the same issue when trying to drive a similarly themed library.
My initial attempt explored using dart:mirrors to iterate over classes in a library and determine if they were tagged by an annotation like this (using your own code as part of the example):
#car('telsamodelx')
class TelsaModelX extends Car {
}
If so, they got automatically populated into the registry. Performance wasn't great, though, and I wasn't sure if how it was going to scale.
I ended up taking a more cumbersome approach:
// Inside of CarRegistry.dart
class CarRegister {
static bool _registeredAll = false;
static Car create() {
if (!_registeredAll) { _registerAll()); }
/* ... */
}
}
// Inside of the same library, telsa_model_x.dart
class TelsaModelX extends Car {}
// Inside of the same library, global namespace:
// This method registers all "default" vehicles in the vehicle registery.
_registerAll() {
register('telsamodelx', () => new TelsaModelX());
}
// Inside of the same library, global namespace:
register(carName, carFxn) { /* ... */ }
Outside of the library, consumers had to call register(); somewhere to register their vehicle.
It is unnecessary duplication, and unfortunately separates the registration from the class in a way that makes it hard to track, but it's either cumbersome code or a performance hit by using dart:mirrors.
YMMV, but as the number of register-able items grow, I'm starting to look towards the dart:mirrors approach again.
The project I am working on is a mobile .NET CF based application. I have to implement the MVP pattern in it. I am now using OpenNETCF.IoC library and Services in it.
I have to refactor Windows Forms code to SmartParts.
I have a problem in implementing navigation scenario:
// Show Main menu
bodyWorkspace.Show(mainMenuView);
// Show First view based on user choice
bodyWorkspace.Show(firstView);
// In first view are some value(s) entered and these values should be passed to the second view
bodyWorkspace.Show(secondView); // How?
In Windows Forms logic this is implemented with variables:
var secondForm = new SecondForm();
secondForm.MyFormParameter = myFormParameter;
How can I reimplement this logic in MVP terms?
It greatly depends on your architecture, but this would be my suggestion:
First, ViewB does not need information in ViewA. It needs information either in the Model or a Presenter. ViewA and ViewB should get their info from the same place.
This could be done, as an example, by a service. This could look like this:
class ParameterService
{
public int MyParameter { get; set; }
}
class ViewA
{
void Foo()
{
// could also be done via injection - this is just a simple example
var svc = RootWorkItem.Services.Get<ParameterService>();
svc.MyParameter = 42;
}
}
class ViewB
{
void Bar()
{
// could also be done via injection - this is just a simple example
var svc = RootWorkItem.Services.Get<ParameterService>();
theParameter = svc.MyParameter;
}
}
Event Aggregation, also supported in the IoC framework you're using, could also work, where ViewA publishes an event that ViewB subscribes to. An example of this can be found here, but generally speaking you'll use the EventPublication and EventSubscription attributes (the former on an event in ViewA, the latter on a method in ViewB).