Question

I'm struggling to get my Behavior class to use an object instance in the callbacks.

class SomethingBehavior extends ModelBehavior
{
     public function setObject($obj)
     {
         // do stuff
     }

     public function afterFind(Model $model,$results,$primary)
     {
        // use the $obj reference set above
     }
}

Now I need the Model class to call setObject(..) before any find operations are performed. So ideally I would just assign the object I need in the constructor.

class Document extends AppModel
{
    //.....
    public function __construct($id,$table,$ids)
    {
        parent::__construct($id,$table,$ds);
        $this->Something->setObject(new MyClass());
    }
}

My problem is that the Behavior object isn't yet configured, and I get a not an object error when trying to use it.

I can't find any callback method for Models like in Components. For example, there is no setup or initialize method.

How can I assign the object I need to the Behavior?

Was it helpful?

Solution

You don't seem to have worked with behaviors much. Try to use the containable, tree or other core or plugin behaviors, then you will soon figure out the basics.

First of all, behaviors are attached to models (and since 2.3: loaded), not the other way around. A model then gets "richer" in functionality.

Either statically be using public $actsAs or dynamically using

$this->Behaviors->attach('Something'); // since 2.3: load() instead of attach()

It can directly access the behavior methods. Lets say we have a method foo() in your behavior. You can then call it from your model as

$this->foo($foo, $bar);

Or from your controller as

$this->Document->Behaviors->attach('Something')
$this->Document->foo($foo, $bar);

Awesome, right? The behavior method usually has this declaration:

public function foo(Model $Model, $foo, $bar) {
    $alias = $Model->alias;
    // do sth
}

As you can see, you always pass the model into it implicitly (as first argument automatically passed). You can access all its attributes.

And do not touch the constructor of the model. no need to do that.

If you really need to pass an object in at runtime, why does your approach not work?

public function setObject(MyClass $obj) {
    $this->Obj = $obj;
}

Now you can internally use the object from your behavior methods

public function doSth(Model $Model) {
    $this->Obj->xyz();
}

Also this might not be the most elegant approach.

OTHER TIPS

You never set the something member of the Document class. You either need to instantiate it inside the constructor, or pass it in.

Personally, I would do something like this:

class Document extends AppModel
{
    private $behavior;

    public function __construct($id,$table,$ids, ModelBehavior $behavior)
    {
        parent::__construct($id,$table,$ds);
        $this->behavior = $behavior
        $this->behavior->setObject(new MyClass());
    }
}

$doc = new Document(..., new SomethingBehavior());

Or better yet, you could even separate it further by doing:

class Document extends AppModel
{
    private $behavior;

    public function __construct($id,$table,$ids, ModelBehavior $behavior)
    {
        parent::__construct($id,$table,$ds);
        $this->behavior = $behavior
    }
}

$behavior = new SomethingBehavior();
$behavior->setObject(new MyClass());

$doc = new Document(..., $behavior);

That way, there is less magic going on in the constructor.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top