When working on CRM Things I found that I really wanted to find everything that was related to a given entity, rather than just the first related entity. To that end I propose a new function called relation_get_related_entities that returns an array of related entities. relation_get_related_entity would then be a kind of wrapper that just returns the first thing in the array returned by relation_get_related_entities.

Here's a first patch.

Comments

rlmumford’s picture

And heres the patch

rlmumford’s picture

Status: Active » Needs review
StatusFileSize
new2.5 KB

Forgot to set status

Status: Needs review » Needs work

The last submitted patch, function_to_get_related_entities-relation-1288894-1.patch, failed testing.

rlmumford’s picture

Status: Needs work » Needs review
StatusFileSize
new2.53 KB

Seen a really obvious problem, so retest

naught101’s picture

Status: Needs review » Needs work

Hrm. I can see the use of such a function, but I don't think we can replace relation_get_related_entity() with it, because that would unnecessarily and massively increase the processing required on entities with many relations on them (think using relations as a replacement for taxonomy).

Then again, I don't really know why we have relation_get_related_entity() at all. It's only used in tests. We could probably replace it with something like your function, but that would require the ability to limit the number of relations searched for in the relation query, with EFQ::range().

rlmumford’s picture

So am I right in thinking we want a way of limiting which relations get returned from the query? Could we limit by the entity type and bundle? Or do we need to have loaded the relation before we can evaluate the end points?

naught101’s picture

Er, no. The query shouldn't return relations. It should return entities that are in relations with the given entity... We have relation_query for that, or at least, it wouldn't be hard to write a wrapper for it to load the relations.

Like said, I don't know what use the current function is, and before we introduce the new one, perhaps it'd be good to get an actual use-case to see how it'd be designed.

rlmumford’s picture

So a couple of use-cases for this function:

- In the Drupal CRM we have entities called Parties as our base contact type, and we use relation to like those Parties to Various profile2s. When we view a particular party we want to load every Profile2 that is related to that profile. At the moment we use a different relation type for every profile type (as this helps us avoids double rows in views) so for us it is enough to limit the endpoints by relation type - it would be nice to filter by the bundle of the endpoint though.

- If we use a relation type which is a Donation with a field storing the amount donated and we want to load every donation attached to a particular party, we need the function to load the endpoints, but also the fields attached to the relation itself. (In reality you would probably do this as a view on relations but I was trying to think of a use-case where you would want to have access to the fields attached to the relation)

naught101’s picture

And you're returning an array, keyed by relation id, of arrays consisting of all other endpoint entity objects? I was originally thinking it would make more sense to just return a flat array of all entity objects, but I'm not so sure now. Would mean you didn't have to do a double loop with the results, but I guess that's not a huge problem..

We'd definitely need to be able to limit it somehow though, whether by number of relations checked, or number of entities returned, I don't know (and would that count entities that appear in more than one relation?)

rlmumford’s picture

So the biggest problem (I think) for performance is going to be calling entity_load() more times than is necessary. Now, If we agree that it would be good to put entities in a flat array keyed by the *entity type*_*id* then we can very easily check whether that entity has already been loaded.

We probably also want to filter what entities get loaded as well, but I don't think its worth doing beyond filtering by type and bundle.

naught101’s picture

Key by "entity_type:entity_id" - entity types can have underscores in them.

This is beginning to sound more and more like an extension of relation_query...

rlmumford’s picture

yup, thanks...that was a silly mistake.

I don't think I've every even looked at relation query (or any of the db classes) in much detail. Will this be like a new method? Or a new class (say endpoint query)?

naught101’s picture

I think it would probably make sense as a new class extending RelationQuery with a different execute() method, but there might be a way to do it just as an additional set of methods/variables in RelationQuery... not sure.

adrien.felipe’s picture

I also needed to get all relations from an entity. But I needed the full relation data as I have fields on the relations and I need to read the data.
I also wanted them grouped by relation types in an array.

This the code that works perfectly for me. As I ran into this post, though I would share my it.

function mymodule_relation_get($entity_type, $entity_id, $relation_type = NULL, $r_index = NULL) {
  $query = relation_query($entity_type, $entity_id, $r_index);
  if ($relation_type) {
    $query->entityCondition('bundle', $relation_type);
  }
  $results = $query->execute();
  $result = reset($results);
  if (empty($result)) {
    return FALSE;
  }
  // Loop through each relation
  foreach ($results as $relation) $rids[] = $relation->rid;
  // Load all related entities endpoint references
  $raw_relations = relation_load_multiple($rids);
  
  // Reformat relations output.
  foreach ($raw_relations as $relation) {
	if (!isset($relations[$relation->relation_type])) {
		$relations[$relation->relation_type] = array();
	}
	$relations[$relation->relation_type][] = $relation;
  }
  
  return $relations;
 }
Chris Gillis’s picture

Component: Code » API

#14 works nicely.

naught101’s picture

No it doesn't: it returns relations. The original post is about returning entities.

I'm still luke-warm about this function, but if it's going to get in, then it needs to be a method on relationQuery, if not an extension of relationQuery. And it needs safeguards so that it won't kill a site by trying to load millions of entities.

sagacity’s picture

Issue summary: View changes

I was just running into this issue. After trying to implement relation_get_related_entities I saw, that I have to calculate twice. One time I have to create a huge array, and the other time I have to get the fragments again. So my approach was to use relation_query directly in my template. In the beginning I was not aware of how to use it, but after studying the helpful posts here, it was possible to do it. Even if this post is older than 3 years, maybe it's helpful for someone coming from seo (like me).

<?php
    // results from relation_query to get relation id
    $query = relation_query('user', $user->uid); // in my case I was searching for nodes related to specific user
    // filtering by "my_type", choose your relation type here or leave this line out
    $query->propertyCondition('relation_type', 'my_type');
    $results = $query->execute();
?>
<?php foreach($results as $result): ?>
    <?php
        // get relation object
        $relation = relation_load($result->rid);
        // get endpoints respectively entities of type "node" (related to specific user)
        $endpoints = relation_get_endpoints($relation, 'node');
        // first endpoint is just equal to node object
        $node = reset($endpoints['node']);
    ?>
    <?php print $node->title; // just print whatever you need ?>
<?php endforeach; ?>