Прежде чем начать, хочу сказать, что я не продвинутый пользователь PHP, я все еще учусь.
Я работаю над приложением, в котором у меня есть класс для обработки всех операций с базой данных, и я пытаюсь упростить этот процесс и лучше вылавливать ошибки. Например, когда я хочу вставить нового пользователя, мне нужно выполнить несколько запросов к разным таблицам в моей базе данных.
Прежде всего, позвольте мне показать класс, который обрабатывает соединение с базой данных.
# database.class.php
namespace Playground;
use PDO;
class Dbh {
private static $instance;
private $conn = null;
private $database="playground";
private $host="localhost";
private $user="root";
private $pass="root";
private $option = array(
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::MYSQL_ATTR_INIT_COMMAND => "SET time_zone="-3:00", lc_time_names="pt_BR""
);
/**
* Construct
*/
private function __construct() {
$this->conn = new PDO(
'mysql:charset=utf8mb4;host=".$this->host.";dbname=".$this->database,
$this->user,
$this->pass,
$this->option
);
}
/**
* Prevent class cloning
*/
private function __clone() {}
/**
* Initialize an instance of this class
*/
public static function init() {
if (!self::$instance) {
self::$instance = new Dbh();
}
return self::$instance;
}
/**
* Close database connection
*/
public function close() {
$this->conn = null;
}
/**
* Load all data from a table and return as an array.
*
* @param String $sql Query to be executed
* @param Array $param Parameters to be binded
*
* @return Array
*/
public function load(String $sql, Array $param = null) {
$q = $this->conn->prepare($sql);
$q->execute($param);
return $q->fetchAll();
}
/**
* Insert new record to the database and return the ID.
*
* @param String $sql Query to be executed
* @param Array $param Parameters to be binded
*
* @return Number
*/
public function insert(String $sql, Array $param = null) {
$q = $this->conn->prepare($sql);
$q->execute($param);
return $this->conn->lastInsertId();
}
}
# user.class.php
/**
* Register a new user
*
* @param Object $jwt JWT Token
* @param Object $post Data via $_POST
*
* @return Response<Null|Object>
*/
public function addUser(object $jwt, object $post) {
// Init Dbh
$dbh = Dbh::init();
// Check for required fields
if (!Utils::checkParams($post, $this->userAddRequiredParams)) {
return $this->response->error("validation');
}
// Add new user
$params = [
':id_group' => $post->id_group,
':master' => $post->master,
':email' => $post->email,
':pass' => Auth::generatePassword(), // Random for new users
];
$id_user = $dbh->insert("INSERT INTO tb_user
(id_group, master, email, pass) VALUES
(:id_group, :master, :email, :pass)
", $params);
if (!$id_user) {
Log::error($jwt->uid, 'post', 'user', 'Fail to add new user. tb_user', $params);
return $this->response->error();
}
// Add user detail
$params = [
':id_user' => $id_user,
':first_name' => ucfirst($post->first_name),
':last_name' => $post->last_name,
':birthdate' => Utils::converterData($post->birthdate),
// [...] There are many other fields here
];
$id_user_info = $dbh->insert("INSERT INTO tb_user_info
(id_user, first_name, last_name, birthdate, ...) VALUES
(:id_user, :first_name, :last_name, :birthdate, ...)
", $params);
if (!$id_user_info) {
Log::error($jwt->uid, 'post', 'user', 'Fail to add new user. tb_user_info', $params);
return $this->response->error();
}
// Add user address
$params = [
':id_user' => $id_user,
':street' => $post->street,
':zipcode' => $post->zipcode,
// [...] There are many other fields here
];
$id_address = $dbh->insert("INSERT INTO tb_user_address
(id_user, street, zipcode, ...) VALUES
(:id_user, :street, :zipcode, ...)
", $params);
if (!$id_address) {
Log::error($jwt->uid, 'post', 'user', 'Fail to add new user. tb_user_address', $params);
return $this->response->error();
}
// Create record to sync user and group
$params = [
':id_author' => $jwt->uid,
':id_group' => $post->id_group,
':id_user' => $id_user,
];
$insert = $dbh->insert("INSERT INTO tb_user_group
(id_author, id_group, id_user) VALUES
(:id_author, :id_group, :id_user)
", $params);
if (!$insert) {
Log::error($jwt->uid, 'post', 'user', 'Fail to add new user. tb_user_group', $params);
return $this->response->error();
}
// Send an welcome e-mail to the new user
// [...]
// Some other irrelevant stuff
// Return success
$user = $this->loadUser($id_user);
return $this->response->success('User added successfully', $user);
}
Этот код работает должным образом. Но допустим, что по какой-то причине нам не удалось правильно вставить адрес пользователя. Тогда функция сломается по адресу и сгенерирует недействительную регистрацию пользователя, поскольку у него не будет адреса.
Я знаю, что есть возможность сделать откат, но не знаю, как это работает, так как раньше я этого не делал. Посмотрев на другие материалы, я нашел кое-что, основанное на Try/Catch метод для всех запросов к базе данных, но когда я попытался, я не смог сделать ошибку, я имею в виду, я сам сделал недопустимый запрос, чтобы проверить его, но catch метод никогда не выполняется. Вот что я сделал.
/**
* Register a new
*
* @param Object $jwt JWT Token
* @param Object $post Data via $_POST
*
* @return Response<Null|Object>
*/
public function addUser(object $jwt, object $post) {
// Init Dbh
$dbh = Dbh::init();
// Check for required fields
if (!Utils::checkParams($post, $this->userAddRequiredParams)) {
return $this->response->error('validation');
}
try {
// Note: This is the same query as before, I'm justi simplifying
// Add new user
$params = [':id_group' => $post->id_group, [...]];
$id_user = $dbh->insert("INSERT INTO tb_user ...", $params);
// Add user detail
$params = [':id_user' => $id_user, [...]];
$id_user_info = $dbh->insert("INSERT INTO tb_user_info ...", $params);
// Add user address
$params = [':id_user' => $id_user, ...];
$id_address = $dbh->insert("INSERT INTO tb_user_address ...", $params);
// Create record to sync user and group
$params = [':id_author' => $jwt->uid, [...]];
$insert = $dbh->insert("INSERT INTO tb_user_group ...", $params);
} catch (Throwable $th) {
$dbh->rollback();
Log::error($jwt->uid, 'post', 'user', 'Fail to add new user. tb_user', $params);
return $this->response->error();
}
// Send an welcome e-mail to the new user
// [...]
// Some other irrelevant stuff
// Return success
$user = $this->loadUser($id_user);
return $this->response->success('User added successfully', $user);
}
Что мне делать в этом случае? Или что можно сделать, чтобы улучшить этот процесс и убедиться, что все шаги правильно вставлены в базу данных? Это обычный поток, который у меня есть и в других областях того же приложения.
![Избегайте вставки базы данных при сбое другого запроса [closed] TheFAQ.ru](https://thefaq.ru/wp-content/uploads/2023/01/logo-250.png)