cakephp behavior afterFind not called on related models
Asked Answered
W

3

6

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;
    }
}
Workhouse answered 26/10, 2010 at 22:5 Comment(1)
From PHP 5.4 and up, you could use a Trait for this - just put your afterFind() code into a new file containing the trait declaration (changing $model references to $this) and include it at the top of your Model class with the use statement. You'll need to use App::import() or require() to load the file containing your trait at the top of your Model file.Breadfruit
O
2

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.
Ozan answered 27/10, 2010 at 11:26 Comment(7)
(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 modelWorkhouse
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.Ozan
Thanks. What do you mean by "literally attach the behavior to every model"?Workhouse
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.Ozan
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.Ozan
@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: trac.cakephp.org/ticket/2056Workhouse
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 ariseWorkhouse
E
2

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

Eyewitness answered 27/10, 2010 at 18:27 Comment(1)
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.Workhouse
M
2

http://github.com/m3nt0r/eventful-cakephp

Set up an event that does the formatting - trigger that event however you need to. Easy as Cake.

Manners answered 2/11, 2010 at 14:39 Comment(1)
Every time i suggest the Eventful plugin somebody upvotes me within minutes - have to wonder if it is m3nt0r (the author)Manners

© 2022 - 2024 — McMap. All rights reserved.