Creating many-to-many relationships in Jahia
Question
Is it possible to create a real n to m relation between content in jahia and how to do it?
Answer
Definitions
Every content type can have n references to another content type. This can be done in a definition e.g. example, an alert can have multiple resorts:
[jnt:alert] > jnt:content, jmix:structuredContent
- name (string)
- resort (weakreference) multiple < 'jnt:resort'
The same thing can be done for the other content type. Resorts can have different alerts:
[jnt:resort] > jnt:content, jmix:structuredContent
- name (string)
- alerts (weakreference) multiple < 'jnt:alert'
The problem, when you update an alert, the resort is not updated. When you want to have both fields up-to-date, you would need an interceptor. Which modify the related content.
Interceptors
With Jahia 8.2
You can take as an example the following source code.
Before Jahia 8.2
An Interceptor can be created with spring. A simple definition like:
<bean name="alertResortInterceptor" parent="propertyInterceptorRegistrator">
<property name="propertyInterceptor">
<bean class="org.jahia.modules.resortalert.interceptor.SaveAlertInResortInterceptor">
<property name="nodeTypes" value="jnt:alert"/>
</bean>
</property>
</bean>
In this case, the interceptor will be applied on jnt:alert contenttype. So maybe on jnt:resorts I could make the definition read only or I could add a second interceptor for the other type.
The implementation of the bean org.jahia.modules.resortalert.interceptor.SaveAlertInResortInterceptor must inherit from org.jahia.services.content.interceptor.BaseInterceptor and implement the following method:
@Override
public Value[] beforeSetValues(JCRNodeWrapper node, String name, ExtendedPropertyDefinition definition,
Value[] originalValues) throws ValueFormatException, VersionException, LockException,
ConstraintViolationException, RepositoryException {
if (name.equals("resort")) {
JCRSessionWrapper session = JCRSessionFactory.getInstance().getCurrentUserSession(Constants.EDIT_WORKSPACE);
for (Value value : originalValues) {
JCRNodeWrapper resort = session.getNodeByUUID(value.getString());
logger.debug("Alert " + node.getPath() + " will be added to Resort: " + resort.getPath());
resort.getProperty("alerts").addValue(node);
resort.saveSession();
}
return null;
}
return originalValues;
}
The method read all selected resorts, and extends the property alert (on the resorts) with the current alert.
This is an simple example. Maybe it must be extended when you publish one alert, you would also have to publish the related resorts.