2
votes

I have hybridRegister callback in my User model. Once user is registered using socal login (facebook for example) I trye to check his email. And if email exists in database, I stop register and make the login using an user data related with this email.

public function hybridRegister($provider, Hybrid_User_Profile $profile) {

    $profile = (array)$profile;


    $data = array(
        'provider' => $provider,
        'provider_uid' => $profile['identifier'],
        //Extra fields here as needed like group_id, status etc.
    );




    if (strtolower($provider) === "vkontakte"){

        $data['firstName'] = $profile['firstName'];
        $data['lastName']  = $profile['lastName'];
        //TODO make fetching picture to our server
        $data['photo']     = $profile['photoURL']; 

        $data['email']     = $profile['emailVerified'];     
    }

    if (strtolower($provider) === "facebook"){

        $data['firstName'] = $profile['firstName'];
        $data['lastName']  = $profile['lastName'];

           //TODO выкачивать картинку на сервер
        $data['photo']     = $profile['photoURL']; 
        $data['email']     = $profile['emailVerified'];   
    }

    //Check if an email exists in our db. if yes, then login user else
    // continue register...

    $user = $this->existEmail($data);
    if ($user){

        **//AuthComponent::login throw error somewhere inside it**
        AuthComponent::login($user);

        return true;
    }
    else {
        // если нет, то продолжаем регистрацию

        $data['password'] = $this->generatePassword();
        $data['username'] = $data['provider'] . $profile['identifier']; 


       $this->sendRegistrationEmail($data['email'], $data['username'], $data['password']);




        $this->create();
        return $this->save($data, false);
    }
}

Below the error:

Database Error
Error: SQLSTATE[42000]: Syntax error or access violation: 1064 You have an    error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '_setDefaults' at line 1
SQL Query: _setDefaults
Notice: If you want to customize this error message, create  app/View/Errors/pdo_error.ctp
Stack Trace
CORE/Cake/Model/Datasource/DboSource.php line 460 → PDOStatement->execute(array)
CORE/Cake/Model/Datasource/DboSource.php line 426 → DboSource->_execute(string, array)
CORE/Cake/Model/Datasource/DboSource.php line 668 → DboSource->execute(string, array, array)
CORE/Cake/Model/Datasource/DboSource.php line 611 → DboSource->fetchAll(string, array, array)
CORE/Cake/Model/Model.php line 827 → DboSource->query(string, array, User)
CORE/Cake/Controller/Component/AuthComponent.php line 604 → Model->__call(string, array)
CORE/Cake/Controller/Component/AuthComponent.php line 604 → User->_setDefaults()
APP/Model/User.php line 250 → AuthComponent->login(array)
[internal function] → User->hybridRegister(string, Hybrid_User_Profile)

I have looked into the authComponent code (a login function). There is a description

/**
* Log a user in.
*
* **If a $user is provided that data will be stored as the logged in user.** If   `$user` is empty or not
* specified, the request will be used to identify a user.

I dont understand why my code diesnt work. Advise me please.

Answer

The code of a hybridRegister function should be changed a bit. Once the existing of user email is approved in a db, function should just return the user. HybridAuth make auth itself. The code go below:

//Check if an email exists in our db. if yes, then login user else
// continue register...

    $user = $this->existEmail($data);
    if ($user){
        return $user;
    }

My mistake wa to think that hybridRegister MUST save an user or return false. But It can just get any existing user record from db and return it.

Thx @AD7six and @burzum for their thoughts. And @AD7six answer was the most helfull for me.

2

2 Answers

2
votes

Check the SQL error and the stack trace, that's what it is shown.

Error: SQLSTATE[42000]: Syntax error or access violation: 1064 You have an    error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '_setDefaults' at line 1
SQL Query: _setDefaults
CORE/Cake/Controller/Component/AuthComponent.php line 604 → User->_setDefaults()

It is obvious that you're calling a method _setDefaults() that doesn't exist in that model object - guess it is a model. And in 2.x methods that don't exist are turned into a SQL query when it's a model object.

However, the AuthComponent itself implements that method. I guess it's trying to call that method on the model and not the component or something like this. Happy debugging!

2
votes

I have hybridRegister callback in my User model.

**//AuthComponent::login throw error somewhere inside it**
AuthComponent::login($user);

That's not going to work

The login function is not static.

The reason that doesn't work, is because in that function it calls other instance methods:

public function login($user = null) {
    $this->_setDefaults(); # <-

That method exists on the auth component, but don't exist on $this (your user model) when called statically.

Right solution

Logging a user in is "Controller" logic; it belongs in a controller, or a compoent but not a model. There is a simple example of how to create a register function in the book, applied to the code in the question that would be:

public function register() {
    if ($this->User->hybridRegister($this->request->data)) {
        $id = $this->User->id;
        $this->request->data['User'] = array_merge(
            $this->request->data['User'],
            array('id' => $id)
        );
        unset($this->request->data['User']['password']);
        $this->Auth->login($this->request->data['User']);
        return $this->redirect('/users/home');
    }
}

Where hybridRegiser is modified to only takes care of creating the user record (or not), sending the registration email if you want, and returning true/false as appropriate.