The Associator Module
The Associator Module is one of the more complicated modules in reason. It has some of the same characteristics as the lister module, but adds more functionality. For one thing, the Associator Module does not support multiple views. The associator module will however use the columns and filters it finds in the database. If it finds more than one view in the database, it will only use the information from the first one. Also, it always uses the same content lister (The assoc_viewer located in content_listers/associate.php).
The Two Lists
One of the main differences that you will see between the normal lister and the associator is that there are two different lists for the items that are associated and those that are not. This happens in the alter_values() function of the content lister. Here, we take the normal entity selector that we're using and make a copy of it. After this we attempt to find the sorting for the list (although we use the sorting for the associated items, we ignore all paging and filters set for the rest of the list). Then we run the new entity selector and put it into the class variable ass_vals. Since we have already selected all the associated items it is important to remove them from the list of items to be selected in the main list. This is done at the bottom by adding a relation "entity.id NOT IN ( val1, val2, ... , valn )". If there are no ass_vals, this section is skipped.
This may seem like a rather bizarre way to do things, but after much deliberation, it was decided that this was the most efficient way to take care of things. It may seem like it is more efficient to use a LEFT JOINS for this kind of thing, allowing us to select all the entities with one query and not having to reapply the sorting or filtering to the list. There are three main reasons we have for not using a LEFT JOINS in this case. 1) By not using a LEFT JOINS, we are always able to see all selected entities, regardless of filtering or paging. This may or may not be a positive, but in our system, the number of unselected entities will in general greatly outnumber the number of selected entities. Thus, it may be helpful to always see them. 2) Using a LEFT JOINS in this situation creates an unnecessarily complicated query. We're already selecting from at least 4 tables, and in theory, we could select from many more (the most at this point is probably 10). Writing such a query can be quite difficult and not worth the time. 3) If a LEFT JOINS is used here we cannot use the entity selector to do our query. This is the most important reason for not using a left joins. Since we already have the viewer class and the entity selector class written, it is nice to be able to leverage those classes. Using a LEFT JOINS means we would have to write the queries by hand, and we would have to rewrite all the other functionality that we already have. Making one extra query seems like a small price to pay for being able to use these classes.
The Admin Functions
Unlike the normal lister which uses Edit and Preview for its admin functions in all cases, there is quite a bit of complex logic that goes into the admin functions for the associator module. First of all, we have to worry about whether or not the item is already selected. If it is not selected, then we have a link that says "Select". If it's already selected, then we have to worry about whether or not the current relationship is a required one-to-many relationship. If it is, then we simply put up text that says "Selected" (since we don't want people to delete a required one-to-many relationship), otherwise we put up a link that says "Deselect".
We also have to worry about whether we're on the first or second level of editing. If we're on the second level of editing, we can't go to the third level so no preview or edit links will be available. However, if we're on the first level, we can allow people to do these things by creating a link to the second level. We create one link each from preview and edit. The exception to this comes if their site is borrowing an entity from a different site. In this case, the edit link is replaced with static text that says "Borrowed".
There are a few other things that it is worth mentioning about the associator module at this point. If you look at the run function, you will see some other things. First, you will notice that the class calls the viewer->show_associated_items() function. This cannot be called from the viewers do_display() function because we need to include the filters and other things in between them. Also, you will see an add link if you're on the first level. This is very similar to clicking on an edit link, except that a new entity is created. Also, during the finish module for that entity, a relationship between the new entity and the current entity is created. Next if the site is able to borrow the current type from another site and we're on the first level, a link to the sharing page is created. If you borrow an item from that site, then a relationship between that and the current item will be created.
Another change from reason2 to reason3 is that now the associator ( and also the sharing modules ) institute list persistence. It was difficult to figure out exactly how to do this, because of the many variables involved. It was decided that the best way was to just store all the different combinations as their own session variable. Therefore, you can find this variable in $_SESSION[ 'assoc' ][ site_id ][ type_id ][ rel_id ][ id ]. Thus, if you're on a different relationship or different entity, you will have different list persistence.