Page tree
Skip to end of metadata
Go to start of metadata

Introduction

Dialog definition has changed between M4.5.x and M5. This is mainly due to the changes of the UI component as we moved from HTML forms to Vaadin UI for dialogs and form.

The main changes are:

  • Configuration of action implementation and definition
    • 4.5 allows you to define saveHandler on dialog definition.
    • 5.x replaces this with a direct action definition on the dialog.
  • Structure of a dialog, tab and field definitions
  • Replacement of controls by fields
M5 Dialog definitionM4.5 Dialog definition

 stkTextImage

 stkTextImage

 actions

 

 commit

 

 class

 

 label

 

 cancel

 

 form

 

 tabs

 tabText

 tabText

 subtitle

 fields

 text

 subtitle

 

 text

 

 label

 

 i18nBasename

 

 label

 

 

Preparation steps

In order to migrate dialogs, some preparation has to be performed in the following areas:

  • Custom save handler replacement.
  • Custom controls replacement.

First identify all your custom components. TODO: Are more detailed steps needed?

Save handler replacement

Replace custom save handlers with either a custom action or a custom property transformer.

Custom action

Replace your save handler with a custom action if the save handler:

  • Acts on more than just form properties.
  • Defines complex logic. 

In this case you will have to create a custom action and definition. Let's take a basic example:

