Yii Framework Forum: Attached Behavior Doesn't Get Access To The Owner From Within Getter Method. - Yii Framework Forum

Jump to content

Page 1 of 1
  • You cannot start a new topic
  • You cannot reply to this topic

Attached Behavior Doesn't Get Access To The Owner From Within Getter Method. Rate Topic: -----

#1 User is offline   twisted1919 

  • Master Member
  • PipPipPipPip
  • Yii
  • Group: Members
  • Posts: 634
  • Joined: 23-October 10
  • Location:Romania

Posted 26 April 2013 - 10:18 AM

So, i have this bevahior, called AttributesMap:
class AttributesMap extends \CBehavior
{
    // writable attributes list
    protected $_writeList ;

    public function setWriteList(array $map)
    {
        $_map = array();
        foreach ($map AS $attributeName) {
            if ($this->owner->hasAttribute($attributeName)) {
                $_map[$attributeName] = $this->owner->getAttribute($attributeName);
            }
        }
        $this->_writeList = new \CMap($_map);
    }
}


Next, i'm attaching it to a AR model:
public function behaviors()
    {
        return array(
            'attributesMap' => array(
                'class' => '\somenamespace\me\app\components\behaviors\AttributesMap',
                'writeList' => array('first_name', 'last_name')
            ),
        );
    }


