Search code examples
phpmysqlpdo

Returning lastInsertId() from database class


I am using a database class picked up from a tutorial on codecourse.com (I am just starting the migration from procedural to pdo) and I am slowly extending it to fit my needs. However, the one thing I cannot manage is to return the lastInsertId() to be used globally.

Using the register example from that tutorial

$user = new User();
$salt = Hash::salt(32);
try {
 $user->create(array(
  'username' => Input::get('username'),
  'password' => Hash::make(Input::get('password'), $salt),
  'salt' => $salt,
  'firstname' => Input::get('first_name'),
  'lastname' => Input::get('last_name'),
  'joined' => date('Y-m-d H:i:s'),
  'group' => 1
  ));
 } catch(Exception $e) {
   die($e->getMessage());
 }

It is at this point that I want to get the lastInsertId() - the one of the just registered user. I am not sure whether it comes out of the Database class via the insert function

require_once 'core/init.php';

class DB {
 private static $_instance = null;
 private $_pdo,
         $_query,
         $_error = false,
         $_results,
         $_count = 0;

 private function __construct() {
    try {
        $this->_pdo = new PDO('mysql:host=' . Config::get('mysql/host') . ';dbname=' . Config::get('mysql/db'),  Config::get('mysql/username'), Config::get('mysql/password') );

    } catch(PDOException $e) {
        die($e->getMessage());
    }
}
public static function getInstance() {
    if(!isset(self::$_instance)) {
        self::$_instance = new DB();
    }
    return self::$_instance;
}


public function query ($sql, $params = array()) {
    $this->error = false;
    if ($this->_query = $this->_pdo->prepare($sql)) {
        $x = 1;
        if(count($params)) {
            foreach($params as $param) {
                $this->_query->bindValue($x, $param);
                $x++;
            }
        }

        if($this->_query->execute()) {
            $this->_results = $this->_query->fetchAll(PDO::FETCH_OBJ);
            $this->_count = $this->_query->rowCount();
        } else {
            $this->_error = true;
      }
    }

    return $this;
}

public function action ($action, $table, $where = array()) {
    if (count($where) === 3) {
        $operators = array('=', '>', '<', '>=', '<=');

        $field = $where[0];
        $operator = $where[1];
        $value = $where[2];

        if (in_array($operator, $operators)) {
            $sql = "{$action} FROM {$table} WHERE {$field} {$operator} ?";
            if(!$this->query($sql, array($value))->error()) {
                return $this;
            }
        }
    }
    return false;
}

public function get ($table, $where) {
    return $this->action('SELECT *', $table, $where);
}

public function delete ($table, $where) {
    return $this->action('DELETE', $table, $where);

}

public function insert ($table, $fields = array()) {

        $keys = array_keys($fields);
        $values = '';
        $x = 1;

        foreach($fields as $field) {
            $values .= '?';
            if ($x < count($fields)) {
                $values .= ', ';
            }

            $x++;
        }


        $sql = "INSERT INTO {$table} (`" . implode('`,`', $keys) . "`) VALUES ({$values})";

        if (!$this->query($sql,$fields)->error()) {
            return true;
        }

        echo $sql;
   }
    return false;

}

public function update ($table, $id, $fields = array()) {

        $set = '';
        $x = 1;

       foreach ($fields as $name => $value) {
            $set .= "{$name} = ?";
            if ($x < count($fields)) {
                $set .= ', ';
            }

            $x++;
        }

        $sql = "UPDATE {$table} SET {$set} WHERE id = {$id}";

        if (!$this->query($sql,$fields)->error()) {
            return true;
        }

     }
    return false;

}


public function first () {
    return $this->results()[0];
}

public function results () {
    return $this->_results;
}

public function count () {
    return $this->_count;
}

public function error () {
    return $this->_error;
}

}

Or the User class via the create function

