diff --git a/Readme.md b/Readme.md index aab6d10..f2c9f89 100644 --- a/Readme.md +++ b/Readme.md @@ -28,7 +28,7 @@ Database Abstraction Layer ... "require": { ... - "provm/database": "^2.0" + "provm/database": "^2.3" ... }, ... @@ -41,13 +41,13 @@ For `MySQL`/`MariaDB` Without `DI` ``` -$database new MySQL(); +$database new ProVM\Database\MySQL(); $database->setHost(); $database->setPort(); // If diferent from 3306 $database->setUsername(); $database->setPassword(); -$connection = new Connection($database); +$connection = new ProVM\Database\Connection($database); ``` With `DI` ``` @@ -76,8 +76,20 @@ $rs = $connection->execute(, ); ``` Get data from ResultSet ``` -$data = $rs->getAsArray(); -$data_objs = $rs->getAsObject(); +$data = $rs->fetchFirst(); +$data_object = $rs->fetchFirstAsObject(); +$data_array = $rs->fetchAll(); +$data_array_of_objects = $rs->fetchAllAsObjects(); +``` +Use transactions +``` +$connection->transaction()->begin(); +try { + $connection->execute($query, $values); + $connection->transaction()->commit(); +} catch (PDOException $exception) { + $connection->transaction()->rollBack(); +} ``` ## Definitions @@ -97,23 +109,20 @@ Connection handling + `Connection::query` Query the database + `Connection::prepare` Prepare query statement + `Connection::execute` Prepare and execute a query statement -+ `Conneciton::transaction` Return a transaction ++ `Connection::transaction` Return a transaction ### Transaction Transaction + `Transaction::begin` Begin transaction + `Transaction::commit` Commit changes + `Transaction::rollBack` Roll back changes -+ `Transaction::query` Same as `Connection::query` -+ `Transaction::prepare` Same as `Connection::prepare` -+ `Transaction::execute` Same as `Connection::execute` ### ResultSet Result set to handle PDOStatement + `ResultSet::execute` Execute a prepared statement -+ `ResultSet::getAsArray` Return query results as array of associative arrays -+ `ResultSet::getAsObject` Return query results as array of objects -+ `ResultSet::getFirst` Return first result as object ++ `ResultSet::fetchAll` Return query results as array of associative arrays ++ `ResultSet::fetchAllAsObjects` Return query results as array of objects ++ `ResultSet::fetchFirst` Return first result as associative array ++ `ResultSet::fetchFirstAsObject` Return first result as object ## TODO -+ Implement other database types. eg: PostgreSQL, SQLite diff --git a/composer.json b/composer.json index e70f7c1..85a3f71 100644 --- a/composer.json +++ b/composer.json @@ -1,17 +1,20 @@ { "name": "provm/database", - "type": "project", - "require-dev": { - "phpunit/phpunit": "^9.5", - "kint-php/kint": "^4.2" - }, + "type": "library", "authors": [ { "name": "Aldarien", "email": "aldarien85@gmail.com" } ], - "require": {}, + "require": { + "php": ">=8", + "ext-pdo": "*" + }, + "require-dev": { + "phpunit/phpunit": "^10.0", + "kint-php/kint": "^5.0" + }, "autoload": { "psr-4": { "ProVM\\": "src/" diff --git a/src/Alias/Database.php b/src/Alias/Database.php deleted file mode 100644 index 8ece3db..0000000 --- a/src/Alias/Database.php +++ /dev/null @@ -1,58 +0,0 @@ -host = $host; - return $this; - } - public function getHost(): string - { - return $this->host; - } - protected int $port; - public function setPort(int $port): DatabaseInterface - { - $this->port = $port; - return $this; - } - public function getPort(): int - { - return $this->port; - } - protected string $name; - public function setName(string $name): DatabaseInterface - { - $this->name = $name; - return $this; - } - public function getName(): string - { - return $this->name; - } - protected string $username; - public function setUsername(string $username): DatabaseInterface - { - $this->username = $username; - return $this; - } - public function getUsername(): string - { - return $this->username; - } - protected string $password; - public function setPassword(string $password): DatabaseInterface - { - $this->password = $password; - return $this; - } - public function getPassword(): string - { - return $this->password; - } -} diff --git a/src/Concept/Database.php b/src/Concept/Database.php index 0ed1e0d..bc9f2a9 100644 --- a/src/Concept/Database.php +++ b/src/Concept/Database.php @@ -1,20 +1,18 @@ setDatabase($database); - $this->connect(); } protected Database $database; - public function setDatabase(Database $database): ConnectionInterface + + protected function getDatabase(): Database + { + return $this->database; + } + + protected function setDatabase(Database $database): Database\Connection { $this->database = $database; return $this; } - public function getDatabase(): Database - { - return $this->database; - } - public function connect(): ConnectionInterface + + protected PDO $pdo; + public function connect(): PDO { if (!isset($this->pdo)) { + $dsn = $this->getDatabase()->getDsn(); if ($this->getDatabase()->needsUser()) { - $pdo = new PDO($this->getDatabase()->getDSN(), $this->getDatabase()->getUsername(), $this->getDatabase()->getPassword()); + $this->pdo = new PDO($dsn, $this->getDatabase()->getUser(), $this->getDatabase()->getPassword()); } else { - $pdo = new PDO($this->getDatabase()->getDSN()); + $this->pdo = new PDO($dsn); } - $this->setPDO($pdo); } - return $this; - } - protected PDO $pdo; - public function setPDO(PDO $pdo): ConnectionInterface - { - $this->pdo = $pdo; - return $this; - } - public function getPDO(): PDO - { return $this->pdo; } - public function query(string $query): ResultSetInterface + + protected Database\Transaction $transaction; + + public function transaction(): Database\Transaction { - $st = $this->getPDO()->query($query); - if (!$st) { - throw new PDOException("Could not run query {$query}"); + if (!isset($this->transaction)) { + $this->transaction = new Transaction($this); } - return new ResultSet($st); + return $this->transaction; } - public function prepare(string $query): ResultSetInterface + + public function query(string $query): Database\ResultSet { - $st = $this->getPDO()->prepare($query); - if (!$st) { - throw new PDOException("Could not prepare query {$query}"); + return new ResultSet($this->connect()->query($query)); + } + public function prepare(string $query): Database\ResultSet + { + return new ResultSet($this->connect()->prepare($query)); + } + public function execute(string $query, ?array $data = null): Database\ResultSet + { + if ($data !== null) { + $rs = $this->prepare($query); + $rs->execute($data); + return $rs; } - return new ResultSet($st); - } - public function execute(string $query, array $values): ResultSetInterface - { - return $this->prepare($query)->execute($values); - } - public function transaction(): TransactionInterface - { - return new Transaction($this->getPDO()); + return $this->query($query); } } diff --git a/src/Database/MySQL.php b/src/Database/MySQL.php index 9836747..a4e009f 100644 --- a/src/Database/MySQL.php +++ b/src/Database/MySQL.php @@ -1,7 +1,7 @@ getHost()}" - ]; - if (isset($this->port)) { - $arr []= "port={$this->getPort()}"; + $dsn = ["mysql:host={$this->getHost()}"]; + if ($this->getPort()) { + $dsn []= "port={$this->getPort()}"; } - $arr []= "dbname={$this->getName()}"; - - return implode(':', [ - 'mysql', - implode(';', $arr) - ]); + $dsn []= "dbname={$this->getName()}"; + return implode(';', $dsn); } } diff --git a/src/Database/PostgreSQL.php b/src/Database/PostgreSQL.php new file mode 100644 index 0000000..fc83fe6 --- /dev/null +++ b/src/Database/PostgreSQL.php @@ -0,0 +1,19 @@ +getHost()}"]; + if ($this->getPort()) { + $dsn []= "port={$this->getPort()}"; + } + $dsn []= "dbname={$this->getName()}"; + $dsn []= "user={$this->getUser()}"; + $dsn []= "password={$this->getPassword()}"; + return implode(';', $dsn); + } +} diff --git a/src/Database/ResultSet.php b/src/Database/ResultSet.php index 6654eb7..d357ffc 100644 --- a/src/Database/ResultSet.php +++ b/src/Database/ResultSet.php @@ -3,10 +3,10 @@ namespace ProVM\Database; use PDO; use PDOStatement; -use ProVM\Concept\Database\ResultSet as RSInterface; -use ProVM\Exception\BlankResult; +use ProVM\Concept\Database; +use ProVM\Exception\Database\BlankResult; -class ResultSet implements RSInterface +class ResultSet implements Database\ResultSet { public function __construct(PDOStatement $statement) { @@ -14,52 +14,44 @@ class ResultSet implements RSInterface } protected PDOStatement $statement; - public function setStatement(PDOStatement $statement): RSInterface + + protected function getStatement(): PDOStatement + { + return $this->statement; + } + protected function setStatement(PDOStatement $statement): ResultSet { $this->statement = $statement; return $this; } - public function getStatement(): PDOStatement - { - return $this->statement; - } - public function execute(array $values): RSInterface + public function execute(array $data): Database\ResultSet { - $this->getStatement()->execute($values); + $this->statement->execute($data); return $this; } - public function getAsArray(): array + protected function checkResults(): PDOStatement { - $rs = $this->getStatement()->fetchAll(PDO::FETCH_ASSOC); - if (!$rs) { - throw new BlankResult(); + if ($this->getStatement()->rowCount() === 0) { + throw new BlankResult(query: $this->getStatement()->queryString); } - return $rs; + return $this->getStatement(); } - public function getAsObject(): array + public function fetchFirst(): array { - $rs = $this->getStatement()->fetchAll(PDO::FETCH_OBJ); - if (!$rs) { - throw new BlankResult(); - } - return $rs; + return $this->checkResults()->fetch(PDO::FETCH_ASSOC); } - public function getFirstAsArray(): array + public function fetchAll(): array { - $rs = $this->getStatement()->fetch(PDO::FETCH_ASSOC); - if (!$rs or count($rs) === 0) { - throw new BlankResult(); - } - return $rs; + return $this->checkResults()->fetchAll(PDO::FETCH_ASSOC); } - public function getFirstAsObject(): object + public function fetchFirstAsObject(): object { - $rs = $this->getStatement()->fetch(PDO::FETCH_OBJ); - if (!$rs or count($rs) === 0) { - throw new BlankResult(); - } - return $rs; + return $this->checkResults()->fetch(PDO::FETCH_OBJ); + } + public function fetchAllAsObjects(): array + { + return $this->checkResults()->fetchAll(PDO::FETCH_OBJ); } } diff --git a/src/Database/SQLite.php b/src/Database/SQLite.php new file mode 100644 index 0000000..f8ab299 --- /dev/null +++ b/src/Database/SQLite.php @@ -0,0 +1,12 @@ +getHost()}"; + } +} diff --git a/src/Database/Transaction.php b/src/Database/Transaction.php index 7901640..3181903 100644 --- a/src/Database/Transaction.php +++ b/src/Database/Transaction.php @@ -2,58 +2,39 @@ namespace ProVM\Database; use PDO; -use PDOException; -use ProVM\Concept\Database\ResultSet as ResultSetInterface; -use ProVM\Concept\Database\Transaction as TransactionInterface; +use ProVM\Concept; -class Transaction implements TransactionInterface +class Transaction implements Concept\Database\Transaction { - public function __construct(PDO $pdo) + public function __construct(Concept\Database\Connection $connection) { - $this->setPDO($pdo); + $this->setConnection($connection); } - protected PDO $pdo; - public function setPDO(PDO $pdo): TransactionInterface + protected Concept\Database\Connection $connection; + + public function getConnection(): Concept\Database\Connection { - $this->pdo = $pdo; + return $this->connection; + } + + public function setConnection(Concept\Database\Connection $connection): Concept\Database\Transaction + { + $this->connection = $connection; return $this; } - public function getPDO(): PDO + + public function begin(): Concept\Database\Transaction { - return $this->pdo; - } - public function begin(): TransactionInterface - { - $this->getPDO()->beginTransaction(); + $this->getConnection()->connect()->beginTransaction(); return $this; } - public function query(string $query): ResultSetInterface - { - $st = $this->getPDO()->query($query); - if (!$st) { - throw new PDOException("Could not run query {$query}"); - } - return new ResultSet($st); - } - public function prepare(string $query): ResultSetInterface - { - $st = $this->getPDO()->prepare($query); - if (!$st) { - throw new PDOException("Could not prepare query {$query}"); - } - return new ResultSet($st); - } - public function execute(string $query, array $values): ResultSetInterface - { - return $this->prepare($query)->execute($values); - } public function commit(): void { - $this->getPDO()->commit(); + $this->getConnection()->connect()->commit(); } public function rollBack(): void { - $this->getPDO()->rollBack(); + $this->getConnection()->connect()->rollBack(); } } diff --git a/src/Exception/BlankResult.php b/src/Exception/BlankResult.php deleted file mode 100644 index 09fb226..0000000 --- a/src/Exception/BlankResult.php +++ /dev/null @@ -1,15 +0,0 @@ -host; + } + public function getPort(): int|bool + { + return $this->port ?? false; + } + public function getName(): string + { + return $this->name; + } + public function getUser(): string + { + return $this->user; + } + public function getPassword(): string + { + return $this->password; + } + + public function setHost(string $host): Concept\Database + { + $this->host = $host; + return $this; + } + public function setPort(int $port): Concept\Database + { + $this->port = $port; + return $this; + } + public function setName(string $name): Concept\Database + { + $this->name = $name; + return $this; + } + public function setUser(string $username): Concept\Database + { + $this->user = $username; + return $this; + } + public function setPassword(string $password): Concept\Database + { + $this->password = $password; + return $this; + } + + public function needsUser(): bool + { + return false; + } +}