fromAugust 2011

Why A Duck?


You have a record; it contains tracks. Consider the relationship between the tracks and between each individual track and the album as a whole: The tracks may also be by different recording artists.

Or ponder the relationship between financial donations to political parties from corporations and those from individuals—and add in the specific amounts of those donations. Muse upon the family relationship between the Marx Brothers—or the Bush twins.

Website building is full of relationships. Yet, despite several attempts, Drupal has not had a generic relationship solution. Node reference and user reference are useful modules but extremely limited. One of the biggest problems with them is the inherent notion of direction. And yet, often relations do not have a direction. Also, there are clearly only two nodes in a relation expressed by node reference. Storing the relationship between the Marx Brothers is not an easy task with such a limited tool.

Enter Relation ( Relation is not a field, but an entity in itself. It can store directed but also non-directed relations. It can store as many entities as you want, so storing all five Marx brothers is easy. And, relation is not just simply an entity but a fieldable entity (it's Drupal 7 and later only) so you can add a number field to the 'donation' relation and store how much was donated. The module provides an API and builds user facing components on top of the API. It integrates both with Views and Rules.

We covered examples in the opening paragraph, now let’s tackle the record album. There are various questions we might want the website to answer, such as: What is track three? What album does it belong to? What are the other tracks on the album?

We can either add a multiple value node reference field to the album node referencing the tracks or we can add a single value node reference field to the track referencing the album. No matter which one you do, to answer all three of these questions you need to do a back reference operation and that's not implemented well. That's no surprise because the node reference field is attached to the source entity and on the target node you need to employ some wizardry to show the back reference.

With relation, you would make the album the relation entity itself, and the endpoints the tracks. So to fetch the tracks of an album, you simply load the album entity. To get the album of a track, you need to find the relation the track belongs to. Finally, to create our block listing the tracks on the same album, we need the query to find the album and then load it to find the other endpoints—which are the tracks.

With that said, now it will be easier to understand a node reference field and how Relation stores its data. For every node reference, one row is stored in the database: (source entity type, source entity id, nid). The source entity type and id are stored, but for the target only an id is stored; the fact that it's a node is implied. Relation on the other hand stores one row for every endpoint: (relation entity id, endpoint entity type, endpoint entity id). If you are familiar with node reference you can think of Relation as an "anyreference" from the relation entity to the target entity. Now you can see how Relation can store relations with five endpoints: it just stores five rows. All rows are equal so all endpoints are equal. There is no difference between them, we do not have the source and the target node reference has; therefore, there is no such thing as a backreference. It is possible to make Relation store direction relations, but that is only enforced on creation time and query time. If you have a review about a product, finding the product the review is about uses the exact same code as finding a review about the product. Most of the time this leads to actually needing two queries instead of one to find the other endpoint(s) of the relation: one to find out the relation id, the other to load the relation entity. Flexibility always comes at a cost, alas.

To better understand an incredibly powerful feature of Relation, let's repeat what kind of entities are involved in a relation: there is the relation entity itself and the endpoint entities. The relation entity stores the fact that the endpoint entities are, well, related. Since endpoints can be any kind of entity, they can also be relations. For example, if you go with the album-as-a-relation solution above, and you want to add authors to it, then you will create such relations: one endpoint will be configured as the album bundle in the relation entity type while the other will be the artist entity type.

Relation is still in the budding stage (at the time of this writing, even 1.0 is not yet out). There is a serious push to replace user and node reference modules completely. With continued effort, Relation may mature quickly enough to be included in the Drupal 8 core.