views:

50

answers:

3

I am using an afterFind function to modify data from a find function. It works fine. If I move the afterFind function into a behavior (in a plugin) it still works, but only when the model of interest is the primary model, i.e. it isn't called when the model belongsTo another model. Is there any way round this? I'm using cake 1.3.4. This is a simplified version of the behavior:

class ChemicalStructureBehavior extends ModelBehavior {
    function afterFind(&$model, $results, $primary) {
        foreach ($results as &$unit) {
            // format chemical formula (with subscripts)
            $unit[$model->alias]['chemical_formula_formatted'] = preg_replace('/([0-9]+)/i', '<sub>$1</sub>', $unit[$model->alias]['chemical_formula']);
        }

        return $results;
    }
}
+2  A: 

I guess I'd do one of 2 things depending on how generically the code block applies:

  1. Universal version: not use a behavior, but include your method block in AppModel::afterFind
  2. Surgical version: use a behavior and attach it to each model that needs to share the functionality.
Rob Wilkerson
(1) doesn't work for me because it only applies to some, but not all, models. (2), is essentially what I'm trying to do, but it doesn't work when the model is not the primary model
Tomba
What I mean is that you'd _literally_ attach the behavior to every model for which you need the functionality. Behaviors aren't intended to operate against associated models.
Rob Wilkerson
Thanks. What do you mean by "literally attach the behavior to every model"?
Tomba
I just mean that associated models are still models. I'd have to verify against the code, but I _thought_ that associated models were retrieved via a separate call to the `find()` method of those models. If so, then attaching the behavior should cause the callback to fire for those.
Rob Wilkerson
On the other hand, independent `find()` calls on associated models could also open the door for some infinite loop hell, so it may be that this was avoided. I'll be curious to hear what you learn by doing.
Rob Wilkerson
@Rob I think you're right saying that "behaviors aren't intended to operate against associated models". I think this may be the same thing: https://trac.cakephp.org/ticket/2056
Tomba
As to what I'm doing, my example was a bit contrived - I realized that using a helper (which I put in my plugin) seemed to be a cleaner way of performing the kind of presentational logic I wanted. So I have abandoned the afterFind() function in my behavior... but I still imagine it could be useful in the future and I guess I'd still like to know how to do it should the need arise
Tomba
+2  A: 

A behavior isn't supposed to work on related models, for example, if you have this two models:

app/models/product.php

<?php

class Product extends AppModel{
    var $belongsTo = array('Category');
    var $actsAs = array('SomeBehavior');
}

?>

app/models/category.php

<?php 

class Category extends AppModel {
    var $hasMany = array('Product');
}

?>

SomeBehavior will only be executed when calling methods for Product, because the behavior isn't associated with Category

Mauro Zadunaisky
I've rephrased my comment.. I don't want it to work on related models, I want it to work on a model whether it's called as the primary model or not. In your example, I would associate the behavior with Category rather than Product, and I'd want the callback functions to be called whether Category is the primary model (/categories/view/1) or when it's called by product (/products/view/1). Currently, the behavior callback functions are only called in the former case. If I put the callback function in the Category model rather than in a behavior, it's called in both cases.
Tomba