I have defined several custom entities using hook_entity_info(). One of these entities has custom bundles. When using the Clean Entity processor, I retrieve no results when requesting an index of the entity type with the custom bundles. No results are returned. Entities that did not have custom bundles were not affected.
I narrowed it down to a section of code in plugins/services_entity_resource_clean.inc in the transform_values() method of the ServicesEntityResourceControllerClean class.
// Default the bundle to the entity_type. This allows eck types that don't use custom bundles to not have to specify the bundle.
$entity_info = entity_get_info($entity_type);
if (isset($entity_info['bundle keys'])) {
foreach ($entity_info['bundle keys'] as $bundle_key) {
if (!array_key_exists($bundle_key, $values)) {
$values[$bundle_key] = $entity_type;
}
}
}
This seems to be setting the bundle key to the entity type in the $values array for ALL entities with bundle keys.
For the time being, I have added a check to this to correct the problem.
// Default the bundle to the entity_type. This allows eck types that don't use custom bundles to not have to specify the bundle.
$entity_info = entity_get_info($entity_type);
if (isset($entity_info['bundle keys'])
&& (count($entity_info['bundles']) == 1 && key(reset($entity_info['bundles'])) == $entity_type)) {
foreach ($entity_info['bundle keys'] as $bundle_key) {
if (!array_key_exists($bundle_key, $values)) {
$values[$bundle_key] = $entity_type;
}
}
}
I've tested this for custom entities with custom bundles, custom entities without bundles, and entities generated by ECK, and all seem to work for me.
Patch incoming.
Comments
Comment #1
nhepner1 commentedPatch!
Comment #2
joachim commentedLooks good. Let's see what the testbot says.
Though I do think this could be considered a bug in ECK. This is what entity_get_info() does:
so I would expect ECK to set a bundle key and therefore trigger this behaviour.
Comment #4
joachim commentedTurns out our tests are broken :(
Comment #5
joachim commentedCould you roll this from the module folder please?
There are coding standards being debated for this: #1539712: [policy, no patch] Coding standards for breaking function calls and language constructs across lines. Those would call for extra indentaion. Or you could put it all on one line. Either is fine with me :)
Comment #6
that0n3guy commentedAttached is the patch re-rolled. I think I did it right.
edit: I just re-rolled to the module folder... not the second half of the post above.
Comment #7
nhepner1 commentedsorry about that - thought I did roll it from the module folder. Thanks @thatOn3guy for the assist!
Comment #8
joachim commentedI think there's a bigger problem in this code that we should fix here:
Compare with http://api.drupal.org/api/drupal/modules!system!system.api.php/function/...
- There should be only ONE entry in $entity_info['bundle keys']. Iterating over that is pointless.
- Much more major, the key name that is given by $entity_info['bundle keys']['bundle'] has **NO** business being present in entity values:
That means that it is the name of a key on something such as a 'node type' object. Nothing to do with what we have here.
I *suspect* what is really meant here is ['entity keys']['bundle'], but as I don't use the clean processor, I don't know.
Comment #9
nhepner1 commentedIf there was more than one value being assigned to $values[$bundle_key], I would agree with you, but it's not creating an Array of $values[$bundle_type] to search against, suggesting that it's forcing only one value.
My thoughts:
I think this block of code is unnecessary.
This is a limiter - it sets an array similar to array('type' => 'entity_type_name'); and adds it as an EntityCondition and makes an assumption that the limiter needs to be applied. In my testing, I have not seen any reason as to why this is the case, as entities generated by ECK still work with this when this section is commented out. It should be noted that the Generic Entity Processor does not do this. As far as I can tell, this section does not "enable" anything or correct any functionality that is not already working.
In the event that someone wants to request a specific type, they should set the param[type]=entity_type_name in their request. It should not be assumed by the application.
I put the patch together in a way that worked for my purposes, by creating an exception around my usage, but didn't nuke the code in the event that there was something going on with it that I'm not seeing. I tested with this section commented out, and single-bundled eck entities still seem to work.
Any thoughts?
Comment #10
joachim commented$bundle_key has still absolutely no business being set in $values.
It's like saying that you have $node_type->foobar and therefore you expect $node->foobar. The two are simply totally unconnected.
I'm not entirely clear on what this function as a whole is meant to do. It's getting called for create, update, and index. Index won't need a bundle setting: if there is only one bundle, that's all you get. It's fairly likely that creating an entity that defines a bundle key will need this set: all sorts of thing in Entity API crash without a bundle key set.
This code is not going about it the right way though.
Comment #11
tom friedhof commentedI agree with nhepner1, this code looks like it's compensating for something in ECK. If someone wants to request a specific type, they should do so explicitly. Here is another patch nuking that code all together.
Comment #12
tom friedhof commentedsetting to needs review
Comment #13
joachim commentedI don't mind this code being there. It's nice DX sugar.
It just needs to be coded correctly! :)
The right logic is:
- is there only one bundle?
- get the bundle key (NOT the 'bundles keyS'!!)
- set it to the entity type (or, to be really sure, pop off the first and only key of the bundles array)
Comment #14
joachim commentedComment #15
wodenx commentedAttached patch is a revised version of that posted at #2068463: Improper use of 'bundle keys' in "clean" controller..
It implements the logic described in #13. Further, it removes this logic from transform_values() and puts it into create(). This is for 2 reasons:
1. We need to have the wrapped entity in order to check the bundle key, since the metadata property name might differ from the bundle key (e.g., for taxonomy, "vocabulary" vs "vocabulary_machine_name"), so we can't just check for it in the provided values.
2. transform_values() is called in 3 places - on "create", "update" or "index" -- for "index" we certainly don't want to but an invisible filter by bundle into the query (this was causing a related issue at [#1890068}, and for "update" we probably don't want to be changing the bundle anyway.
Comment #16
wodenx commentedComment #17
joachim commentedCould we get this info back in please?
Comment #18
wodenx commentedPlease see also #1890068: "No entities found." on index call. This patch should resolve that issue as well.
Comment #19
wodenx commentedre #17 - well, we do have:
Do you think we have to mention eck explicitly? This little bit allows any single-bundle entity to be created this way, not just eck.
Comment #20
joachim commented> This little bit allows any single-bundle entity to be created this way, not just eck.
Most single-bundled entities don't have a bundle key, so it's an ECK peculiarity I think!
We can word is so it's '... such as eck'. But it's nice to have some justification for what will look odd in future when we've forgotten about this.
Comment #21
wodenx commentedMade the wording change above and committed, along with a test which fails without the patch.