Welcome Guest, Not a member yet? Register   Sign In
problems using magic methods with datamapper
#1

[eluser]johnmerlino[/eluser]
Hey all,

Because I have magic methods __set and __get defined in a model which inherits from DataMapper, I get the following exception:

Call to a member function field_data() on a non-object in /Users/jmerlino/Sites/hbla/system/application/libraries/Datamapper.php on line 622

All I am doing is creating a new user:

Code:
//users controller

                $u = new User();
                $u->first_name = $this->input->post('first_name');
                $u->last_name = $this->input->post('last_name');
                $u->email = $this->input->post('email');
                $u->password = $this->input->post('password');

Note that there is no property called password. But there are attributes called encrypted_password and password_salt. So I do the following in my model:

Code:
//user model - inherits from DataMapper

            protected $password_salt;
            protected $encrypted_password;
            protected $activation_code;
            protected static $CI;

            public function __get($property){
                 $method = "get{$property}";
                if ( method_exists($this, $method)){
                    return $this->$method();
                }
            }

            public function __set($property,$value){
                 $method = "set{$property}";
                if(method_exists($this, $method)){
                    return $this->$method( $value );
                } else {
                    $this->$property = $value;
                }
            }
                      
            public function setPassword($password){
                if ( ! is_null( $password ) ) {
                    $this->password_salt = User::random_string_generator();
                    $this->encrypted_password = User::encrypt($password,$this->password_salt);
                }
                return null;    
            }
    public static function random_string_generator(){
               $chars = array_merge(range("a","z"),range("A","Z"),range("0","9"));
               shuffle($chars);
               return implode('',array_slice($chars,0,10));
            }
            
            public static function encrypt($pass,$salt){
                return sha1($pass . $salt);
            }

            public function save(){
                if(User::email_exists($this->email)){
                    return parent::save();
                }
                return false;
            }
            
            public static function email_exists($email){
                self::$CI = get_instance();
                self::$CI->db->where('email',$email);
                $query = self::$CI->db->get('users');
                if($query->num_rows == 0){
                    return true;
                 }
                 return false;
            }
As you can see, I have a setPassword() method which handles the assignment for the encrypted_password and password_salt properties. If I remove the magic methods, the error doesn't occur, but of course then the two properties are not updated to the database because their assignment occurs in setPassword().

Is there way to address the coexistance of magic methods declared in the same model which inherits from DataMapper?

Thanks for response.
#2

[eluser]johnmerlino[/eluser]
Obviously this would resolve the issue:

Code:
$u->setPassword($this->input->post('password'));

But I like using magic methods to make the code look more clean. And if it's possible to use magic methods in model while still inheriting from DataMapper, that would be nice.

Thanks for response.
#3

[eluser]WanWizard[/eluser]
field_data() is a CI database library method. This error suggests there's something wrong with the database instance ($this->db).

The reason this fails is that Datamapper already uses the __get() magic method. And by defining your own, you disable Datamappers, which is why $this->db is not assigned properly.

Try changing your method to
Code:
public function __get($property)
{
    $method = "get{$property}";
    if ( method_exists($this, $method))
    {
        return $this->$method();
    }
    else
    {
        parent::__get($property);
    }
}
#4

[eluser]johnmerlino[/eluser]
Thanks for response but it still generates the same error. If I change __set as well like this:

Code:
public function __get($property){
                $method = "get{$property}";
                if ( method_exists($this, $method)){
                    return $this->$method();
                }
                else {
                    parent::__get($property);
                }
            }

            public function __set($property,$value){
                 $method = "set{$property}";
                if(method_exists($this, $method)){
                    return $this->$method( $value );
                }
                else {
                       parent::__set($property,$value);
                 }
            }

it tells me Uncaught exception 'Exception' with message 'Unable to call the method "__set" on the class User'.

I guess it says that because the __set method is not declared in DataMapper? If not, then why does it give me error:

Code:
Fatal error: Call to a member function field_data() on a non-object in /Users/jmerlino/Sites/hbla/system/application/libraries/Datamapper.php on line 622

with this:

Code:
public function __get($property){
                $method = "get{$property}";
                if ( method_exists($this, $method)){
                    return $this->$method();
                }
                else {
                    parent::__get($property);
                }
            }

            public function __set($property,$value){
                 $method = "set{$property}";
                if(method_exists($this, $method)){
                    return $this->$method( $value );
                }
                else {
                       $this->$property = $value;
                 }
            }

The __set method above was working prior to inheriting from DataMapper.

Thanks for response.
#5

[eluser]johnmerlino[/eluser]
Thanks for your responses.
#6

[eluser]WanWizard[/eluser]
Datamapper doesn't use __set(), so no need to call the parent method.

And the error is my bad, I should really find the time to test what I type... You should return the result of parent::__get()...




Theme © iAndrew 2016 - Forum software by © MyBB