Jahia 7.3 Jahia 8 Legacy

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

Every content type can have n references to another content type this can be done in defintion e.g. example an alert can have multiple resorts:



[jnt:alert] > jnt:content, jmix:structuredContent
 - name (string)
 - resort (weakreference) multiple < 'jnt:resort'

 

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 uptodate, you would need an interceptor. Which modify the related content. 
An Interceptor can be created with spring. A simple defintion 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 an 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 follow 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.