Create a Rest API in PHP and Consume it in React Part 2
In the second part of this tutorial, we will add category model & controller, user model & controller and we will add functions for registration login & logout.
Create CategoryModel
Inside models, we add a new file 'CategoryModel' Here we have one function for fetching all categories.
<?php
namespace App\Models;
use App\Database\Database as DB;
use PDO;
class CategoryModel
{
private $conn;
public function __construct()
{
$database = new DB;
$this->conn = $database->connect();
}
public function fetchAllCategories()
{
$stmt = $this->conn->prepare("SELECT * FROM categories");
$stmt->execute();
$categories = $stmt->fetchAll(PDO::FETCH_ASSOC);
return $categories;
}
}
Create CategoryController
Inside controllers, we add a new file 'CategoryController' Here we call the function already added in the 'CategoryModel'.
<?php
namespace App\Controllers;
use App\Models\CategoryModel as Category;
class CategoryController
{
private $model;
public function __construct()
{
$this->model = new Category;
}
public function index()
{
$categories = $this->model->fetchAllCategories();
echo json_encode([
'categories' => $categories
]);
}
}
Create UserModel
Inside models, we add a new file 'UserModel' Here we have functions for storing log-in logout, and generating access tokens for users.
<?php
namespace App\Models;
use App\Database\Database as DB;
use PDO;
class UserModel
{
private $conn;
public function __construct()
{
$database = new DB;
$this->conn = $database->connect();
}
public function store($data)
{
$stmt = $this->conn->prepare('INSERT INTO users(name, email, password)
VALUES (:name, :email, :password)');
$stmt->bindParam(':name', $data['name']);
$stmt->bindParam(':email', $data['email']);
$stmt->bindParam(':password', $data['password']);
$stmt->execute();
}
public function auth($data, $login) {
$email = $data['email'];
$stmt = $this->conn->prepare("SELECT * FROM users
WHERE email = :email");
$stmt->bindParam(':email', $email);
$stmt->execute();
$user = $stmt->fetch(PDO::FETCH_ASSOC);
if($user && $login) {
$user['api_key'] = $this->createApiKey($user['id']);
}
return $user;
}
public function signout($api_key, $user_id)
{
$this->removeApiKey($api_key, $user_id);
}
public function createApiKey($user_id)
{
$api_key = bin2hex(random_bytes(16));
$stmt = $this->conn->prepare('INSERT INTO api_keys(user_id, api_key)
VALUES (:user_id, :api_key)');
$stmt->bindParam(':user_id', $user_id);
$stmt->bindParam(':api_key', $api_key);
$stmt->execute();
return $api_key;
}
public function removeApiKey($api_key, $user_id)
{
$stmt = $this->conn->prepare("DELETE FROM api_keys
WHERE user_id = :user_id AND api_key = :api_key");
$stmt->bindParam(':user_id', $user_id);
$stmt->bindParam(':api_key', $api_key);
$stmt->execute();
}
public function checkIfApiKeyIsValid($api_key, $user_id)
{
$stmt = $this->conn->prepare("SELECT * FROM api_keys
WHERE user_id = :user_id AND api_key = :api_key");
$stmt->bindParam(':user_id', $user_id);
$stmt->bindParam(':api_key', $api_key);
$stmt->execute();
$data = $stmt->fetch(PDO::FETCH_ASSOC);
return $data;
}
}
Create UserController
Inside controllers, we add a new file 'UserController' Here we call functions already added in the 'UserModel'.
<?php
namespace App\Controllers;
use App\Models\UserModel as User;
class UserController
{
private $model;
public function __construct()
{
$this->model = new User;
}
public function register($data)
{
$user = $this->model->auth($data, $login = false);
if($user) {
echo json_encode([
'error' => true,
'message' => 'You have already an account try to log in.'
]);
}else {
$options = [
'const' => 12
];
//hash password
$password = password_hash($data['password'], PASSWORD_BCRYPT, $options);
$data['password'] = $password;
$this->model->store($data);
echo json_encode([
'message' => 'Account created successfully.'
]);
}
}
public function login($data)
{
$user = $this->model->auth($data, $login = true);
if(!$user) {
echo json_encode([
'error' => true,
'message' => 'These credentials do not match any of our records.'
]);
}else if(password_verify($data['password'], $user['password'])){
unset($user['password']);
echo json_encode([
'user' => $user,
]);
}else {
echo json_encode([
'error' => true,
'message' => 'These credentials do not match any of our records.'
]);
}
}
public function logout($data)
{
if(!$data['api_key'] || empty($data['api_key'])) {
http_response_code(401);
echo json_encode([
'error' => true,
'message' => 'unauthenticated'
]);
}else if(!$this->model->checkIfApiKeyIsValid($data['api_key'], $data['user_id'])) {
http_response_code(401);
echo json_encode([
'error' => true,
'message' => 'unauthenticated'
]);
}else {
$this->model->signout($data['api_key'], $data['user_id']);
echo json_encode([
'message' => 'Logout successfully'
]);
}
}
}