The main reasoning behind this PDO wrapper, is that I find myself using unique constraints quite frequently in my designs, and I have if ($ex->errorInfo[1] == 1062)
littered throughout my code, and I thought there has to be a better way.
<?php
class PDOMysql extends \PDO {
public function __construct($dsn, $username = null, $passwd = null, $options = null)
{
parent::__construct($dsn, $username, $passwd, $options);
$this->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
$this->setAttribute(\PDO::ATTR_DEFAULT_FETCH_MODE, \PDO::FETCH_OBJ);
}
public function prepareAndExecute($statement, array $params = []): \PDOStatement
{
try {
$stmt = $this->prepare($statement);
$stmt->execute($params);
return $stmt;
} catch (\PDOException $ex) {
if ($ex->errorInfo[1] == 1062) {
throw new PDOMysqlUniqueConstraintException($ex);
} else {
throw $ex;
}
}
}
}
class PDOMysqlUniqueConstraintException extends \PDOException {
public function __construct(\PDOException $ex)
{
parent::__construct($ex->getMessage(), $ex->getCode(), $ex->getPrevious());
}
}
// example usage
$user = 'vps';
$pass = 'vps';
$db = new PDOMysql("mysql:host=localhost;dbname=testdb", $user, $pass);
// create table
$sql = "create table if not exists `mytable` (col1 varchar(100) null, constraint idx_u unique (col1) )";
$db->prepareAndExecute($sql);
// insert first row
$params = ['col1' => uniqid('')];
$sql = "insert into mytable (col1) values (:col1)";
$db->prepareAndExecute($sql, $params);
// select row
$sql = "select * from mytable where col1 = :col1";
$stmt = $db->prepareAndExecute($sql, $params);
var_dump($stmt->fetchAll());
// insert duplicate row
try {
$sql = "insert into mytable (col1) values (:col1)";
$db->prepareAndExecute($sql, $params);
} catch (\PDOMysqlUniqueConstraintException $ex) {
die('Unique Constraint Detected');
}