Reorder and Added missing databases

This commit is contained in:
2023-02-28 23:41:51 -03:00
parent a326904825
commit 99344fda7d
17 changed files with 260 additions and 251 deletions

View File

@ -28,7 +28,7 @@ Database Abstraction Layer
... ...
"require": { "require": {
... ...
"provm/database": "^2.0" "provm/database": "^2.3"
... ...
}, },
... ...
@ -41,13 +41,13 @@ For `MySQL`/`MariaDB`
Without `DI` Without `DI`
``` ```
$database new MySQL(); $database new ProVM\Database\MySQL();
$database->setHost(<host>); $database->setHost(<host>);
$database->setPort(<port>); // If diferent from 3306 $database->setPort(<port>); // If diferent from 3306
$database->setUsername(<username>); $database->setUsername(<username>);
$database->setPassword(<password>); $database->setPassword(<password>);
$connection = new Connection($database); $connection = new ProVM\Database\Connection($database);
``` ```
With `DI` With `DI`
``` ```
@ -76,8 +76,20 @@ $rs = $connection->execute(<query>, <values>);
``` ```
Get data from ResultSet Get data from ResultSet
``` ```
$data = $rs->getAsArray(); $data = $rs->fetchFirst();
$data_objs = $rs->getAsObject(); $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 ## Definitions
@ -97,23 +109,20 @@ Connection handling
+ `Connection::query` Query the database + `Connection::query` Query the database
+ `Connection::prepare` Prepare query statement + `Connection::prepare` Prepare query statement
+ `Connection::execute` Prepare and execute a query statement + `Connection::execute` Prepare and execute a query statement
+ `Conneciton::transaction` Return a transaction + `Connection::transaction` Return a transaction
### Transaction ### Transaction
Transaction Transaction
+ `Transaction::begin` Begin transaction + `Transaction::begin` Begin transaction
+ `Transaction::commit` Commit changes + `Transaction::commit` Commit changes
+ `Transaction::rollBack` Roll back 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 ### ResultSet
Result set to handle PDOStatement Result set to handle PDOStatement
+ `ResultSet::execute` Execute a prepared statement + `ResultSet::execute` Execute a prepared statement
+ `ResultSet::getAsArray` Return query results as array of associative arrays + `ResultSet::fetchAll` Return query results as array of associative arrays
+ `ResultSet::getAsObject` Return query results as array of objects + `ResultSet::fetchAllAsObjects` Return query results as array of objects
+ `ResultSet::getFirst` Return first result as object + `ResultSet::fetchFirst` Return first result as associative array
+ `ResultSet::fetchFirstAsObject` Return first result as object
## TODO ## TODO
+ Implement other database types. eg: PostgreSQL, SQLite

View File

