Extending a Model with Module-Defined Fields

Module-defined fields (MDFs) allow developers to inject additional fields into models from the Platform Core and other Modules. This is crucial when you want to reuse a model created by another person but need to capture additional information unique to your use case without changing the source code.

Continuing with the Bookstore example, let's assume we want to create an incentive program for our bookstore employees. We want to give each employee an IncentiveQuota ... if they sell that many books, they will get a bonus! Each employee's value will differ based on past performance, experience, and other factors.

We could add a new model to store this information, but MDFs provide an easier management method. Assuming that all our employees are Users in the system, we can actually add an IncentiveQuota field to the base User model from Platform.

To begin, right-click your project and choose New > MDFs ...

This will ask you which model you will be extending. You can extend any model from a Module you depend on. In this case, we will choose the User model.

Now that we have an MDF editor, let's add our new field. We'll add a field called IncentiveQuota of type Integer.

Now build your project and restart Platform Server. This will produce several artifacts:

  • Database: A new column ZBKS_INCENTIVE_QUOTA is added to the USERS table

  • Model Object: A new java class UserMDFs is available in the package com.mybooks.model. In java, you can access this object through the owning User object by calling user.getMDFs(UserMDFs.class)

  • Process Type Configuration: The new fields will be available for use in views and actions in the MPT.

To see our new MDFs in action, let's add a User search to the UI which includes our new field.

Open your MPT and navigate to User. Switch to the Views tab and add a new View called UserSearch, based on query "DefaultUserSearch".

You will see that your new MDF field is listed at the bottom of the Query tab as ZBKS.IncentiveQuota. (It is namespaced with the "ZBKS" prefix to make sure it doesn't get confused with MDFs from other modules, which might use the same name.) Let's include it in the retrieval.

Since this is the first time we're using User, we need to grant permissions ... go back to the Permissions tab and give ZBKS.SampleRoleType permission to read and write any Users under his Enterprise:

Then, give ZBKS.SampleRoleType permission to execute the view we added previously.

Now let's add a menu item for this view to our UI. Go back to the top of the MPT, open the UiMetaModel tab and add an appropriate WebAction and WebActionRef.

<!-- New WebAction to add: -->
<WebAction name="UserSearch">
    <PanelOptions>
        <PanelClass>One.Report</PanelClass>
        <PanelConfig>{viewName: "ZBKS.UserSearch", customModelName: "Standard User", autoExecute: true}</PanelConfig>
    </PanelOptions>
</WebAction>
      
<RoleTypeUiConfig menuType="tree">
    <RoleTypeRef>
        <IntrinsicRoleType>ZBKS.SampleRoleType</IntrinsicRoleType>
    </RoleTypeRef>
    <WebActionRef name="BooksByTitle"/>
    <WebActionRef name="CreateBook"/>
    <WebActionRef name="UserSearch"/>  <!-- this row is new -->
</RoleTypeUiConfig>

Save the MPT and Click the Submit button to submit the MPT to the server.

At this point, we should be able to login, search for Users, and see the new MDF column.

Of course, we don't yet have any IncentiveQuota values in the database ... but we can easily make that field editable like any other field. Add an action UpdateQuota to the User model in your MPT, and make the IncentiveQuota field optional. Create an action screen and add Email (non-nullable field on User) and ZBKS.IncentiveQuota field to it using Add button which makes this field visible, and give ZBKS.SampleRoleType permissions to execute this action.

Now submit your MPT and execute your new action.

We have now populated data in our module-specific field which we can throughout the Bookstore module.