The Entity Reference Autocomplete module
With the inclusion of entities in core, the way developers approach development in Drupal has dramatically changed in the last few years. Not too long ago nodes were the core of pretty much every aspect of a Drupal project. Nowadays it's not too difficult to find projects in which entities are the backbone of the project. Developers used to have to hack, or at the very least, write the core behaviour of a site by using mechanisms supposed to be there just for additional functionality. Now, they can dictate how the system should behave. This is probably the main reason for the shift of focus from nodes to entities.
Before, writing your own models and controllers for the objects that compose a site rarely happened. Doing so would involve spending a lot of time, and losing the integration that nodes offer out of the box with common tools such as views or panels (not to mention other obvious aspects like having forms, permissions, menu paths, and other features out of the box). Sure, one could just write handlers to integrate any custom models with these tools, but in the end, the benefit obtained would be small compared with the time spent. And even if the benefit was substantial, one would find oneself writing the same boilerplate code over and over again to deal with the most basic, common aspects of any custom module, yet not taking advantage of many of the most common contributed modules out there.
With Entities, the story has changed. Most of those things are already baked in for us now. If not completely, certainly most of the things have already been taken care of. This encourages people to write their own entities and leverage the Entity API as much as possible. When doing so, and architecturing a site with custom tables and entities, one of the most common things one might want to do is to relate the custom entities in some way. That's where two possible options come up: custom columns to be used as foreign keys, or fields. One could be tempted into the easy way of using the entityreference module, and simply add fields to the custom entities to reference any content they need. That would be quick, and provide a user friendly way to reference entities when working with them on the browser. There's nothing wrong with that approach, as long as the content to be referenced doesn't represent a main attribute of the model, and is not a key element to relate the model to any of the other entities that are supposed to be the core of the site.
However, when you bear in mind aspects like scalability and performance, you can't really let any nice or fancy features get in the way of architectural and design decisions. Even if they might save you a couple of hours at the beginning, they might become an important problem in the future. In other words, you should always put design decisions upfront, and not worry too much about implementation details. Think of your application in a way that makes sense, and think how the data is going to be related and accessed. Only then, architect your applications in the best possible way. Although this might sound obvious, it's easily forgotten after a few years working with a platform like Drupal, in which a big percentage of the work was done based on nodes and the Field API.
In a project that we have recently started, we've come across the situation described, in which we have several entities, all of them related in a nested hierarchy of five levels. All of these entities are created in the browser, and all of them let the user specify the parent to relate the new entity to (ideally, through an autocomplete field). At that point the entityreference module seemed a good option. However, relating these entities through fields doesn't really make sense in the application domain. Also, the way we need to retrieve the data forces us to have a proper model to store it. Otherwise, the site won't perform too nicely when things get big. So, we needed a friendly way to reference entities in the browser, without having to deal with all the field clutter, and writing some autocomplete paths specifically for our forms again, wasn't an attractive option. The first time you do it, it's ok, the second, it's even fine if you're in a hurry, but the third time, you don't really want to repeat the same work again, even if most of it is a copy & paste from a previous project*. For that reason we wrote a small, generic tool that we thought the community would find useful when dealing with similar cases.
The Entity Reference Autocomplete module
The Entity Reference Autocomplete module is just a small helper tool for developers. It defines a new form element type, called "entityreference", to easily add autocomplete fields to forms, from which to reference any entity of a Drupal site in the same way one would do it through an Entity Reference field. It handles all the validation out of the box, making sure that users have access to the possible entities to reference before returning them to their browsers. It lets developers add filters for the different entity bundles that can be accepted, as well as the maximum number of entities that can be referenced. Also, it returns the basic information about the entities referenced so that it's available on the submit callbacks of the forms.
Let see how to use it. All you need to do, is build your form as usual through drupal_get_form. In the form array, declare a new field of type 'entityreference' for each autocomplete field you need. The following example shows the 3 properties currently available, of which only the entity type "#era_entity_type" is mandatory. "#era_bundles", when specified, must be an array, even if it holds only 1 value, and "#era_cardinality" indicates the maximum number of references a user can add on the field.
function test_form($form, &$form_state) {
$form['referenced_entity_id'] = array(
'#type' => 'entityreference',
'#title' => t('My Reference'),
'#era_entity_type' => 'my_entity', // Mandatory.
'#era_bundles' => array('bund_1', 'bund_2'), // Optional.
'#era_cardinality' => 3, // Optional.
);
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('submit'),
);
return $form;
}
After rendering the code above, you will have an autocomplete field like the following image. In that case it references a project entity.
So, what about the values the user has entered? Apart from being able to add any custom validation to them, they are available in $form_state['values'] array, as usual, but the module adds some extra information about them, rather than just sticking to the entity ids, should you need it. The following code is taken from the module, and shows the actual information returned in the $form_state array after the validation has passed:
// Return some basic context of the entity referenced by the user.
$values[] = array(
'entity_id' => $entity_id,
'entity_label' => entity_label($element['#era_entity_type'], $entity),
'entity_type' => $element['#era_entity_type'],
'entity_bundle' => $bundle,
);
As you can see, just a few lines of code are needed to get your entity references fields on forms without having to be forced to use fields, or write your own autocomplete callbacks every time.
Stable but not stopped
We like to take advantage of any other contributed modules before writing our own tools, and we encourage people to do the same, as it helps to improve that contributed code and make it more useful, rather than keep reinventing the wheel. In this case, nothing seemed to solve the task for us: the Entity Reference module, despite being a fantastic tool, is completely coupled to fields, which we wanted to avoid for our specific case. We also came across the Entity Autocomplete module, which does pretty much the same thing, but doesn't seem to be too actively maintained, and presents a security issue that is yet to be solved**, so we ended up writing our own solution.
You can download the first stable release of the Entity Reference Autocomplete module from https://drupal.org/project/entityreference_autocomplete. If you're a developer and usually write custom entities for projects, you might find it useful, or at least I hope so. In that case, keep an eye on it, because it will probably receive some new features, such as filtering by entity fields, or any of the entity columns***.
*This doesn't apply if you are Spanish. In that case you're probably tired even before doing it the first time, so you would just go and write something generic straight away, which was my case.
** And, to add a grain of truth, I found it after I had actually written the module.
*** At the moment the filtering is done only by the entity label.
Related Service Areas: DevelopmentTeaser: Learn how I built this helpful tool for developers to easily reference entities in forms and how you can install and use it.Categories: DevelopmentDrupal PlanetPrimary Category: DevelopmentTags: entitiesform apifield apicontributions