Best Practices for Creating a Feature in CRM Core

Last updated on
11 March 2017

This page outlines some best practices for creating a feature for CRM Core. These practices are continuing to develop as people work with the module, and more documentation around them will emerge over time.

CRM Core is built as a framework for people to collaborate on the production of small, useful features that extend the use of the module. In order to provide portability around functionality between websites, it is important to build some standards that will allow developers to avoid conflicts between features. Some of these are obvious, and some of these are counter-intuitive depending on how you plan to use CRM Core.

Consider the items listed on this page as guidelines towards guaranteeing interoperability. They will be useful in most cases, but not all. If you are developing a simple feature you plan to distribute for CRM Core, they will serve you well. If you are planning to build an install profile that will provide users with a pre-configured CRM system, there may be reasons to deviate from the guidelines listed here. Use your judgement, and ask questions in the issue queue if there is something you are wondering about.

Use a Unique Namespace

Every feature developed for CRM Core should have its own unique namespace. This namespace should be reflected in all the elements used by your feature: field names, content types, views, paths, etc.

For instance, in feature foo, which is used to manage bars:

  • A content type might be called foo_bar.
  • A field in the content type might be called foo_date_started.
  • A view displaying all the bars might be called foo_list_of_all_bars.
  • A path to a report about the views might be created as such: crm-core/reports/foo/all-bars.

Respect the Reserved Paths

There are some reserved paths in CRM Core. These are guidelines offered as a way of ensuring interoperability and predictability in how the system will be used. You are not forced to conform to them, but realize that other people looking to use your module might run into issues if you stray too far.

  • Contacts: crm-core/contact, crm-core/contacts
  • Reports: crm-core/reports
  • Dashboard: crm-core, crm-core/dashboard
  • Activities: crm-core/contact/%contact-id/activity/%activity-id, crm-core/activity/%activity-id,
  • Relationships: crm-core/contact/%contact-id/relationships/%relationship-id, crm-core/relationships/%relationship-id
  • Administration: admin/structure/crm-core, admin/config/crm-core

More about the importance of reserved paths can be found in the documentation for CRM Core UI Conventions.

Clone and Override, Don't Overwrite

There are lots of situations that can arise where you might want to make some changes to a default display in CRM Core and distribute it to other users. Perhaps you have a really great way of displaying a list of contacts in the system, or maybe you have created a better way to display activities in the system.

The best practice for distributing features that do this is as follows:

  • Clone the view used to display the contacts / activities / relationships. These are all views, which should make it easy.
  • Make your changes to the cloned view and export it as part of your feature. Give it the same path as the default view you are modifying.
  • In your feature, disable the default view in CRM Core when the feature is enabled. Re-enable the default view when the feature is disabled.

Entities Should be Self-Contained

When building a feature, wherever possible, ensure the entities it defines are contained within the feature itself. The feature should declare the entity and the default fields used within it. Other features should not add or delete fields from the entity once it is defined.

This applies to CRM Core entities as well. If you are building a feature that adds fields to the default meeting type, that is okay, but remember that you can't always count on it being present because users can delete it. It is often better to create a new feature with its own meeting type with all the fields needed for your module. This keeps you from having to make assumptions about what is there.

Use Bridge Features for Fields

If you really, really need to have 2 features that rely on a common set of fields, consider building a third feature that contains the entity / fields that they will use. This is a best practice for a couple of reasons. First off, it is really, really easy to get into situations where an entity / field is being exported in 2 features. It can create issues within features itself and make your life difficult. Second, and most importantly, people need to be able to turn features off within CRM Core. Taking steps to ensure that each feature can operate independently of others is just good practice.

Don't Create Fields on Contact Entities

Depending on your use case, it's not always a good idea to build features that add fields to the contact entity.

When you do, you are making an assumption about how people have configured their CRM Core system. It cuts down on the portability of features and forces people to use the fields you defined.

For instance: let's say you are building a feature that stores a field for business address. Maybe that feature displays a really nice set of maps for looking at a the business addresses of contacts in a certain city. Some of the people looking to use your feature may already have a field for storing a business address - suddently your feature is creating repetitive data, which might be hard to deal with.

When people are working with CRM Core, they will configure their own fields with their own meaning. When you create features that rely on fields in the contact entity, you are forcing them to use the same fields the same way you have intended. There are some situations where this is appropriate - for instance, if you are building a feature that is intended to work as part of a specific distribution.

In other situations, it is best to build features in a way where fields that affect a contact record can be configured through instructions to the user or a settings page. This is a problem that affects a lot of other platforms besides CRM Core, and will probably change over time.