123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233 |
- <?php
- namespace Juju;
- require_once('Data/securestring.class.php');
- require_once('PDO/transaction.class.php');
- require_once('PDO/defaultvalue.class.php');
- require_once('PDO/filter.class.php');
- require_once('PDO/table.class.php');
- use Juju\{Data\SecureString, PDO\DefaultValue, PDO\Filter, PDO\Table, PDO\Transaction};
- class PDO {
- public static function from(string $dsnstring){
- $parts = explode(':', $dsnstring);
- $dsnstring = $parts[1];
- $dsn = explode(';', $dsnstring);
- $dsn = array_reduce($dsn, function($dsn, $item){
- $item = explode('=', $item);
- $dsn[$item[0]] = $item[1];
- return $dsn;
- });
- if(!isset($dsn['host'])){
- throw new \Exception("DSN '{$dsnstring}' missing host");
- }
- if(!isset($dsn['dbname'])){
- throw new \Exception("DSN '{$dsnstring}' missing dbname");
- }
- if(!isset($dsn['user'])){
- $user = $dsn['dbname'];
- }else{
- $user = $dsn['user'];
- }
- if(!isset($dsn['pass'])){
- $dsn['pass'] = $user;
- }
- $pass = SecureString::from($dsn['pass']);
- unset($dsn['pass'], $dsn['user']);
- $dsn = array_reduce(array_keys($dsn), function($a, $key) use($dsn){
- $a[] = "{$key}={$dsn[$key]}";
- return $a;
- });
- $dsnstring = $parts[0].':'.implode(';', $dsn);
- return new PDO($dsnstring, $user, $pass);
- }
- private $pdo;
- private function __construct(string $dsn, string $user, SecureString $pass){
- $mysql = explode(':', $dsn)[0] === 'mysql';
- $options = [];
- if($mysql){
- $options[\PDO::MYSQL_ATTR_INIT_COMMAND] = "SET NAMES 'UTF8'";
- $options[\PDO::MYSQL_ATTR_MULTI_STATEMENTS] = false;
- $options[\PDO::MYSQL_ATTR_FOUND_ROWS] = true;
- }
- $pdo = new \PDO($dsn, $user, (string)$pass, $options);
- $pdo->setAttribute(\PDO::ATTR_AUTOCOMMIT, true);
- $pdo->setAttribute(\PDO::ATTR_CASE, \PDO::CASE_LOWER);
- $pdo->setAttribute(\PDO::ATTR_EMULATE_PREPARES, false);
- $pdo->setAttribute(\PDO::ATTR_DEFAULT_FETCH_MODE, \PDO::FETCH_ASSOC);
- $this->pdo = $pdo;
- }
- public function transaction(callable $fn){
- $pdo = $this->pdo;
- if($pdo->inTransaction()){
- throw new \Exception("Unable to start a new transaction");
- }
- $transaction = new Transaction($this);
- if($fn($transaction) === false){
- do{
- $transaction->rollback();
- }while($transaction->savepoint);
- $pdo->rollback();
- }else{
- $transaction->commit();
- if($pdo->inTransaction()){
- $pdo->commit();
- }
- }
- unset($transaction);
- $pdo->setAttribute(\PDO::ATTR_AUTOCOMMIT, true);
- return $this;
- }
- public function table(string $name){
- return new Table($this, $name);
- }
- public function prepare(string $statement, array $options = []){
- $pdo = $this->pdo;
- if($pdo->getAttribute(\PDO::ATTR_DRIVER_NAME) == 'mysql'){
- $options[\PDO::MYSQL_ATTR_USE_BUFFERED_QUERY] = true;
- }
- $query = $pdo->prepare($statement);
- if($query === false){
- throw $this->getError();
- }
- return $query;
- }
- public function exec(string $statement){
- $query = $this->prepare($statement);
- $query->execute();
- $count = 0;
- while($query->fetch() !== false){
- $count++;
- }
- if($count === 0){
- $query2 = $this->query("select ROW_COUNT()");
- $count = $query2->fetchColumn();
- $query2->closeCursor();
- if($count === 0){
- $count = $query->rowCount();
- }
- }
- $query->closeCursor();
- return $count;
- }
- public function query(string $statement, int $mode = null, ...$args){
- $query = $this->prepare($statement);
- if(!is_null($mode)){
- $query->setFetchMode($mode, ...$args);
- }
- $query->execute();
- return $query;
- }
- public function quote($value, $type = \PDO::PARAM_STR){
- if($type == \PDO::PARAM_INT){
- return (int)$value;
- }elseif($type == \PDO::PARAM_BOOL){
- return (bool)$value ? "b'1'" : "b'0'";
- }elseif($type == \PDO::PARAM_NULL){
- return 'null';
- }
- return $this->pdo->quote((string)$value, $type);
- }
- public function beginTransaction(...$args){
- return $this->pdo->beginTransaction(...$args);
- }
- public function commit(...$args){
- return $this->pdo->commit(...$args);
- }
- public function rollback(...$args){
- return $this->pdo->rollback(...$args);
- }
- public function setAttribute(...$args){
- return $this->pdo->setAttribute(...$args);
- }
- public function getAttribute(...$args){
- return $this->pdo->getAttribute(...$args);
- }
- public function lastInsertId(...$args){
- $id = $this->pdo->lastInsertId(...$args);
- if($id === 0){
- $query = $this->pdo->query("select LAST_INSERT_ID()");
- $id = $query->fetchColumn();
- $query->closeCursor();
- }
- return $id;
- }
- public function getError(){
- $error = $this->pdo->errorInfo();
- return new \Exception($error[2], $error[1]);
- }
- public function stringFilter(array $filter = null){
- $where = '';
- if(!is_null($filter)){
- $where = 'where ';
- foreach($filter as $name => $value){
- if($value instanceof Filter){
- $where .= "`{$name}` {$value} and";
- }else{
- if(is_integer($value)){
- $type = \PDO::PARAM_INT;
- }elseif(is_bool($value)){
- $type = \PDO::PARAM_BOOL;
- }elseif(is_null($value)){
- $type = \PDO::PARAM_NULL;
- }else{
- $type = \PDO::PARAM_STR;
- }
- $where .= "`{$name}` = {$this->quote($value, $type)} and";
- }
- }
- $where = rtrim($where, ' and');
- }
- return $where;
- }
- public function stringSet(array $data){
- $sets = '';
- foreach($data as $name => $value){
- $sets .= "`{$name}` = {$this->quote($value)},";
- }
- if(count($sets) > 0){
- $sets = 'set '.rtrim($sets, ',');
- }
- return $sets;
- }
- public function stringColumn(string $name, array $column){
- $default = '';
- if(!is_null($column['default'])){
- $value = $column['default'];
- if($value instanceof DefaultValue){
- $default .= " DEFAULT {$value}";
- }else{
- if(is_integer($value)){
- $type = \PDO::PARAM_INT;
- }elseif(is_bool($value)){
- $type = \PDO::PARAM_BOOL;
- }else{
- $type = \PDO::PARAM_STR;
- }
- $default .= " DEFAULT {$this->quote($value, $type)}";
- }
- }
- $null = $column['null'] ? ' NULL' : ' NOT NULL';
- $ai = $column['increment'] ? ' AUTO_INCREMENT' : '';
- return "`{$name}` {$column['type']}{$null}{$default}{$ai}";
- }
- public function stringIndex(string $name, array $idx){
- if($idx['unique']){
- return "constraint unique index {$name} (".implode(',', $idx['columns']).")";
- }else{
- return "index {$name} (".implode(',', $idx['columns']).")";
- }
- }
- public function stringForeignKey(string $name, array $foreignKey){
- $cols0 = '';
- $cols1 = '';
- foreach($foreignKey['columns'] as $row){
- $cols0 .= "{$row[0]},";
- $cols1 .= "{$row[1]},";
- }
- $cols0 = rtrim($cols0, ',');
- $cols1 = rtrim($cols1, ',');
- return "constraint `{$name}` foreign key ({$cols0}) references `{$foreignKey['references']}` ({$cols1})";
- }
- }
- ?>
|