@ -1,17 +1,20 @@
{ {
"name": "provm/database", "name": "provm/database",
"type": "project", "type": "library",
"require-dev": {
"phpunit/phpunit": "^9.5",
"kint-php/kint": "^4.2"
},
"authors": [ "authors": [
{ {
"name": "Aldarien", "name": "Aldarien",
"email": "aldarien85@gmail.com" "email": "aldarien85@gmail.com"
} }
], ],
"require": {}, "require": {
"php": ">=8",
"ext-pdo": "*"
},
"require-dev": {
"phpunit/phpunit": "^10.0",
"kint-php/kint": "^5.0"
},
"autoload": { "autoload": {
"psr-4": { "psr-4": {
"ProVM\\": "src/" "ProVM\\": "src/"

View File

@ -1,58 +0,0 @@
<?php
namespace ProVM\Alias;
use ProVM\Concept\Database as DatabaseInterface;
abstract class Database implements DatabaseInterface
{
protected string $host;
public function setHost(string $host): DatabaseInterface
{
$this->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;
}
}

View File

@ -1,20 +1,18 @@
<?php <?php
namespace ProVM\Concept; namespace ProVM\Concept;
use PDO;
interface Database interface Database
{ {
public function setHost(string $host): Database;
public function getHost(): string; public function getHost(): string;
public function setPort(int $port): Database; public function getPort(): int|bool;
public function getPort(): int;
public function setName(string $name): Database;
public function getName(): string; public function getName(): string;
public function setUsername(string $username): Database; public function getUser(): string;
public function getUsername(): string;
public function setPassword(string $password): Database;
public function getPassword(): string; public function getPassword(): string;
public function needsUser(): bool; public function needsUser(): bool;
public function getDSN(): string; public function setHost(string $host): Database;
public function setPort(int $port): Database;
public function setName(string $name): Database;
public function setUser(string $username): Database;
public function setPassword(string $password): Database;
public function getDsn(): string;
} }

View File

@ -1,18 +1,15 @@
<?php <?php
namespace ProVM\Concept\Database; namespace ProVM\Concept\Database;
use PDO;
use ProVM\Concept\Database; use ProVM\Concept\Database;
interface Connection interface Connection
{ {
public function setDatabase(Database $database): Connection; public function connect(): \PDO;
public function getDatabase(): Database;
public function connect(): Connection; public function transaction(): Transaction;
public function setPDO(PDO $pdo): Connection;
public function getPDO(): PDO;
public function query(string $query): ResultSet; public function query(string $query): ResultSet;
public function prepare(string $query): ResultSet; public function prepare(string $query): ResultSet;
public function execute(string $query, array $values): ResultSet; public function execute(string $query, ?array $data = null): ResultSet;
public function transaction(): Transaction;
} }

View File

@ -1,14 +1,12 @@
<?php <?php
namespace ProVM\Concept\Database; namespace ProVM\Concept\Database;
use PDOStatement;
interface ResultSet interface ResultSet
{ {
public function __construct(PDOStatement $statement); public function execute(array $data): ResultSet;
public function execute(array $values): ResultSet;
public function getAsArray(): array; public function fetchFirst(): array;
public function getAsObject(): array; public function fetchAll(): array;
public function getFirstAsArray(): array; public function fetchFirstAsObject(): object;
public function getFirstAsObject(): object; public function fetchAllAsObjects(): array;
} }

View File

@ -4,9 +4,6 @@ namespace ProVM\Concept\Database;
interface Transaction interface Transaction
{ {
public function begin(): Transaction; public function begin(): Transaction;
public function query(string $query): ResultSet;
public function prepare(string $query): ResultSet;
public function execute(string $query, array $values): ResultSet;
public function commit(): void; public function commit(): void;
public function rollBack(): void; public function rollBack(): void;
} }

View File

@ -2,74 +2,67 @@
namespace ProVM\Database; namespace ProVM\Database;
use PDO; use PDO;
use PDOException;
use ProVM\Concept\Database; use ProVM\Concept\Database;
use ProVM\Concept\Database\Connection as ConnectionInterface;
use ProVM\Concept\Database\ResultSet as ResultSetInterface;
use ProVM\Concept\Database\Transaction as TransactionInterface;
class Connection implements ConnectionInterface class Connection implements Database\Connection
{ {
public function __construct(Database $database) public function __construct(Database $database)
{ {
$this->setDatabase($database); $this->setDatabase($database);
$this->connect();
} }
protected Database $database; 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; $this->database = $database;
return $this; return $this;
} }
public function getDatabase(): Database
{ protected PDO $pdo;
return $this->database; public function connect(): PDO
}
public function connect(): ConnectionInterface
{ {
if (!isset($this->pdo)) { if (!isset($this->pdo)) {
$dsn = $this->getDatabase()->getDsn();
if ($this->getDatabase()->needsUser()) { 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 { } 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; return $this->pdo;
} }
public function query(string $query): ResultSetInterface
protected Database\Transaction $transaction;
public function transaction(): Database\Transaction
{ {
$st = $this->getPDO()->query($query); if (!isset($this->transaction)) {
if (!$st) { $this->transaction = new Transaction($this);
throw new PDOException("Could not run query {$query}");
} }
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); return new ResultSet($this->connect()->query($query));
if (!$st) { }
throw new PDOException("Could not prepare 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); return $this->query($query);
}
public function execute(string $query, array $values): ResultSetInterface
{
return $this->prepare($query)->execute($values);
}
public function transaction(): TransactionInterface
{
return new Transaction($this->getPDO());
} }
} }

View File

@ -1,7 +1,7 @@
<?php <?php
namespace ProVM\Database; namespace ProVM\Database;
use ProVM\Alias\Database; use ProVM\Implement\Database;
class MySQL extends Database class MySQL extends Database
{ {
@ -9,20 +9,13 @@ class MySQL extends Database
{ {
return true; return true;
} }
public function getDsn(): string
public function getDSN(): string
{ {
$arr = [ $dsn = ["mysql:host={$this->getHost()}"];
"host={$this->getHost()}" if ($this->getPort()) {
]; $dsn []= "port={$this->getPort()}";
if (isset($this->port)) {
$arr []= "port={$this->getPort()}";
} }
$arr []= "dbname={$this->getName()}"; $dsn []= "dbname={$this->getName()}";
return implode(';', $dsn);
return implode(':', [
'mysql',
implode(';', $arr)
]);
} }
} }

View File

@ -0,0 +1,19 @@
<?php
namespace ProVM\Database;
use ProVM\Implement\Database;
class PostgreSQL extends Database
{
public function getDsn(): string
{
$dsn = ["pgsql:host={$this->getHost()}"];
if ($this->getPort()) {
$dsn []= "port={$this->getPort()}";
}
$dsn []= "dbname={$this->getName()}";
$dsn []= "user={$this->getUser()}";
$dsn []= "password={$this->getPassword()}";
return implode(';', $dsn);
}
}

View File

@ -3,10 +3,10 @@ namespace ProVM\Database;
use PDO; use PDO;
use PDOStatement; use PDOStatement;
use ProVM\Concept\Database\ResultSet as RSInterface; use ProVM\Concept\Database;
use ProVM\Exception\BlankResult; use ProVM\Exception\Database\BlankResult;
class ResultSet implements RSInterface class ResultSet implements Database\ResultSet
{ {
public function __construct(PDOStatement $statement) public function __construct(PDOStatement $statement)
{ {
@ -14,52 +14,44 @@ class ResultSet implements RSInterface
} }
protected PDOStatement $statement; 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; $this->statement = $statement;
return $this; 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; return $this;
} }
public function getAsArray(): array protected function checkResults(): PDOStatement
{ {
$rs = $this->getStatement()->fetchAll(PDO::FETCH_ASSOC); if ($this->getStatement()->rowCount() === 0) {
if (!$rs) { throw new BlankResult(query: $this->getStatement()->queryString);
throw new BlankResult();
} }
return $rs; return $this->getStatement();
} }
public function getAsObject(): array public function fetchFirst(): array
{ {
$rs = $this->getStatement()->fetchAll(PDO::FETCH_OBJ); return $this->checkResults()->fetch(PDO::FETCH_ASSOC);
if (!$rs) {
throw new BlankResult();
}
return $rs;
} }
public function getFirstAsArray(): array public function fetchAll(): array
{ {
$rs = $this->getStatement()->fetch(PDO::FETCH_ASSOC); return $this->checkResults()->fetchAll(PDO::FETCH_ASSOC);
if (!$rs or count($rs) === 0) {
throw new BlankResult();
}
return $rs;
} }
public function getFirstAsObject(): object public function fetchFirstAsObject(): object
{ {
$rs = $this->getStatement()->fetch(PDO::FETCH_OBJ); return $this->checkResults()->fetch(PDO::FETCH_OBJ);
if (!$rs or count($rs) === 0) { }
throw new BlankResult(); public function fetchAllAsObjects(): array
} {
return $rs; return $this->checkResults()->fetchAll(PDO::FETCH_OBJ);
} }
} }

12
src/Database/SQLite.php Normal file
View File

@ -0,0 +1,12 @@
<?php
namespace ProVM\Database;
use ProVM\Implement\Database;
class SQLite extends Database
{
public function getDsn(): string
{
return "sqlite:{$this->getHost()}";
}
}

View File

@ -2,58 +2,39 @@
namespace ProVM\Database; namespace ProVM\Database;
use PDO; use PDO;
use PDOException; use ProVM\Concept;
use ProVM\Concept\Database\ResultSet as ResultSetInterface;
use ProVM\Concept\Database\Transaction as TransactionInterface;
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; protected Concept\Database\Connection $connection;
public function setPDO(PDO $pdo): TransactionInterface
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; return $this;
} }
public function getPDO(): PDO
public function begin(): Concept\Database\Transaction
{ {
return $this->pdo; $this->getConnection()->connect()->beginTransaction();
}
public function begin(): TransactionInterface
{
$this->getPDO()->beginTransaction();
return $this; 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 public function commit(): void
{ {
$this->getPDO()->commit(); $this->getConnection()->connect()->commit();
} }
public function rollBack(): void public function rollBack(): void
{ {
$this->getPDO()->rollBack(); $this->getConnection()->connect()->rollBack();
} }
} }

View File

@ -1,15 +0,0 @@
<?php
namespace ProVM\Exception;
use ProVM\Database\Exception;
use Throwable;
class BlankResult extends Exception
{
public function __construct(?Throwable $previous = null)
{
$message = "No results found";
$code = 0;
parent::__construct($message, $code, $previous);
}
}

View File

@ -1,11 +1,16 @@
<?php <?php
namespace ProVM\Database; namespace ProVM\Exception;
class Exception extends \Exception use Exception;
use Throwable;
abstract class Database extends Exception
{ {
const BASE_CODE = 600;
public function __construct(string $message = "", int $code = 0, ?Throwable $previous = null) public function __construct(string $message = "", int $code = 0, ?Throwable $previous = null)
{ {
$code += 300; $code += Database::BASE_CODE;
parent::__construct($message, $code, $previous); parent::__construct($message, $code, $previous);
} }
} }

View File

@ -0,0 +1,20 @@
<?php
namespace ProVM\Exception\Database;
use Throwable;
use ProVM\Exception\Database;
class BlankResult extends Database
{
public function __construct(?string $table = null, ?string $query = null, ?Throwable $previous = null)
{
$message = implode('', [
"No results found",
($query !== null) ? " in {$query}" : '',
($table !== null) ? " in {$table}" : '',
'.'
]);
$code = 1;
parent::__construct($message, $code, $previous);
}
}

View File

@ -0,0 +1,65 @@
<?php
namespace ProVM\Implement;
use ProVM\Concept;
abstract class Database implements Concept\Database
{
protected string $host;
protected int $port;
protected string $name;
protected string $user;
protected string $password;
public function getHost(): string
{
return $this->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;
}
}