Problem/Motivation
The current relationship definitions are:
- incomplete
- restrictive, and
- do not play well with Views (due to their bundled, multi-table join nature)
For example, consider the relation_handler_join class.
The build_join() method finds the other endpoint on a relation in three steps:
- join entity to endpoints
- self-join the endpoints table but grab a different endpoint (r_index)
- join endpoints to other entity
This join is intended for use when the base table to the view is an entity like a node. In practice, I have found it more useful to have the base table be Relation. But there is no relationship definition that provides the other endpoint in this case. If this class is used, then it produces a cross product of rows. In other words, you get N x N rows returned instead of N rows.
So I modified this class to eliminate the first join from entity to endpoints. This solved the cross product problem. However, if you then want to relate to the other endpoint entity, it is a bit of wishful thinking to have the join handler get the correct alias for the desired instance of the endpoints table. Using the "%alias" token works for the current relationship but fails if you need multiple relationships for the View.
This is because of the "not playing well with Views" part. Since Relation joins multiple tables in a single relationship definition, but Views only knows about two of them, then Views is not able to manage the aliases. Because of this, you can not specify the "table instance" through the Views UI and are not able to accurately determine an alias in code.
The unknown alias problem is an issue if you need to add multiple relationship definitions to the view. For me, this seems to be a very likely possibility. The handler code can not reliably determine the aliases it needs.
Proposed resolution
Replace the three existing multi-table relationships (plus the fourth mentioned above) with three dual-table relationships:
- relation to endpoints
- endpoints to entity
- endpoints to endpoints
With these three:
- we provide the existing functionality and more
- you will be able to specify the "table instance" through the Views UI, and
- Relation will fit into the Views API ("play well")
The new relationships may imply you can not use one of the endpoint entities as the base table to Views. However, in my experience this seems not a hindrance, but a good practice. You will still be able to access each endpoint (or all endpoints) using the new relationships.
Remaining tasks
Review, write tests, change documentation (API documentation does not exist).
User interface changes
The relationship options form will now include the "table instance" select element as Views will know about it.
API changes
None.
| Comment | File | Size | Author |
|---|---|---|---|
| #29 | 1361780-29.patch | 18.25 KB | mikran |
| #28 | add_more_conditions-1361780-27.patch | 13.46 KB | mikran |
| #28 | relation_handler_enpoint_entity_join-1361780-27.patch | 4.75 KB | mikran |
| #27 | relation1.png | 163.57 KB | howto |
| #22 | add_relation_type_condition-1361780-22.patch | 13.37 KB | howto |
Comments
Comment #1
solotandem commentedAttached patch implements the proposed resolution.
Comment #2
chx commentedTerrific idea.
I must presume you meant this patch. I can't seem to be able to pick r_index though.
Comment #3
dawehnerThere
You can't have a relationship without a handler. Maybe an issue for views should be filled...
Here is a new patch
Comment #4
chx commentedRight now, the biggest problem is that I do not readily see how to add the relation table itself. Otherwise, we are good.
Comment #5
solotandem commented#2: Yes, I would replace the definitions and handlers, not add to them. But I did not know how you would take to the idea and did not want to be presumptuous. (I did use the word "replace" in the issue.)
#4: Maybe I am missing a use case, but as I wrote above, I have found a good practice to use relation as the base table for the view. Then you have it and may not ever need to add it. If we do, or if we need a relationship from entity to endpoint, we can certainly add them.
Thanks for looking at this, both of you.
Comment #6
chx commentedWe are getting closer.
Comment #7
chx commentedThanks for the work, what we have in contrib works. To some extent. There are a few problems: you can't get to the relation table and you need to make that chainable , as a base table isn't enough because you can have E1-R1-E2-R2-E3. Also if you have node --> user then you can't get from user to anywhere.
Comment #8
solotandem commented@chx, regarding today's commits: line 74 in relation_handler_relationship.inc, the relation_handler_endpoint_endpoint_join class
I had the table alias as $r not $l and that was intended. The other endpoint table ($l in this case) has already been joined and on that earlier join you would be able to specify an r_index value for it. The r_index restriction on this join is intended for the new instance of the endpoint table being joined. I envisioned this being useful with n-ary relations where you might want endpoints 1 and 2 out of 0-3. This is not fleshed out. I have a case where we would want to extend the r_index != r_index while restricting the search to index values in a range.
For example, a 4-way relation from A->B<-B<-A. The r_index != r_index would be restricted to r_index IN (1,2). That is where I was going with this.
Comment #9
mustanggb commentedWas doing a "1->many" of "users->nodes" using a view of users and a "
Provides a relationship from @left(users) to @right(nodes) via the relation @relation_type_label" relationshipSince the 06/12/2011 4:24:44 pm commit this has been removed and it seems the replacement is meant to be "
@left(users) to the other endpoints(nodes) using the "@relation_type_label" relation"However this option is not appearing as a Relationship option in my view of users
Comment #10
solotandem commented@akamustang: The relationship definitions are being redone as indicated above. They are mostly there, although chx has remarked in IRC that a relationship from user to relation is not available. Can you redo the view starting from the relation and add relationships as follows?
- relation to endpoint
- endpoint to user
- endpoint to other endpoint
- other endpoint to node
The first relationship is in the "relation" group in the Views UI, while the others are in "entity" group.
If not, stay tuned for further commits.
Comment #11
mustanggb commentedAfter creating a relation view the only available relationships group was "Relation", there was not the option of "Entity"
Comment #12
chx commentedYeah there is no entity group (and solotandem thought of endpoints, anwyays). Everything is in the relation group. Read the title/description carefully, they tell you quite a lot. I also worked on them a lot to be so. Also, it's being heavily worked on, so within a short term it might be a lot better.
Comment #13
solotandem commentedAttached patch adds missing relationships:
- from endpoints to "left" entity.
- from entity to endpoints
Patch also adds documentation and (imho) clarifies the titles and labels on the relationships.
With these definitions, I was able to use the entity (node, user, etc.) as the base table to the view, and relate to the sibling endpoint entity.
Comment #14
dawansv commentedSeems to work for me now with this patch.
I have a directional relation called Participants between nodes (representing courses) and users. I wanted to have a view to pull the users attached a particular course; after some messing around, I was able to to it by creating the 3 following relationships:
Relation: Participants (endpoints -> user)
(Endpoints::Participants) Relation: Participants (endpoints -> endpoints)
(Endpoints::Participants) Relation: Endpoints: Participants (endpoints -> node)
EDIT:
In addition, I am now also able to do it directly from a view using the user table as its basis (instead of relation), so that's even better:
User: Endpoints: Participants (user -> endpoints)
(Endpoints::Participants) Relation: Participants (endpoints -> endpoints)
(Endpoints::Participants2) Relation: Endpoints: Participants (endpoints -> node)
Thanks
Comment #15
MeDAN commentedI'm using current version of the Relation module(15 dec). Are this patches are applied in my version ? Earlier I could get RID field, after update I can't get this field...
// Update
I can add only "endpoints" field. Fields like RID,VID, Relation Type, UID, Created etc. can't be added. I think it is caused table group name change but Im now an expert in Relation module.
Comment #16
solotandem commentedThe patch in #6 is in the latest code, but not the patch in #13.
Neither patch should prevent you from adding the RID field. Describe the structure of your view: base table, relationships, etc. You might move this to a new support request issue.
Comment #17
MeDAN commentedOk I created new issue -> http://drupal.org/node/1372956.
Any advice/patch/whatever is very important to me. I'm fighting with views in Relation for a long time. After each update I have new problems...
Comment #18
chx commentedThere's a whole + // Define join from entity to endpoints. section commented out. Also, there are no tests :(
Thanks for providing the missing definitions!
Comment #19
solotandem commentedAttached patch adds missing relationships:
- from endpoints to relation (not included in #13)
- from endpoints to "left" entity
- from entity to endpoints
I removed the commented lines, but still do not have any tests. :(
Comment #20
pdcarto commentedRe #14, I think I undertand the concept, but I don't see how to make the middle views relationship: the one going from endpoints -> endpoints.
In my case, I have students and organizations as node entities, and internships as relations. Internships have some fields like year (taxonomy) and final report (file field). I need to display a list of students and information about their internships (organization name, year, and final report). Not all students have internships, so I can't base the view off the internship relation.
Here are the three views relationship options I am currently seeing (I have applied patch #19):
Relation: endpoints[internship] -> node) Endpoints table to node using "internship" relation
Relation: interns with -> endpoints[internship] Relation table to endpoints table using "internship" relation
Relation: node -> endpoints[internship]) node to the sibling endpoints using the "internship" relation
Nothing obvious there about relating endpoints to endpoints. I'm not sure what the second one ("Relation table to endpoints table") does. Is that the "end points -> end points" views relation? I don't see an option to base it on the previously created node->endpoints.
Thanks
Comment #21
pdcarto commentedI figured #20 out - failed to clear views cache after applying the patch! It seems to be working - so far so good, anyway. Thanks!
Comment #22
howto commentedThe last patch at #19 work for me. But we need add "relation type" condition (column bundle of table "field_data_endpoints") on the first JOIN clause from endpoints to "left" entity.
Because between 2 entity type (or entity type:bundle) have many relation types so we must specific relation type for the select query
I try to create relationship from "endpoints ---> relation" and then filter by "Relation type" and "r_index" but the query omit entities (left side) if it do not have relation with "right side" entities instead of result in NULL
So, add "Relation type" condition at first join from endpoints to "left" entity will retain the entities (left side) that do not have relation with "right side"
---> JOIN clause in #19 comment <-----
LEFT JOIN {field_data_endpoints} field_data_endpoints ON A.id = field_data_endpoints.endpoints_entity_id
---> My JOIN clause <-----
LEFT JOIN {field_data_endpoints} field_data_endpoints ON A.id = field_data_endpoints.endpoints_entity_id AND field_data_endpoints.bundle = 'relation_type1'
Change in this patch:
1. Add join handler in relation.views.inc (relation_handler_endpoint_entity_join)
2. Declare file in relation.info
3. Define join handler class in file "relation_handler_endpoint_entity_join"
Comment #23
howto commentedIgnore #22 patch
Post lasted patch
Comment #24
tomogden commentedIt works perfectly, great job!
While it's true working with relations requires a rather complicated string of Views relationships (inner joins), it's really the best way to accomplish this. Maybe a training video should be in order.
Comment #25
mikran commentedI'm not quite sure if I'm on the map with the scope of this issue but my observations are the following(with a patch from #23): I have simple view listing users and I add new relationship user -> endpoints of relation type X. SQL as a result:
The relationships list shows these joins per relation type but the resulting query matches endpoints of all relations and all entity types. When you proceed from endpoints to relation or whatever the query can't make difference between user/1 and node/1 for example.
Only way to get the bundle added to query is by picking directional relation and then choosing position of the relationship base for it.
Comment #26
mustanggb commentedComment #27
howto commented@mikran
. I think this is not a appropriate way to get the correct result because the query will add bundle condition on the "second" field_data_endpoints table (regular alias "field_data_endpoints_field_data_endpoints")
Eg:
My view config:
The sql query is:
This query does not result the exact node:page that have relation with article (node/1) at relation type "article_to_page".

This is detail result run in phpmyadmin
Comment #28
mikran commentedOkay, here is a patch that fixes the scenario I had. These conditions probably have to be extended to endpoints -> endpoints joins as well.
The added file 'views/relation_handler_endpoint_entity_join.inc' is in separate patch file as I didn't figure out how to put it to same file.
Comment #29
mikran commentedWhitespace error fixed and now I figured out how to put everything into single file :).
Comment #30
mikran commentedSome more test results:
Chain:
1. entity -> endpoint (works)
2. endpoint -> endpoint (works)
-2.1 endpoint -> relation (does not work, uses entity_id whereas endpoints_entity_id is what we are looking for)
-2.2 endpoint -> entity (does not work, uses correct field 'endpoints_entity_id' but 'bundle' and 'endpoints_entity_type' are not included)
Comment #31
mustanggb commentedHow about this one then
Using #19 I have a directional relationship from All users bundles > Nodes of type test
Starting with a view showing Relations, relationships can be build and work fine
However starting with a view of Users no relationships (pertaining to this module) are available
Comment #32
chx commentedTo play nice with Views, it is enough to stick to the original implementation but move the logic into the query method of the relationship handler and use the Views API properly instead of DBTNG.
Comment #33
mustanggb commentedSo just to clarify
Does this mean that views integration has been rewritten and is now "playing nicely" again?
Comment #34
tomogden commentedI'm lost as well. Is there a follow up issue somewhere? What happens with the patches we've been running with that we need to make Relation work?
Comment #35
naught101 commentedI think this is chx's way of saying "fixed, but it a slightly different way". See commit e8e00ad
Comment #36
tomogden commentedConfirmed. I was able to make the view function using the latest version of the project, and it only required TWO relationships.
Comment #36.0
tomogden commentedAdd clarification.