Magnolia CMS workflow can be hook with ease (read more here and here) setting in few minutes standard Magnolia commands where you can whatever your application need.
Now lets go further.
The sample ContextLoggerCommand writes the same lines (of course, with a different execution context or parameter values), both when hooked on workflow launch or on workflow complete command:
2015-05-07 23:55:12,303 INFO info.magnolia.commands.MgnlCommand : Logging command parameters:
2015-05-07 23:55:12,304 INFO info.magnolia.commands.MgnlCommand : param repository: website
2015-05-07 23:55:12,304 INFO info.magnolia.commands.MgnlCommand : param recursive: false
2015-05-07 23:55:12,304 INFO info.magnolia.commands.MgnlCommand : param path: /demo-features
2015-05-07 23:55:12,304 INFO info.magnolia.commands.MgnlCommand : param modifiedOnly: false
2015-05-07 23:55:12,304 INFO info.magnolia.commands.MgnlCommand : param uuid: babb5315-f417-4083-9cf1-714bb304742f
2015-05-07 23:55:12,304 INFO info.magnolia.commands.MgnlCommand : param comment: This is a comment
2015-05-07 23:55:12,304 INFO info.magnolia.commands.MgnlCommand : param publicationDate: 2015-05-07T23:54:00
2015-05-07 23:55:12,304 INFO info.magnolia.commands.MgnlCommand : param version: 1.1
2015-05-07 23:55:12,304 INFO info.magnolia.commands.MgnlCommand : param requestor: superuser
What is the meaning of those parameters?
- repository: this is the activating Node repository (could be website, dam, …)
- recursive: true | false, it tell the activation command if a recursive publishing has been asked by the requestor
- path: this is the activating Node path (something like /demo-project/my-page)
- modifiedOnly: true | false, it tells something about the status of the node on public instance. It is a brand new node or an existing node just modified?
- uuid: this is the activating Node uuid, like “babb5315-f417-4083-9cf1-714bb304742f”
- comment (optional): this is the requestor comment
- publicationDate (optional): this is the scheduled date (2015-05-07T23:54:00 as a String representation
- version (optional): this is the Node version number (1.1, 1.2..)
- requestor: this is the username of the user that initiated the workflow
NB: these parameters refer to activation command only. Deactivation command is similar but with some differences..
Why 3 parameters for detecting a Node?
Interesting question.. normally, you can identify a JCR Node using only 2 parameters: repository + identifier or repository + path. Usually, the first pair is used (repo + id), but in Magnolia CMS a Node path, expecially if on website repository, is also a content URL: since the Node position (page URL) is available as a Context parameter, you don’t have to access the database to perform path-based actions.
In parameter list, 2 of them are special: comment and publicationDate. They are filled by the requestor on page activation dialog window:
The first one is only something that “enrich” the publication workflow. But the second one is read by activation workflow to understand if activation needs to be scheduled in the future: in this scenario, Magnolia reads a editor-generated content to act differently.
Perfect! That’s exactly what I need! Ask editors parameters is something we learned since the first Java HelloWorld, so.. I feel at home!
But.. how to do this?
Let us assume this scenario: I want to create a notification system that sends an email to users subscribed to website page updates. So, when a new page is activated on public instance, I need to intercept the command and send an email. But.. what happen if an editor updates the same page more than once a day? Subscribed users will be notified for any update. No good. I would like that any editor could say: “Hey, don’t alert subscribed users, this updates is only a typo-fix publication!”. In this way, intercepting command will check for the presence of a well-known parameter and in that case, it will skip the syndication.
Add a dialog field
The first step is to add a new field in pages activation dialog. This can be done as adding a standard field in a component dialog.
But.. where is the dialog? Let’s start from the origin. When editor clicks on “publish” button in the Magnolia sidebar or in context menu, a “pages” action is executed.
That action is overwritten by workflow module when installs, so that action is actually this one (the “schedulePublicationAction”):
The “schedulePublicationAction” uses a standard dialog:
Now, we can add a new custom field here: since a TextField and a DateField are already there, our choice is a CheckboxField:
And that’s it. Now, if you try to activate a page, you will see something like this:
Awesome. But if you try to log again what happen when workflow is launched, you won’t see that parameter: it has only been added to a dialog, without a server-side part that handle its storage. You don’t trust me? See what is saved in Tasks repository:
Now, the tricky side of the story begins.
Since we are dealing with a standard Magnolia Content App and we are inside a Action (invoked by our dialog), we need to instruct that action about the new “alert” parameter:
Now, we need to store that value in Task bag. We need to override a ParameterResolver class, and.. honestly, I don’t like this step, since Magnolia does not allow an easy way to do that. Anyway, create your class and bind it here:
Now, before reading the code, a little comment. The right thing would have been to add that parameter to HumanTask class. But that class is quite nested, inner.. there is another injection point: Magnolia stores its parameter in a “content” node inside the Task. And that node is stored as a Map (String – Object), so.. we can store whatever we want inside!
Here the code (partially hidden, since it is part of EE source code):
Now, let’s have a look at Tasks repo:
And this is the log (4th line):
2015-05-13 22:35:27,813 INFO info.magnolia.commands.MgnlCommand : Logging command parameters:
2015-05-13 22:35:27,813 INFO info.magnolia.commands.MgnlCommand : param repository: website
2015-05-13 22:35:27,814 INFO info.magnolia.commands.MgnlCommand : param recursive: false
2015-05-13 22:35:27,814 INFO info.magnolia.commands.MgnlCommand : param alert: true
2015-05-13 22:35:27,814 INFO info.magnolia.commands.MgnlCommand : param path: /demo-features
2015-05-13 22:35:27,814 INFO info.magnolia.commands.MgnlCommand : param modifiedOnly: false
2015-05-13 22:35:27,814 INFO info.magnolia.commands.MgnlCommand : param uuid: babb5315-f417-4083-9cf1-714bb304742f
2015-05-13 22:35:27,814 INFO info.magnolia.commands.MgnlCommand : param comment: This is a comment (with alert!)
2015-05-13 22:35:27,814 INFO info.magnolia.commands.MgnlCommand : param version: 1.9
2015-05-13 22:35:27,814 INFO info.magnolia.commands.MgnlCommand : param requestor: superuser
Yeah! Finish! Uhm.. not completely.. one last clean part, let’s put that parameter available to publishers in their MessageView:
Please have a look at how the parameter name is changed: since we decided to use the “content” storage bag of a Task, now our “alert” param is inside a content node called “content”.. this leads to a render name of “content.alert”. And here is the final result:
And.. done!
Few considerations:
- This is a hack. It is not intended to be a “standard” way to approach a customization. But for sure, it will save you (much) time.
- Magnolia does not expose a comfortable hook to inject logics, I needed to copy part of the code of a superclass!
- The overall changes are quite heavy to add a simple checkbox in a dialog. I hope that in future this can be facilitated.
Be First to Comment