$pdo->dbconn, "options" => $pdo->options, "config" => $pdo->config, "migrate" => $pdo->migration, ], $params)); } else { return new static($pdo, $params); } } static function config_errmodeException_lowerCase(self $pdo) { $pdo->db->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION); $pdo->db->setAttribute(\PDO::ATTR_CASE, \PDO::CASE_LOWER); } const OPTIONS = [ \PDO::ATTR_PERSISTENT => true, ]; const CONFIG = [ [self::class, "config_errmodeException_lowerCase"], ]; const MIGRATE = null; const dbconn_SCHEMA = [ "name" => "string", "user" => "?string", "pass" => "?string", ]; const params_SCHEMA = [ "dbconn" => ["array"], "options" => ["?array|callable"], "config" => ["?array|callable"], "migrate" => ["?array|string|callable"], "auto_open" => ["bool", true], ]; function __construct($dbconn=null, ?array $params=null) { if ($dbconn !== null) { if (!is_array($dbconn)) { $dbconn = ["name" => $dbconn]; #XXX à terme, il faudra interroger config #$tmp = config::db($dbconn); #if ($tmp !== null) $dbconn = $tmp; #else $dbconn = ["name" => $dbconn]; } $params["dbconn"] = $dbconn; } # dbconn $this->dbconn = $params["dbconn"] ?? null; $this->dbconn["name"] ??= null; $this->dbconn["user"] ??= null; $this->dbconn["pass"] ??= null; # options $this->options = $params["options"] ?? static::OPTIONS; # configuration $this->config = $params["config"] ?? static::CONFIG; # migrations $this->migration = $params["migrate"] ?? static::MIGRATE; # $defaultAutoOpen = self::params_SCHEMA["auto_open"][1]; if ($params["auto_open"] ?? $defaultAutoOpen) { $this->open(); } } protected ?array $dbconn; /** @var array|callable */ protected array $options; /** @var array|string|callable */ protected $config; /** @var array|string|callable */ protected $migration; protected ?\PDO $db = null; function open(): self { if ($this->db === null) { $dbconn = $this->dbconn; $options = $this->options; if (is_callable($options)) { func::ensure_func($options, $this, $args); $options = func::call($options, ...$args); } $this->db = new \PDO($dbconn["name"], $dbconn["user"], $dbconn["pass"], $options); _config::with($this->config)->configure($this); //_migration::with($this->migration)->migrate($this); } return $this; } function close(): void { $this->db = null; } protected function db(): \PDO { $this->open(); return $this->db; } /** @return int|false */ function _exec(string $query) { return $this->db()->exec($query); } private static function is_insert(?string $sql): bool { if ($sql === null) return false; return preg_match('/^\s*insert\b/i', $sql); } function exec($query, ?array $params=null) { $db = $this->db(); $query = new _query_base($query, $params); if ($query->useStmt($db, $stmt, $sql)) { if ($stmt->execute() === false) return false; if ($query->isInsert()) return $db->lastInsertId(); else return $stmt->rowCount(); } else { $rowCount = $db->exec($sql); if (self::is_insert($sql)) return $db->lastInsertId(); else return $rowCount; } } function beginTransaction(): void { $this->db()->beginTransaction(); } function commit(): void { $this->db()->commit(); } function rollback(): void { $this->db()->rollBack(); } /** * Tester si $date est une date/heure valide de la forme "YYYY-mm-dd HH:MM:SS" * * Si oui, $ms obtient les 6 éléments de la chaine */ static function is_datetime($date, ?array &$ms=null): bool { return is_string($date) && preg_match('/^(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})$/', $date, $ms); } /** * Tester si $date est une date valide de la forme "YYYY-mm-dd [00:00:00]" * * Si oui, $ms obtient les 3 éléments de la chaine */ static function is_date($date, ?array &$ms=null): bool { return is_string($date) && preg_match('/^(\d{4})-(\d{2})-(\d{2})(?: 00:00:00)?$/', $date, $ms); } function verifixRow(array &$row) { foreach ($row as &$value) { if (self::is_date($value)) { $value = new Date($value); } elseif (self::is_date($value)) { $value = new DateTime($value); } }; unset($value); } function get($query, ?array $params=null, bool $entireRow=false) { $db = $this->db(); $query = new _query_base($query, $params); $stmt = null; try { /** @var \PDOStatement $stmt */ if ($query->useStmt($db, $stmt, $sql)) { if ($stmt->execute() === false) return null; } else { $stmt = $db->query($sql); } $row = $stmt->fetch(\PDO::FETCH_ASSOC); if ($row === false) return null; $this->verifixRow($row); if ($entireRow) return $row; else return cl::first($row); } finally { if ($stmt instanceof \PDOStatement) $stmt->closeCursor(); } } function one($query, ?array $params=null): ?array { return $this->get($query, $params, true); } /** * si $primaryKeys est fourni, le résultat est indexé sur la(es) colonne(s) * spécifiée(s) */ function all($query, ?array $params=null, $primaryKeys=null): Generator { $db = $this->db(); $query = new _query_base($query, $params); $stmt = null; try { /** @var \PDOStatement $stmt */ if ($query->useStmt($db, $stmt, $sql)) { if ($stmt->execute() === false) return; } else { $stmt = $db->query($sql); } if ($primaryKeys !== null) $primaryKeys = cl::with($primaryKeys); while (($row = $stmt->fetch(\PDO::FETCH_ASSOC)) !== false) { $this->verifixRow($row); if ($primaryKeys !== null) { $key = implode("-", cl::select($row, $primaryKeys)); yield $key => $row; } else { yield $row; } } } finally { if ($stmt instanceof \PDOStatement) $stmt->closeCursor(); } } }