I need to be able to pass arguments to the description callback function in hook_userpoints_info. A patch is attached. My use case is demonstrated by the following snippet:
<?php
/**
* Implements hook_userpoints_info().
*/
function userpoints_flag_userpoints_info() {
$info = array();
foreach (flag_get_flags() as $flag) {
$info['userpoints_flag_' . $flag->name] = array(
'description callback' => 'userpoints_flag_description_callback',
'description arguments' => array(
'flag_title' => $flag->title,
),
);
}
return $info;
}
function userpoints_flag_description_callback($operation, $entity, $arguments) {
$params = array(
'%flag' => $arguments['flag_title'],
'%label' => entity_label($operation->entity_type, $entity),
);
return t('%flag: %label', $params);
}
?>
Comments
Comment #1
berdirHm. Yes, need something like this.
I'm not yet sure if we should do dynamic operations like this or instead find an alternative solution like being able to pass an array of possible sub-operations in. For example, userpoints_nc defines 6 or so different operations for nodes and comments. We need a way to separate node types too but when there is an operation for each node type and you have, say 20 node types (not *that* uncommon), you end up with 12 * 20 = 240 defined operations just for that.
Another place where we need to be able to do that separation is the planned flood control feature, that allows you define per operation how many transactions/points you can earn in a timeframe. You might want to combine all or multiple flags/content types/whatever there (wildcards might also work to a certain degree).
FYI: You could also load the flag title based on the flag name which is part of the operation string to have something working while we're discussing this.
Comment #2
gilgabar commentedWould it really be necessary to separate operations by node type? That information is already available via the entity object. So for any given transaction you should be able to figure that out pretty easily.
The flag example would appear to be a different case. The entity in question is the thing being flagged, so the only way to pass any context about the flag itself to the hook is via the operation. There should actually be more operations per flag to pass along information about whether it was a flag vs unflag, and whether it was for the user doing the flagging vs a flagged user or node author, so, to a lesser degree, it would end up with a situation similar to what you are describing with nodes.
The root of the problem, from the perspective of the flag example, is that where in 6.x you had access to all the relevant data that you would care to use when creating a description - because it was created directly in the call to userpoints_userpointsapi() - in 7.x when the description is created after the fact, you no longer have access to any data that was not saved as part of the transaction, and so are forced to cram anything you might need in to the operation name, or as is the case with the original post, try to pass in derived data via arguments, or otherwise reconstitute it as you suggest.
I certainly see the advantages of the new approach and it sounds like you have plans for the hook beyond its current role as a poor man's theme registry, so I wouldn't suggest switching back. I don't see any elegant solutions to the general problem at the moment, but as a simple half-measure description arguments seem reasonable.
Comment #3
berdirThe additional information is not really supposed to be used in the the description callback but by another module. See #985948: Create a "Flood control" sub-module to limit points that can be added/deducted over a configurable amount of time. And that module needs to a generic way to access this information, it doesn't know if there is a referenced entity, what it is and what the possible values are. The idea there is to build a an UI where you can configure something like "Users are able to earn 100 points by creating nodes of type A and B each day.". We're still in the planning phase there, so that might or might not fly in the end...
And you are right, the new hook does have it's own problems too. But when thinking about i18n, I can't think of any other way to make it work.
I think there are also other cases where putting more information (flag/unflag, user/author, flag type in your case) into the operation makes sense, one example is Rules. That allows you to configure rules which apply to a specific transaction type only.
Comment #4
gilgabar commentedIn the case of flood control you could still probably get away without node type specific operations. If the flood control UI allows you to select a combination of operation and node type, with the operations being the existing insert, update, etc, then you should be able to check that against the node/operation combo used at the time of point assignment. Is there some part of that that would not work the way I'm imagining?
Re: the i18n stuff, I believe the watchdog module has an alternative approach that you may consider. The message text and the variables are stored in separate columns, rather than storing the rendered string in one column.
Comment #5
berdirFlood control: Node types was just one example. The problem is, the flood control api/UI must work for all kinds of userpoints transactions, we want to limit received points, not nodes/comments. So we need a way to map node types to something that flood control module can work with.
i18n: Yes, that is another approach. The problem with that is that automated translation string extraction only works for specifically defined functions like t() or watchdog(). So it wouldn't be possible to translate these strings on translate.drupal.org unless we trick the system (by adding faked t() calls for example) or by adding support for userpoints_transaction() to the potx project (which is unlikely to happen because it would be very complex to parse our one-big-array-argument).
Anyway, I will commit your patch as soon as you post an updated one that updates the hook documentation in userpoints.api.php. I'm not yet sure when the flood control stuff will happen and this fixes a problem that we have now.
Comment #6
BenK commentedSubscribing
Comment #7
manuel.adanCurrently, there are no plans to improve the 7.x branch of this project with new features. Closing this by now as outdated. Please, feel free to reopen if you want to work on it.