Support for Drupal 7 is ending on 5 January 2025—it’s time to migrate to Drupal 10! Learn about the many benefits of Drupal 10 and find migration tools in our resource center.
The current relation_data schema is
relation_id entity_type entity_id
and I wondered why it's not
relation_id source_type source_id target_type target_id
...unless naught101 mentioned that there's a possibility for n-ary relations; i.e., not a 1:1 relationship but 2 to X entities in a single relationship.
That sounds worth to document.
Comment | File | Size | Author |
---|---|---|---|
#39 | relation-HEAD.field_.39.patch | 1.05 KB | sun |
#37 | relation-981364-field-37.patch | 932 bytes | naught101 |
#35 | relation-981364-35.patch | 7.82 KB | naught101 |
#34 | relation-981364-34.patch | 8.09 KB | naught101 |
#33 | relation-HEAD.field_.33.patch | 7.57 KB | sun |
Comments
Comment #1
naught101 CreditAttribution: naught101 commentedThe current schema also allows simple descriptors (one to none relationships), eg. the_earth:is_round
The thing I don't understand is that the two rows don't appear to describe the way that the entity relates to the relationship? eg. which is the subject, which is the object? Or is that in a different table?
Comment #2
chx CreditAttribution: chx commentedBecause such a schema would be directional, the current one is unidirectional. Same for #1. We do not have any directionality right now. We can add if we want but note it's much easier to add a flag which one is which than creating an unidirectional module once you have a directional (aka nodereference and backreference).
Comment #3
naught101 CreditAttribution: naught101 commentedFlags make sense in the relation_data table. I can think of four possible flags: source, target, auxiliary (n-ary relations), and none/self (descriptors eg. node1:isPublished).
Maybe the latter is out of the scope of the project. There is also another possibility: auxiliary values that aren't entities - eg. scalars.
I'm not sure if the latter few should even be in this table, since they're gonna be fields. Is that gonna be a separate table? if not, this table would probably have to get much more complex, right?
Comment #4
naught101 CreditAttribution: naught101 commentedI don't understand why the relation table exists? If relation defines bi-directional relationships, and a directional predicate always has a logical opposite, would it make more sense to have the predicates in the relation_data table? That way you could have :
Then again, maybe it's best to leave the predicate in the relationship_type table or what ever it turns out to be called, and just have the reverse-predicate as a field or something. see #981398: Bundle creation and UI
Comment #5
naught101 CreditAttribution: naught101 commentedAs sun pointed out in skype, the current schema has no way of supporting revisions. I don't think we can just let field API deal with the storage, because that makes the unidirectionality difficult to deal with, right? Maybe we can add a revision id to this table as well? And that would require a revision id in the relationship table as well, right?
Comment #6
sunThe lack of revisions worries me. Indeed, Field API already has a built-in concept for handling field revisions, but since we are actually not storing any field value (yet), the field's tables are basically empty (except for Field API's internal values).
Of course, one option would be to simply duplicate (i.e., store a unused copy of) the relation data in the field's values.
However, in an ideal world, we'd directly use the field storage as primary storage for the relation data, but I'm not sure whether that is possible to do. Technically, the schema isn't too different --
entity_id
already exists,entity_type
basically exists viaetid
(entity type ID) already, but could as well be added as-is to the field's schema, andrelation_id
would definitely be a relation field's schema column.Since relation types will be (bound to) fields anyway, this really sounds worth to investigate.
It's not only about revisions, but also about query performance. If the data for a specific relation type is contained in a dedicated table (which exists anyway), then lookup queries are going to be faster. Furthermore, field values already have a built-in concept of language; i.e., users would additionally get the possibility of different relations per language for free.
Comment #7
chx CreditAttribution: chx commentedComment #8
chx CreditAttribution: chx commentedWe can remove the entity-ness and piggyback on the combofield/multigroup/whatnot http://drupal.org/node/939836
Oh and this solves the bundle discovery problem we had -- you can only relate to bundles the user already attached the relation to.
Comment #9
naught101 CreditAttribution: naught101 commentedbaby steps.
Comment #10
naught101 CreditAttribution: naught101 commentedhook_field_presave() implementation
Comment #11
naught101 CreditAttribution: naught101 commentedThis just stops the previous patch from breaking on page loads (there's some empty item in there that I don't understand..). Too braindead right now. will pick it up again tomorrow.
Comment #12
chx CreditAttribution: chx commenteda) i think relation_field_is_empty should check for relation_id b) the widget should use #type value not #type hidden
Comment #13
sunQuite mind-blowing. Not much better, but at least some progress.
Comment #14
sunSleeping over this, I realized that we still don't have proper field data revisions with this, but we can fix that easily (and possibly simplify even more code).
Problem space:
The field data does not contain any information about what has been referenced. Likewise, the field data revisions don't contain that either.
AFAICS, this is easily resolvable by adding
entity_type
andentity_id
to the field schema of the relation field type.Thus, each field $item in an entity fully describes the relation.
Actually, it even looks like that would additionally simplify our field loading -- potentially even removing the need for that crazy double-self-join.
Comment #15
sunWhen ignoring n-ary relationships, then there wouldn't be a change in storage:
As visible, each field item would fully store the entered information. Thus, every field revision would be self-contained, allowing admins to figure out (diff) the actual change between revisions.
I'm aware that this imposes problems. Food for thought, and probably, a conf call.
Comment #16
naught101 CreditAttribution: naught101 commentedOther possibility, with fielded relations.
This obviously fucks up the relation_id concept a bit, but it wouldn't be hard to add a top level relation id, parent_id perhaps (which would just be = 1 in this example). This shouldn't event be too hard for more than one level of relation hierarchy (which I think should never, ever happen. At least not without some kind of punishment).
Comment #17
naught101 CreditAttribution: naught101 commentedwith stuff added to schema. Works without hook_load(), but the presave isn't working..
Comment #18
naught101 CreditAttribution: naught101 commentedThis fixed some stupid mistakes, and definitely puts the field data into the target entity correctly, but it's not saved to {field_data_[field_name]}.
Do we need to do something more than just save it? Trigger field storage somehow?
Comment #19
naught101 CreditAttribution: naught101 commentedThis, combined with the workaround at #988780: Merge both modules into one causes an infinite loop
[entity1]_save() -> hook_field_presave() -> [entity2] -> hook_field_presave() -> [entity1] -> etc.
my loop check doesn't work, I guess because it never actually saves either entity. So we might need to pass a recursion depth flag, but I'm not sure where.
Comment #20
naught101 CreditAttribution: naught101 commentedHuh. A recursion-depth flag won't work, because if you have other relations attached to the target, they will recurse (separately) on save, so there's still a potential for very large loops. possibly infinite, not sure.
Comment #21
naught101 CreditAttribution: naught101 commentedok, this works. set $target->recursion, and then just don't do anything if that's set in $entity next time around.
works for nodes, but apparently not for users... hrm..
Comment #22
naught101 CreditAttribution: naught101 commentedfix a couple of mistakes things, make code more self documenting.
Pretty sure user_save() doesn't accept $user objects with programatically added fields. this may be a problem.
works perfectly with taxonomy terms and nodes.
Comment #23
sunSo here we go! :)
Note: db_next_id() still has to be moved from the field widget code into the field presave hook. We're needlessly incrementing IDs whenever the widget is displayed currently ;)
Comment #24
sunFixed db_next_id() issue, which directly fixes a data integrity problem.
Comment #25
sunSlightly fixed field schema column definitions.
Comment #26
sunKilled relation_get_possible_targets(), since field instance information is fully available in $field already.
Comment #27
sunIntensively reviewed and discussed with naught101, and we think that this is a big milestone in the progress already, so...
Thanks for reporting, reviewing, and testing! Committed to HEAD.
A new development snapshot will be available within the next 12 hours. This improvement will be available in the next official release.
Comment #28
aidanlis CreditAttribution: aidanlis commentedAwesome! Well done guys!
Comment #29
sunComment #30
naught101 CreditAttribution: naught101 commentedyep, fine for now. we neet to discuss #989264: field columns are VERY confusing as well though
Comment #31
sunUntested.
Comment #32
sunOther FTW! ;)
Comment #33
suns/target/other/
Comment #34
naught101 CreditAttribution: naught101 commentedchange empty check back to other_entity_id because relation_id is empty, doesn't get filled until presave.
also, add relation_id to $item by reference, otherwise SQL error.
Comment #35
naught101 CreditAttribution: naught101 commentedonce more without debugging stuff..
Comment #36
naught101 CreditAttribution: naught101 commentedfixed: http://drupal.org/cvs?commit=459424
Comment #37
naught101 CreditAttribution: naught101 commentedDamn. last patch introduced a bug - last
&$item
in the for look stays set, and so gets garbled later. Changed the name of a the later variable to $other_item, but perhaps the reference should be unset/not used in the first place?Comment #38
naught101 CreditAttribution: naught101 commentedFixed. http://drupal.org/cvs?commit=459760
Comment #39
sunThe committed code differed from the patch here, and contained a coding style flaw.
Comment #40
naught101 CreditAttribution: naught101 commentedfixed at http://drupal.org/cvs?commit=468756