Closed (fixed)
Project:
Drupal core
Version:
7.x-dev
Component:
comment.module
Priority:
Major
Category:
Bug report
Assigned:
Reporter:
Created:
11 Oct 2010 at 17:24 UTC
Updated:
19 Nov 2010 at 20:00 UTC
Jump to comment: Most recent file
function comment_entity_info() {
$return = array(
'comment' => array(
'label' => t('Comment'),
'base table' => 'comment',
'uri callback' => 'comment_uri',
'fieldable' => TRUE,
'controller class' => 'CommentController',
'entity keys' => array(
'id' => 'cid',
'bundle' => 'node_type',
'label' => 'subject',
),
As you can see, we define the bundle key as "node_type". However, that column doesn't exist in {comment}.
So, EntityFieldQuery tries to select the column, chokes and dies.
| Comment | File | Size | Author |
|---|---|---|---|
| #32 | 938462.patch | 6.96 KB | bojanz |
| #29 | fail.patch | 4.45 KB | bojanz |
| #29 | 938462.patch | 6.95 KB | bojanz |
| #22 | 938462_1.patch | 3.98 KB | bojanz |
| #22 | 938462_2.patch | 2.54 KB | bojanz |
Comments
Comment #1
bojanz commentedHere's a simple patch removing that key.
Let me know if an alternate approach is needed.
Comment #2
chx commentedThat's obviously braindead. But why do we have a core that passes all tests?
Comment #3
bojanz commentedThee hook_entity_info docs for ['entity keys']['bundle'] say: This entry can be omitted if this entity type exposes a single bundle.
However, the comment module does expose multiple bundles (one per node type), so the whole thing is just odd.
The key should be in the table, but it isn't, and it isn't used.
But then again, this is my first time looking at comment.module
So, the test would be:
1) Load all modules
2) Load every entity type
3) On each entity type, do an EntityFieldQuery. If it doesn't die, it's cool.
EDIT: And the patch breaks comments completely, so the approach might be wrong ;)
Comment #4
bojanz commentedThis is actually a bigger problem than EntityFieldQuery not being able to query comments.
The comment entity type exposes bundles, has a bundle key, but that bundle key (node_type) is not stored in the database, but calculated in the entity controller instead (by joining {comment} with {node}, getting it's type, and prepending "comment_node" to it). This is plain retarded.
Let's try and do this properly.
1. Added node_type to schema.
2. Added update function that adds the new column and fills it with data.
3. Removed extra join and node type calculation from the comment entity controller.
Comment #5
chx commentedThis can not be supported. The bundle for taxonomy_terms are the vocabulary machine name however the taxonomy_term_data table only has a vid. Comments store their bundle in node. Both use a custom entityload class to assemble the entity and indeed the entity documentation talks of object properties not database keys. The only solution is to remove bundle support. Ppl using EFQ can use propertyCondition vid for terms and... they are screwed on comments. Such is life. There is no way to help that in Drupal 7 core. A contrib can do a schema alter and do the denormalization.
The rest should be ok, entity type, entity id and revision id these are ok but bundles are not.
Comment #6
chx commentedtaxonomy_vocabulary_machine_nameinstead ofvocabulary_machine_name.Phew! We saved the bundle with minimal API change and empowered the whole system with information.
Comment #7
catchDiscussed this in chx with irc, the above plan is option #4 of these:
I think that's the best at this stage of the cycle. We need a Drupal 8 issue to figure out a standard for entity bundles (if I remember correctly there was some resistance to storing bundles as strings for taxonomy terms and comments due to the extra storage, queries on ints are more efficient etc., but is that worth the tradeoff to avoid issues like this).
Comment #8
rszrama commentedI don't see addressed above the possibility of simply documenting the limitation for Drupal 7, i.e. that you cannot use EFQ::propertyCondition() on Comment or Term bundles. Based on the inline documentation, I see two things that would make this a reasonable plan of action:
That said, it seems like a fix is preferable. Just wanted to point out that this isn't a technically "unexpected" bug... maybe just an unintentional limitation.
As to applying chx's solution, it seems like it would work. It's uncomfortable, though, to introduce a JOIN based on a naming convention and the use of foreign keys. I suppose it's the least invasive solution where we are now, but it's going to result in some unwieldy API documentation. : P (This should also be accompanied with documentation in the term and comment schema to indicate altering the foreign key definitions would break EFQ::propertyCondition().)
I suppose at the very least we have core examples to point to, but really we can just say any other entity developers should just make sure the bundle has a column in the entity's base table.
I think, too, that bojanz inadvertently raised a related issue above... that of entities that are defined as single bundle entities. In the case of the commerce_order entity, I don't define a bundle entity key and through trial and error found out this means my entity will have a single commerce_order bundle. Now, there is no column in my commerce_order table for the order type, so it seems the EFQ::propertyCondition() won't work for me here anyways. Maybe it's never supposed to work to query based on bundle if there is no bundle entity key. But what if a contributed module alters the entity info, adds a bundle key, creates an order types table, and then uses a third table to relate orders to their order type (i.e. instead of altering the schema to add a column onto the base commerce_order table) and alters the orders on load to include their type. The proposed solution cannot accommodate that, and shouldn't... the documentation for the $column parameter sets that expectation.
In other words, even with the fix, it can still be broken, and unless I'm misunderstanding EFQ (which is quite likely) still won't accommodate entities that don't support bundles. That might tilt this toward "don't fix, document the limitation", but if the fix is preferable for other reasons, then chx's suggestion would work, should be documented, and the method should be discouraged until the problem can be removed in D8. How exactly it should be removed for comment bundles if not just storing the type in the comment table is a little beyond me this late in the evening. ; )
Comment #9
chx commentedIf your entity type does not have a bundle then dont specify a condition on bundle :) piece of cake, there. But the fix for comment, taxonomy_term and any other entity type that follows the core example of storing the bundle in another table is necessary IMO.
Comment #10
rszrama commentedWould it be worse to introduce something other than a [table]_[field] naming convention that gets checked as a fallback? i.e. what if you could specify a bundle entity key of [field] (the regular definition), or [foreign_key]:[field] (which finds the table the foreign key, joins on the key, and adds the [field] to the query)?
Of course, I'm not sure if : is any better (could get even more creative and use ->), but at least people wouldn't normally be using : in bundle names (whereas they're most likely already using _). Also, even if the _ is kept, I wonder if specifying the foreign key outright wouldn't be preferable to specifying a table and then searching the foreign keys for that table. In this regard, you could actually do away with step 1 in chx's solution and instead change the bundle entity key for comments from node_type to comment_node_type (or comment_node:type).
Comment #11
rszrama commentedHmm, of course you can't use a : if you expect the bundle entity key to be a property on the loaded entity... duh. However, perhaps you specify the foreign key to use for the bundle somewhere else in the entity's info array. Just musing... point about referencing the foreign key instead of a table name would still stand.
Comment #12
fagoWe actually miss information about the bundle object here. If we would have the bundle 'db table', it could check for the "bundle keys | bundle" property and query for that using the foreign-keys info. Let's just make any storage-object an entity for d8 so we have a proper and unique place for info about it...
Still, comments and terms are a bit different now. Terms use the usual "entity object - bundle object - bundle name" approach, while comments go directly with the on load determined "node_type" property. It might work to translate the comment case to "entity object - bundle object - bundle name" too, with using "node" as bundle object and "type" as bundle key.
Then for d7, we would just need something like a "bundle db table" property.
Let's not magically bake more information in a single info-key. The 'entity keys' are about the object properties, if we need information on how to find the property column in the DB, that's something different and thus it should be another info key.
Comment #13
bojanz commentedInteresting discussion. We definitely need to fix bundles in D8.
Right now, the main problem is that EFQ gives a fatal error if the bundle column is not present in the table even when we have no entityCondition on bundle!
This is because the defined entity keys (such as bundle) are always added to the query in propertyQuery(), even when not used in a condition or an ordering.
The field_sql_storage query builder doesn't have this problem.
This is not a hard thing to fix. We just add an additional check that peeks into the base table schema.
As for the proposed solution with joins, I'm not really a fan of adding hacks to the code for this. Feels a bit wrong.
I'm much more inclined to agree with the previous chx's comment:
We document that those two are problematic like Ryan suggested, and revisit it for D8.
Changing status, since the previous patch is not really getting us where we need to be.
EDIT: Just saw fago's comment, I see that he too is weary of the proposed approach. An additional key might not be a bad idea though, even though it's still a hack.
EDIT2: Also, shouldn't that be "Make EntityFieldQuery entityCondition bundle work"?
Comment #14
amitaibu> Then for d7, we would just need something like a "bundle db table" property.
I wonder if it this property doesn't connect too tightly the idea of an abstracted entity that "doesn't care" about it's storage, to the DB?
Comment #15
fago>I wonder if it this property doesn't connect too tightly the idea of an abstracted entity that "doesn't care" about it's storage, to the DB?
The whole EFQ-entity-query "backend" is db specific, just as the default drupal entity controller. This properties are used by the db-specific implementations, you still can do others. Though I'm not aware of anyone having done that already?
Comment #16
catchThere are not many use cases for bundle queries on comments. Recent comments on a node type would often use node_comment_statistics since that gets you just one comment per node. The vid on terms is fine. We can't drop it for nodes. So documenting the limitation seems good here. Well that and fixing the fatal error.
Comment #17
chx commentedbojanz then let's fix EFQ not to error out and document. Let's do the absolute minimal necessary.
Comment #18
bojanz commentedI'm on it. Still fighting the flu, should have something tomorrow.
Comment #19
bojanz commentedI suck.
Anyway, here's are two possible options. Feel free to massage the docs in the comments bellow.
1) In patch #1:
If a user (developer) specifies an entityCondition('bundle') or entityOrderBy('bundle'), and the resolved column doesn't exist in the db, he gets an exception.
That's more developer friendly.
2) In patch #2, he just gets an sql error. We don't hold his hand for wrong property names, so why do it for bundles?
I'm for #2, but since I wrote #1 first, i thought I'd give it up for consideration as well.
Comment #20
bojanz commentedComment #22
bojanz commentedOnce again, now a bit smarter.
Comment #23
chx commentedCalling that variable having is a really bad idea. Anything else is a lot better. bundle_present or whatnot. But having is a SQL keyword and superb confusing.
Comment #24
bojanz commentedThat variable was there before me. And true, it's a bit confusing.
However, I don't think it's that bad, since propertyQuery() is tied to the SQL database...
Generally, isn't patch #2 preferable anyway? and it doesn't touch $having at all...
Comment #25
chx commentedI suspect yes. http://drupal.org/files/issues/938462_2_0.patch is indeed RTBC.
Comment #26
chx commentedWe can try harder. Field tables store bundle. (MongoDB also does. It's somewhat mandatory for fields to store it because they have no clue whether there is such a thing as an entity base table.) We have an entity type and a bundle here...
field_info_instances($entity_type = NULL, $bundle_name = NULL)can deliver us the instances and then we can bring the table of any instance in. Is this something we want to do?Comment #27
chx commentedDiscussed with bojanz and we both agree that for Drupal 7, we still want to go ahead with the simple patch indicated above. It'd be a hack to join in a random field table.
Comment #28
bojanz commentedWe agreed on IRC that this should get a test.
Test scenario:
1) Define an entity type that specifies a bundle key not present in the database
2) Do a query. Any query. Check that it succeeds.
We run the test without the current RTBC patch, it fails. We apply the patch, run the test again, it succeeds.
Comment #29
bojanz commentedHere we are.
New patch, plus a patch with just the test changes (which should fail).
The test modifies the rarely used test_entity_bundle entity_type to behave like comment (bundle specified, added in a controller, not present in db).
Also, I sneaked in a change to EFQ tests that catches exceptions, so that we get a nice 1 test fail, and not everything aborted.
Comment #30
bojanz commentedThis should be Controller class for the test_entity_bundle entity type., but let's see first if there are other things that need to be changed...
Comment #31
chx commentedThat looks good. I would have sworn we fixed that test already like that... good job.
Comment #32
bojanz commentedProviding the wording fix mentioned in #30.
Everything else is the same, so this goes back to RTBC after the bot gives it a go.
Comment #33
bojanz commentedComment #34
dries commentedCommitted to CVS HEAD. Thanks.