class User {
private $_db,
        $_data,
        $_sessionName,
        $_cookieName,
        $_isLoggedIn;
public function __construct($user = null) {
    $this->_db = DB::getInstance();
    $this->_sessionName = Config::get('session/session_name');
    $this->_cookieName = Config::get('remember/cookie_name');
    if (!$user) {
        if (Session::exists($this->_sessionName)) {
            $user = Session::get($this->_sessionName);
            if ($this->find($user)) {
                $this->_isLoggedIn = true;
            } else {
                //Logged out
            }
        }
    } else {
        $this->find($user);
    }
}
public function update($fields=array(), $id = null) {
    if (!$id && $this->isLoggedIn ()) {
        $id = $this->data()->id;
    }
    if (!$this->_db->update('users', $id, $fields)) {
        throw new Exception('There was a problem updating the account!');
    }
}
public function create($fields) {
    if (!$this->_db->insert('users', $fields)) {
        throw new Exception('There was a problem creating an account!');
    }
}
 public function find($user=null) {
    if ($user) {
        $field = (is_numeric($user)) ? 'id' : 'username';
        $data = $this->_db->get('users', array($field, '=', $user));
        if ($data->count()) {
            $this->_data = $data->first();
            return true;
        }
    }
    return false;
}
public function login($username=null, $password=null, $remember = false) {
    if(!$username && !$password && $this->exists()) {
        Session::put($this->_sessionName, $this->data()->id );
    } else {
        $user = $this->find($username);
        if ($this->data()->password === Hash::make($password, $this->data()->salt)) {
            Session::put($this->_sessionName, $this->data()->id);
            if ($remember) {
                $hash = Hash::unique();
                $hashCheck = $this->_db->get('users_session', array('user_id', '=', $this->data()->id));
                if (!$hashCheck->count()) {

                    $this->_db->insert('users_session', array(
                         'user_id' => $this->data()->id,
                        'hash' => $hash
                    ));
                } else {
                    $hash = $hashCheck->first()->hash;
                }
                Cookie::put($this->_cookieName, $hash, Config::get('remember/cookie_expiry'));
            }
            return true;
        }
        return false;
        }
}
public function hasPermission ($key) {
    $group = $this->_db->get('groups', array('id', '=', $this->data()->group));
    if($group->count()) {
        $permissions = json_decode($group->first()->permissions, true);
        if ($permissions[$key] == true) {
            return true;
        }
    }
    return false;
}
public function exists () {
    return (!empty($this->_data)) ? true : false;
}
public function logout () {
    Session::delete($this->_sessionName);
}
public function data () {
    return $this->_data;
}
 public function isLoggedIn () {
    return $this->_isLoggedIn;
}
}

I have tried in both but whenever I try to echo the lastInsertId() back out, nothing is returned. Any advice would be greatly welcomed. If the problem might be outside of these areas, I have uploaded the entire script to https://github.com/MargateSteve/login.

Thanks in advance

Steve


Solution

  • Add a public variable to your DB class that will hold the last inserted record ID:

    class DB {
        public $lastInsertId = null;
    

    In the same DB class modify the query method, where the actual insert happens so that you can grab the ID from PDO:

    public function query ($sql, $params = array()) {
        $this->error = false;
        if ($this->_query = $this->_pdo->prepare($sql)) {
            $x = 1;
            if(count($params)) {
                foreach($params as $param) {
                    $this->_query->bindValue($x, $param);
                    $x++;
                }
            }
    
            if($this->_query->execute()) {
                $this->lastInsertId = $this->_pdo->lastInsertId();
                $this->_results = $this->_query->fetchAll(PDO::FETCH_OBJ);
                $this->_count = $this->_query->rowCount();
            } else {
                $this->_error = true;
            }
        }
    
        return $this;
    }
    

    On the code above this is the important line:

    $this->lastInsertId = $this->_pdo->lastInsertId();
    

    You are assigning the value of PDO::lastInsertId() to your lastInsertId instance variable, that way you can access it from wherever you instantiate a DB object.

    Now, modify the user class to hold a variable called id as well, do not name it lastInsertId because its confusing; in this context you have one single instance of a user which represents a single user and hence id simply refers to this instance user id:

    class User {
    
        public $id = null;
    

    Modify in this same User class the create method as well to grab the lastInsertId value from your db object instance:

    public function create($fields) {
        if (!$this->_db->insert('users', $fields)) {
            throw new Exception('There was a problem creating an account!');
        }
    
        $this->id = $this->_db->lastInsertId;
    
    }
    

    Then you can access the user ID in your register.php file simply accesing the user instance variable e.g. $user->id :

    try {
        $user->create(array(
            'username' => Input::get('username'),
            'password' => Hash::make(Input::get('password'), $salt),
            'salt' => $salt,
            'firstname' => Input::get('first_name'),
            'lastname' => Input::get('last_name'),
            'joined' => date('Y-m-d H:i:s'),
            'group' => 1
        ));
    
        Session::flash('home', "You have registered with user ID $user->id");
        Redirect::to('index.php');
    } catch(Exception $e) {
        die($e->getMessage());
    }