This tutorial explains how to:
An example of the requirement is as follows:
For this tutorial, I have created the Vendor entity in a module called MyModule. All files related to Vendor live in custom/Espo/Modules/MyModule/. Because Contact is an existing entity, the customizations will be placed in custom/Espo/Custom/. Modifying existing entities works because the associated json files are merged into the files that come with Espo. If you choose to not use a module, place the files for Vendor in custom/Espo/Custom/ as well. Everything else is the same.
Part 1: Creating the relationship and adding a column to the middle table
In custom/Espo/Modules/MyModule/Resources/metadata/entityDefs/Vendor.json:
In custom/Espo/Custom/Resources/metadata/entityDefs/Contact.json:
Stopping Point
Part 2 - Showing the additional field in the UI
In summary, the relationship and additional column in the middle table have been established. What follows is the process for showing the value of additional column to the user. To accomplish that, each entity (Contact and Vendor) must be modified. Some of the modifications involve telling Espo to use non-storable fields. In other words, the fields are populated by relationships instead of directly from the database, which is the more typical method.
The next steps involve modifying the Vendor entity, which happen in custom/Espo/Modules/MyModule/Resources/metadata/entityDefs/Vendor.json:
A similar list of steps must be implemented for the Contact entity in custom/Espo/Custom/Resources/metadata/entityDefs/Contact.json:
Stopping Point
Remember to set the other files as necessary:
- Add a middle column (in Espo language, it is called a mid key) to a many-to-many relationship.
- Add the mid key to the UI to allow it to be seen and modified by users.
- Update the mid key using the query builder via PHP. The situation: I want to relate Contacts (existing entity) to Vendors (custom entity). The Contact should have a Role which is different for each Vendor. Note: This is the same situation as what exists between Contacts and Accounts.
An example of the requirement is as follows:
- Michael Scott is a Contact.
- Dunder Mifflin and Michael Scott Paper Company are Vendors.
- At Dunder Mifflin, Michael Scott is the Regional Manager. At Michael Scott Paper Company, Michael Scott is the President. In each Vendor detail view, I want to see Michael Scott listed with the correct title.
For this tutorial, I have created the Vendor entity in a module called MyModule. All files related to Vendor live in custom/Espo/Modules/MyModule/. Because Contact is an existing entity, the customizations will be placed in custom/Espo/Custom/. Modifying existing entities works because the associated json files are merged into the files that come with Espo. If you choose to not use a module, place the files for Vendor in custom/Espo/Custom/ as well. Everything else is the same.
Part 1: Creating the relationship and adding a column to the middle table
- Create the custom Vendor entity using the normal tools and methods.
- Add a many-to-many relationship between Contact and Vendor. In the following image, I created the relationship from within the Relationship area of the Vendor entity.
- The important settings are as follows:
- Relationship names: "vendors" and "contacts"
- Middle table name: "contactVendor"
- Labels: These are not important, but use "Vendors" and "Contacts" to make things easier, at least at first.
- IMPORTANT: Add a Link Multiple Field on the right side for Contacts. The additional column in the middle table can also be used in list views, but this tutorial requires a Link Multiple Field.
- At this point, you should see the following sections of code in your files:
In custom/Espo/Modules/MyModule/Resources/metadata/entityDefs/Vendor.json:
Code:
{ ... "fields": { ... "contacts": { "type": "linkMultiple", "layoutDetailDisabled": true, "layoutMassUpdateDisabled": true, "layoutListDisabled": true, "noLoad": true, "importDisabled": true, "exportDisabled": true, "customizationDisabled": true, "isCustom": true }, }, "links": { ... "contacts": { "type": "hasMany", "relationName": "contactVendor", "foreign": "vendors", "entity": "Contact", "audited": false, "isCustom": true } } }
Code:
{ ... "links": { ... "vendors": { "type": "hasMany", "relationName": "contactVendor", "foreign": "contacts", "entity": "Vendor", "audited": false, "isCustom": true } }, "fields": { ... "vendors": { "type": "linkMultiple", "layoutDetailDisabled": true, "layoutMassUpdateDisabled": true, "layoutListDisabled": true, "noLoad": true, "importDisabled": true, "exportDisabled": true, "customizationDisabled": true, "isCustom": true } } }
- At this point, the relationships are functional. You can relate entities to each other using the regular methods.
- The middle table is currently defined as follows:
- id - The ID of the row in the middle table
- contactId - The ID of the associated Contact record
- vendorId - The ID of the associated Vendor record
- deleted - The flag to set the row as deleted
- Add the following code to custom/Espo/Modules/MyModule/Resources/metadata/entityDefs/Vendor.json and rebuild the instance from the administration menu:
Code:
{ ... "links": { ... "contacts": { ... "additionalColumns": { "role": { "type": "varchar", "len": 40 } }, } } }
- The middle table is now defined as follows:
- id - The ID of the row in the middle table
- contactId - The ID of the associated Contact record
- vendorId - The ID of the associated Vendor record
- deleted - The flag to set the row as deleted
- role - The additional column for the many-to-many relationship.
Stopping Point
- If you don't need to show the value of the additional column to the user, you can stop here.
- If you need to show the value of the additional column to the user, continue with the tutorial.
Part 2 - Showing the additional field in the UI
In summary, the relationship and additional column in the middle table have been established. What follows is the process for showing the value of additional column to the user. To accomplish that, each entity (Contact and Vendor) must be modified. Some of the modifications involve telling Espo to use non-storable fields. In other words, the fields are populated by relationships instead of directly from the database, which is the more typical method.
The next steps involve modifying the Vendor entity, which happen in custom/Espo/Modules/MyModule/Resources/metadata/entityDefs/Vendor.json:
- Add a new field called contactRole to store the value in the role field of the middle table. The new field is not storable, which means it is indirectly populated by Espo instead of directly through a call to the database. You can name this field whatever you want as long as it is unique in terms of the fields for the Vendor entity.
- Add a property called columnAttributeMap to the link for the Contact relationship. It must contain a key-value pair.
- The key of the property, role, must match the name of the new field in the middle table.
- The value of the property, contactRole, must match the name of the new field of the Vendor entity.
- Add several properties to the contacts field and modify some of the existing properties. I don't know what several of the properties do, so I won't try to explain. Copy, paste, and modify to fit your situation. Note: The value of the role property is vendorRole; this value must match the name of the non-storable field in the Contact entity.
- For now, we are using a default view called views/fields/link-multiple-with-role, which is in client/src/fields/views/link-multiple-with-columns.js.
Code:
{ ... "fields": { ... "contacts": { "type": "linkMultiple", "layoutDetailDisabled": false, "layoutMassUpdateDisabled": false, "layoutListDisabled": false, "noLoad": false, "importDisabled": false, "exportDisabled": false, "customizationDisabled": false, "columns": { "role": "vendorRole" }, "additionalAttributeList": [ "columns" ], "view": "views/fields/link-multiple-with-columns", "default": "javascript: return {contactsIds: []}", "isCustom": true }, "contactRole": { "type": "varchar", "notStorable": true, "utility": true, } }, "links": { ... "contacts": { ... "columnAttributeMap": { "role": "contactRole" } } } }
A similar list of steps must be implemented for the Contact entity in custom/Espo/Custom/Resources/metadata/entityDefs/Contact.json:
- Add a new field to store the text in the UI and an additional property to the link for the Vendor relationship.
- The new property for the link is called columnAttributeMap. It must contain a key-value pair.
- The key of the property, role, must match the name of the field in the middle table.
- The value of the property, vendorRole, must match the name of the new field of the Vendor entity (see below).
- The new field, vendorRole, is not storable, which means it is indirectly populated by Espo instead of directly through a call to the database. You can name this field whatever you want as long as it is unique in terms of the fields for the Contact entity.
Code:
{ ... "fields": { ... "vendorRole": { "type": "varchar", "notStorable": true, "utility": true } }, "links": { ... "contacts": { ... "columnAttributeMap": { "role": "vendorRole" } } } }
Stopping Point
- If you need role to be a free-from text field, you can stop here.
- If you need to create a list of options for the role field continue with this tutorial.
Remember to set the other files as necessary:
- Layouts - Detail, List, Search, and other views
- Languages and labels
Comment