How can I prevent endless recursion with Drupal's node_load()?
I'm using the Ubercart product and product_kit modules. This is great at linking from the relevant product kit to the products which are included, but I also want to link from the individual product to any kits it may be part of.
I figured I could do a database search on the SKU/Model number (got that part done easily), and then use node_load($nid) to get the related kit.
I have this so far:
function amh_shop_nodeapi(&开发者_StackOverflow社区$node, $op, $a3 = null, $a4 = null)
{
if ($node->type == 'product') {
if ($op == 'load') {
error_log("product::load");
$bundles = array();
$results = db_query('SELECT DISTINCT n.nid FROM {node} n RIGHT JOIN {uc_products} up ON up.nid = n.nid WHERE up.model LIKE "%s /%" OR up.model LIKE "%/ %s /%" OR up.model LIKE "%/ %s"', $node->model, $node->model, $node->model);
while ($bundle = db_fetch_object($results)) {
error_log("bundle::load");
$bundles[] = node_load($bundle->nid);
}
}
}
}
But, because the product kits are also loading the products, I end up in a recursive loop.
I guess my question actually comes in two parts:
The question that is the title of this post: how do I prevent this recursion?
Slightly different question that probably answers the first one anyway: should I be doing this when the node is being loaded, or later in the process (for example, at view or alter)?
Hey there is a module called http://drupal.org/project/contemplate. They had a similar problem of recursion within that module, but they figured out a workaround for it by setting a recursion_limit.
I am not sure if it solves your problem, but it will definitely be worth going through their module and search the code for contemplate_max_recursion_depth. That might give you some pointers.
Hope it helps..
One of solutions, just don't call node_load for product_kit, so it will not call node_load for subproducts, query need datas manually via db_query:
function amh_shop_nodeapi(&$node, $op, $a3 = null, $a4 = null)
{
if ($node->type == 'product') {
if ($op == 'load') {
$bundles = array();
$results = db_query('SELECT n.nid, n.title FROM {node} n INNER JOIN {uc_product_kits} k ON n.nid=k.nid WHERE n.product_id=%d ORDER BY n.title', $node->nid);
while ($bundle = db_fetch_object($results)) {
$bundles[] = l($bundle->title, 'node/'.$bundle->nid);
}
}
}
$node->amh_bundles = $bundles; // Here's array of links to product_kits
}
What about this: It introduces a recursion variable check.
function amh_shop_nodeapi(&$node, $op, $a3 = null, $a4 = null)
{
static $recursion_nid = NULL;
if ($node->type == 'product') {
if ($op == 'load') {
error_log("product::load");
$bundles = array();
$results = db_query('SELECT DISTINCT n.nid FROM {node} n RIGHT JOIN {uc_products} up ON up.nid = n.nid WHERE up.model LIKE "%s /%" OR up.model LIKE "%/ %s /%" OR up.model LIKE "%/ %s"', $node->model, $node->model, $node->model);
while ($bundle = db_fetch_object($results)) {
error_log("bundle::load");
if (isset($recursion_nid) && $recursion_nid == $nid) {
// recursion detected
}
else {
$recursion_nid = $node->nid;
$bundles[] = node_load($bundle->nid);
unset($recursion_nid);
}
}
}
}
}
you should consider cacheing data like this. If you're loading it all the time it could really drain resources. I would consider a custom module that can store a relationship between individual projects and associated kits.
精彩评论