Create a Definition class
CustomSaveActionDefinition
public class CustomSaveActionDefinition extends SaveDialogActionDefinition {
    public CustomSaveActionDefinition() {
		// This allows you to directly register your action
        setImplementationClass(CustomSaveAction.class);
    }
}
Create an Action class
CustomSaveAction
public class CustomSaveAction extends SaveDialogAction {
    public CustomSaveAction(CustomSaveActionDefinition definition, Item item, EditorValidator validator, EditorCallback callback) {
        super(definition, item, validator, callback);
    }
    @Override
    public void execute() throws ActionExecutionException {
        // First Validate
        validator.showValidation(true);
        if (validator.isValid()) {
			// Get the JcrNodeAdapter that contains all field properties 
            final JcrNodeAdapter itemChanged = (JcrNodeAdapter) item;
            try {
                String fieldPropertyText = itemChanged.getItemProperty("fieldPropertyText").toString();
				// Manipulate the data, and do your business logic 
				...
				// Once this is done, set the transformed value to the itemChanged if you want that they are persisted on the related JCR node 
				// The related node will be updated based on the item value by the following call:
                final Node node = itemChanged.applyChanges();
				
				node.getSession().save();

Register the custom save action to the migration task
Create a specific ActionCreator

In case you need to configure more than a class and label on your custom action definition, you will need to create a custom ActionCreator.

 public class CustomActionCreator implements ActionCreator {
    private final String name;
    private final String label;
	private final String myCustomProperty;
    private final String className;
    public BaseActionCreator(String name, String label, String className, String myCustomProperty) {
        this.className = className;
        this.label = label;
        this.name = name;
 		this.myCustomProperty = myCustomProperty;
    }
    @Override
    public void create(Node actionsNode) throws RepositoryException {
		// Create the action node
        Node actionNode = actionsNode.addNode(this.name, NodeTypes.ContentNode.NAME);
		// Create the properties
        actionNode.setProperty("label", this.label);
        actionNode.setProperty("class", this.className);
		....
    }

 

From your custom dialog migration task

You can create a custom dialog migration class extending DialogMigrationTask. Extending this class let you define the custom controls and action to use during dialog migration.

/**
 * Field Migration task for the specific Form fields.
 */
public class CustomDialogMigrationTask extends DialogMigrationTask {
    public CustomDialogMigrationTask(String moduleName) {
        super(moduleName);
    }
    @Override
    protected void registerActionsForDialogToCreate(HashMap<String, List<ActionCreator>> dialogActionsToMigrate) {
        // Register the Custom Save Action
        ActionCreator saveAction = new CustomActionCreator("commit", "save changes", CustomSaveAction.class.getName(), "myProperty");
        // Register a standard Cancel Action
        ActionCreator cancelAction = new BaseActionCreator("cancel", "cancel", "info.magnolia.ui.admincentral.dialog.action.CancelDialogActionDefinition");
        // Create an entry
        dialogActionsToMigrate.put("dialogName", Arrays.asList(saveAction, cancelAction));
    } 

In this case, during migration when dialogs named "dialogName" are handled, the specific CustomSaveAction is set as save action.

You may also simply create a new instance of DialogMigrationTask in your version handler and pass the HashMap<String, List<ActionCreator>> dialogActionsToMigrate in the constructor parameter.  

Custom Transformer

Actions

Transforming field values

Custom controls replacement

Magnolia 5 introduced some new fields (previously called controls), so the first step is to check if your custom control is available as a standard M5 field (List of fields). If this is not the case, you will need to create and register your own field.

Replace a custom control with an existing M5 field

Register a custom ControlMigration to the migration task.

Assume that your control's ID is dateControl and that the M5 date field is exactly what you were expecting. No additional control migration step is needed. This means that the steps performed in DateControlMigration are sufficient.

What the task does:

  • Removes the controlType  property
  • Create a class  property pointing to DateFieldDefinition.class.getName()

In this case, just register a new entry into getCustomMigrationTask() from your custom CustomDialogMigrationTask

public class CustomDialogMigrationTask extends DialogMigrationTask {
    public CustomDialogMigrationTask(String moduleName) {
        super(moduleName);
    }

    @Override
    protected void registerControlsToMigrate(HashMap<String, ControlMigrator> controlsToMigrate) {
  		// Define your custom types 
  		controlsToMigrate.put("dateControl", new DateControlMigration()); 
  		....
OR (Recommended way if you don't have ActionCreator)

In your version handler inject  ControlMigratorsRegistry, add the migrator to the registry, and then simply call the  DialogMigrationTask

    @Inject
    public CustomModuleVersionHandler(ControlMigratorsRegistry controlMigratorsRegistry) {
        // Register control migration task.
        controlMigratorsRegistry.register("dateControl", new DateControlMigration()); 
        ....
		
		register(DeltaBuilder.update("2.2", "")
        
		// migrate dialogs to magnolia 5 dialogs
        .addTask(new DialogMigrationTask("myCustomModule"))
Additional step needed

Assume that your custom controls uses 2 property split into three M5 DateField.

M4.5.x Control definitionValue M4.5 Dialog definitionNew Value

 dateControl

 

 stkTextImage

 

 dateTime

true

 time

true

 dateTimeFormat

yyyy-MM-dd:HH:mm:ss

 dateFormat

yyyy-MM-dd
  

 timeFormat

HH:mm:ss

 controlType

Date

 class

info.magnolia.ui.form.field.definition.DateFieldDefinition

 required

true

 required

true

 label

Date

 label

Date

 

DateControlMigration already handles the migration of the controlType property to class.

Now a CustomDateControlMigration has to be written in order to manipulate the dateTime and dateTimeFormat properties.

/** 
* Migrate an custom dateControl to a DateField. 
*/ 
public class CustomDateControlMigration implements DateControlMigration { 

	@Override 
	public void migrate(Node controlNode) throws RepositoryException { 
		super.migrate(controlNode); 
		// Remove the first property 
		Property dateTimeProperty = controlNode.getProperty("dateTime"); 
		PropertyUtil.renameProperty(dateTimeProperty, "time"); 
		// Split the second property 
		Property formatProperty = controlNode.getProperty("dateTimeFormat"); 
		controlNode.setProperty("dateFormat",StringUtils.left(formatProperty.getString(), StringUtils.indexOf(formatProperty.getString(), ":"))); 
		controlNode.setProperty("timeFormat",StringUtils.right(formatProperty.getString(), StringUtils.indexOf(formatProperty.getString(), ":"))+1); 
		formatProperty.remove(); 
	} 
}

Register a new entry into getCustomMigrationTask() from your custom CustomDialogMigrationTask

public class CustomDialogMigrationTask extends DialogMigrationTask { 
	.... 
	@Override
    protected void registerControlsToMigrate(HashMap<String, ControlMigrator> controlsToMigrate) {	
		// Define your custom types 
		controlsToMigrate.put("dateControl", new CustomDateControlMigration()); 
        ....

Replace a custom control with a new field

Assume that you have a dialog displaying a list of user specific information and then normal text fields. For the user specific information display the best approach would be to extend the StaticField field. In M5, Field are created by FieldFactory referenced by a FieldDefinition. In general, if you want to add functionality to an existing Field, you will only have to override the related FieldFactory, define a new FieldDefinition and register the new Field

Coming back to our example, the StaticFielFactory expose a 'public String createFieldValue()' that allows to create the message to display.

Create your custom FieldFactory
public class StaticCustomFieldFactory extends StaticFieldFactory<StaticCustomFieldDefinition> { 
	private static final Logger log = LoggerFactory.getLogger(StaticCustomFieldFactory.class); 
	
	// Injected factory private MyFactory factory; 
	@Inject 
	public StaticCustomFieldFactory(StaticCustomFieldDefinition definition, Item relatedFieldItem, MyFactory factory) { 
		super(definition, relatedFieldItem); 
		this.factory = factory; 
	} 

	@Override public String createFieldValue() { 
		String value = ""; 
		try { 
			// put your logic here 
			this.factory.do(... 
			... 
		} 
		return value; 
	}

 

Create your custom FieldDefinition
/** 
 * Definition used for create a StaticFormField. 
 */ 
public class StaticCustomFieldDefinition extends StaticFieldDefinition { }
Register the new custom field

Register.

Register a custom ControlMigrator to the migration task.

Create a CustomControlMigrator that will migrate your old controls to the newly created field. This task will basically

  • create the new field definitions property
  • remove the old property like controls,...
public class StaticCustomControlMigrator implements ControlMigrator {
    @Override
    public void migrate(Node controlNode) throws RepositoryException {
        controlNode.getProperty("controlType").remove();
        controlNode.setProperty("class", StaticCustomFieldDefinition.class.getName());
		...
    }
}

This task is called during the dialog migration process once registered.

public class CustomDialogMigrationTask extends DialogMigrationTask { 
    .... 
    @Override
    protected void registerControlsToMigrate(HashMap<String, ControlMigrator> controlsToMigrate) {    
        // Define your custom types 
        controlsToMigrate.put("dateControl", new CustomDateControlMigration()); 
		controlsToMigrate.put("myControl", new StaticCustomControlMigrator()); 
        ....

Dialog migration task

GOAL:

REQUIREMENTS:

STEPS:

Class: DialogMigrationTask
Constructor attributes
:

PropertyDescriptionDefault valueValid values
moduleNameName of the module where the migration will be performed.  Mandatory. String 

 

Custom implementation

Based on the previous code example:

public class CustomDialogMigrationTask extends DialogMigrationTask { 
        
	public CustomDialogMigrationTask(String moduleName) {
        super(moduleName);
    }

	@Override
    protected void registerActionsForDialogToCreate(HashMap<String, List<ActionCreator>> dialogActionsToMigrate) {
        // Register the Custom Save Action
        ActionCreator saveAction = new CustomActionCreator("commit", "save changes", CustomSaveAction.class.getName(), "myProperty");
        // Register a standard Cancel Action
        ActionCreator cancelAction = new BaseActionCreator("cancel", "cancel", "info.magnolia.ui.admincentral.dialog.action.CancelDialogActionDefinition");
        // Create an entry
        dialogActionsToMigrate.put("dialogName", Arrays.asList(saveAction, cancelAction));
    } 

    @Override
    protected void registerControlsToMigrate(HashMap<String, ControlMigrator> controlsToMigrate) {    
        // Define your custom types 
        controlsToMigrate.put("dateControl", new CustomDateControlMigration()); 
		controlsToMigrate.put("myControl", new StaticCustomControlMigrator()); 
    }

 

 

 

 

  • No labels