When the execution reaches:
if ($this->owner->hasAttribute($attributeName)) {...


It throws an error because $this->owner is null.
Any pointers ?

Thanks.
0

#2 User is offline   le_top 

  • Advanced Member
  • PipPipPip
  • Yii
  • Group: Members
  • Posts: 303
  • Joined: 08-June 10
  • Location:France

Posted 26 April 2013 - 11:29 AM

Are you using this behavior as
$this->setWriteList(...)


Where $this is the instance of the active record?
0

#3 User is offline   softark 

  • Keep It Simple
  • Yii
  • Group: Moderators
  • Posts: 2,045
  • Joined: 16-February 11
  • Location:Japan

Posted 26 April 2013 - 11:37 AM

Hi twisted,

Probably setWriteList() is called in the constructor (or initialization process) of AttributesMap, before it is attached to the owner.
0

#4 User is offline   twisted1919 

  • Master Member
  • PipPipPipPip
  • Yii
  • Group: Members
  • Posts: 634
  • Joined: 23-October 10
  • Location:Romania

Posted 26 April 2013 - 01:54 PM

Hi there,
@le_top - nope, i don't even reach the point where i access this behavior, the error happens when it is attached to the model.

@softwark - not quite, take a look, here is my entire class:
<?php

namespace somenamespace\me\app\components\behaviors;

class AttributesMap extends \CBehavior
{
    // writable attributes list
    protected $_writeList ;
    
    // readable attributes list
    protected $_readList;

    public function setWriteList(array $map)
    {
        $_map = array();
        foreach ($map AS $attributeName) {
            if ($this->owner->hasAttribute($attributeName)) {
                $_map[$attributeName] = $this->owner->getAttribute($attributeName);
            }
        }
        $this->_writeList = new \CMap($_map);
    }
    
    public function setReadList(array $map)
    {
        $_map = array();
        foreach ($map AS $attributeName) {
            if ($this->owner->hasAttribute($attributeName)) {
                $_map[$attributeName] = $this->owner->getAttribute($attributeName);
            }
        }
        $this->_readList = new \CMap($_map);
    }
    
    public function getWriteList()
    {
        if (!is_object($this->_writeList) || !($this->_writeList) instanceof \CMap) {
            $this->_writeList = new \CMap();
        }
        return $this->_writeList->toArray();
    }
    
    public function getReadList()
    {
        if (!is_object($this->_readList) || !($this->_readList) instanceof \CMap) {
            $this->_readList = new \CMap();
        }
        return $this->_readList->toArray();
    }
}


It's nothing too fancy actually. The error is triggered when the behavior is attached to the model, i'm not doing anything else.
0

#5 User is offline   le_top 

  • Advanced Member
  • PipPipPip
  • Yii
  • Group: Members
  • Posts: 303
  • Joined: 08-June 10
  • Location:France

Posted 26 April 2013 - 02:05 PM

I think it is sometihng in your attach context which implies that setWriteList is called too early.
0

#6 User is offline   twisted1919 

  • Master Member
  • PipPipPipPip
  • Yii
  • Group: Members
  • Posts: 634
  • Joined: 23-October 10
  • Location:Romania

Posted 26 April 2013 - 02:18 PM

The thing is that set* and get* are setters and getters and i think this is the problem.
If i
public function getSomething()
    {
        return $this->getOwner();
    }

and call that manually with
$model->behavior->getSomething(); // or
$model->behavior->something;

They both work, but as you say, i think in my case it happens to early and the owner doesn't get set at that point.

Don't know if i should report this as a bug or not.
0

#7 User is offline   le_top 

  • Advanced Member
  • PipPipPip
  • Yii
  • Group: Members
  • Posts: 303
  • Joined: 08-June 10
  • Location:France

Posted 26 April 2013 - 02:24 PM

Well, there you have it, which is what I referred to in my first reply.
You should write:
$model->getSomething(); // or
$model->something;


The base class (CComponent) works out where to find the method.
0

#8 User is offline   le_top 

  • Advanced Member
  • PipPipPip
  • Yii
  • Group: Members
  • Posts: 303
  • Joined: 08-June 10
  • Location:France

Posted 26 April 2013 - 02:28 PM

BTW, I have an extension that provides dynamic getters and setters, so the issue is not with the method being getters or setters.
0

#9 User is offline   twisted1919 

  • Master Member
  • PipPipPipPip
  • Yii
  • Group: Members
  • Posts: 634
  • Joined: 23-October 10
  • Location:Romania

Posted 26 April 2013 - 02:39 PM

Yes i understood your point from the start, what i mean is that i never call the setter setWriteList for example nor the getters.
that setter is triggered by Yii itself when i pass the writeList attribute to the behavior. The behavior does not have a public property called writeList. Do you see my point ?
0

#10 User is offline   twisted1919 

  • Master Member
  • PipPipPipPip
  • Yii
  • Group: Members
  • Posts: 634
  • Joined: 23-October 10
  • Location:Romania

Posted 26 April 2013 - 02:44 PM

You can try and simulate that.
Have a behavior with a setter method, something like:
class SomeBehavior extends CBehavior{
  public function setSomething($str) {
     var_dump($this->owner->anyPropertyOfTheModel);
  }
}


Then attach that behavior to a model like:
$model->attachBehaviors(array(
   'someBehavior' => array(
      'class' => 'SomeBehavior',
      'something' => 'this will trigger the fancy error',
   )
));


And run it. It will trigger the error.
0

#11 User is offline   le_top 

  • Advanced Member
  • PipPipPip
  • Yii
  • Group: Members
  • Posts: 303
  • Joined: 08-June 10
  • Location:France

Posted 26 April 2013 - 03:24 PM

Hi
The issue is with the fact the the initializer is called before the behavior is attached.

Fix it like this (using another initializer, or adjust you rmethod to behave differently when there is no owner yet):
public $initialWriteList;
public function attach($owner) {
    parent::attach($owner);
    $this->writeList = $this->initialWriteList;
}


0

#12 User is offline   twisted1919 

  • Master Member
  • PipPipPipPip
  • Yii
  • Group: Members
  • Posts: 634
  • Joined: 23-October 10
  • Location:Romania

Posted 26 April 2013 - 04:00 PM

@ le_top - thanks for the hint, i'll give it a try when I reach a computer (writing from my phone now) and i will let you know about how it goes.
0

#13 User is offline   twisted1919 

  • Master Member
  • PipPipPipPip
  • Yii
  • Group: Members
  • Posts: 634
  • Joined: 23-October 10
  • Location:Romania

Posted 27 April 2013 - 08:21 AM

Just an update. I gave up upon the idea, i think it's way easier to just:
$attributes = array('first_name', 'last_name');
foreach ($user->getAttributes($attributes) as $attributeName => $attributeValue) {
[...]
}

than to define a class to do same stuff, no point in reinventing the wheel after all.
0

#14 User is offline   le_top 

  • Advanced Member
  • PipPipPip
  • Yii
  • Group: Members
  • Posts: 303
  • Joined: 08-June 10
  • Location:France

Posted 27 April 2013 - 08:40 AM

Hi

It all depends on the level of abstraction you want to introduce and what the eventual goal is.

In your case it looks as if you want to limit the attributes that are readable and writeable for the class to a limited list.

So, IMHO, you are stll 'reinventing' the wheel with the last implementation.

Let me explain:
The model rules let you define which attributes are 'safe'.
The list if safe attributes can be retrieved through 'getSafeAttributes'.
The default 'setAttributes' allows you to set safe attributes only.

Where you need to 'extend' your class is where you want to read only the safe attribute.
This is where a behavior can be usefull.
To maintain your list, use the rules and scenarios.
0

Share this topic:


Page 1 of 1
  • You cannot start a new topic
  • You cannot reply to this topic

1 User(s) are reading this topic
0 members, 1 guests, 0 anonymous users