Compare commits
4 Commits
develop
...
ac9b141928
Author | SHA1 | Date | |
---|---|---|---|
ac9b141928 | |||
d5fde83afb | |||
ec19c25681 | |||
6b978c371c |
2
.gitignore
vendored
2
.gitignore
vendored
@ -4,5 +4,3 @@
|
|||||||
|
|
||||||
# PHPStorm
|
# PHPStorm
|
||||||
**/.idea/
|
**/.idea/
|
||||||
|
|
||||||
**/.cache/
|
|
||||||
|
22
Dockerfile
22
Dockerfile
@ -1,22 +0,0 @@
|
|||||||
FROM composer:lts as deps
|
|
||||||
WORKDIR /app
|
|
||||||
RUN --mount=type=bind,source=./composer.json,target=composer.json \
|
|
||||||
--mount=type=bind,source=./composer.lock,target=composer.lock \
|
|
||||||
--mount=type=cache,target=/tmp/cache \
|
|
||||||
composer install --no-interaction
|
|
||||||
|
|
||||||
FROM php:8-cli as base
|
|
||||||
WORKDIR /app
|
|
||||||
RUN apt-get update && \
|
|
||||||
apt-get install -yq --no-install-recommends libsqlite3-dev && \
|
|
||||||
rm -rf /var/lib/apt/lists/* && \
|
|
||||||
docker-php-ext-install pdo pdo_sqlite
|
|
||||||
COPY ./src /app/src
|
|
||||||
|
|
||||||
FROM base as dev
|
|
||||||
COPY ./tests /app/tests
|
|
||||||
RUN mv "$PHP_INI_DIR/php.ini-development" "$PHP_INI_DIR/php.ini"
|
|
||||||
COPY --from=deps /app/vendor/ /app/vendor
|
|
||||||
|
|
||||||
FROM dev as test
|
|
||||||
ENTRYPOINT [ "./vendor/bin/phpunit" ]
|
|
35
Readme.md
35
Readme.md
@ -28,7 +28,7 @@ Database Abstraction Layer
|
|||||||
...
|
...
|
||||||
"require": {
|
"require": {
|
||||||
...
|
...
|
||||||
"provm/database": "^2.3"
|
"provm/database": "^2.0"
|
||||||
...
|
...
|
||||||
},
|
},
|
||||||
...
|
...
|
||||||
@ -41,13 +41,13 @@ For `MySQL`/`MariaDB`
|
|||||||
|
|
||||||
Without `DI`
|
Without `DI`
|
||||||
```
|
```
|
||||||
$database new ProVM\Database\MySQL();
|
$database new 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 ProVM\Database\Connection($database);
|
$connection = new Connection($database);
|
||||||
```
|
```
|
||||||
With `DI`
|
With `DI`
|
||||||
```
|
```
|
||||||
@ -76,20 +76,8 @@ $rs = $connection->execute(<query>, <values>);
|
|||||||
```
|
```
|
||||||
Get data from ResultSet
|
Get data from ResultSet
|
||||||
```
|
```
|
||||||
$data = $rs->fetchFirst();
|
$data = $rs->getAsArray();
|
||||||
$data_object = $rs->fetchFirstAsObject();
|
$data_objs = $rs->getAsObject();
|
||||||
$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
|
||||||
@ -109,20 +97,23 @@ 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
|
||||||
+ `Connection::transaction` Return a transaction
|
+ `Conneciton::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::fetchAll` Return query results as array of associative arrays
|
+ `ResultSet::getAsArray` Return query results as array of associative arrays
|
||||||
+ `ResultSet::fetchAllAsObjects` Return query results as array of objects
|
+ `ResultSet::getAsObject` Return query results as array of objects
|
||||||
+ `ResultSet::fetchFirst` Return first result as associative array
|
+ `ResultSet::getFirst` Return first result as object
|
||||||
+ `ResultSet::fetchFirstAsObject` Return first result as object
|
|
||||||
|
|
||||||
## TODO
|
## TODO
|
||||||
|
+ Implement other database types. eg: PostgreSQL, SQLite
|
||||||
|
@ -1,5 +0,0 @@
|
|||||||
services:
|
|
||||||
database:
|
|
||||||
build: .
|
|
||||||
volumes:
|
|
||||||
- ./:/app
|
|
@ -1,20 +1,17 @@
|
|||||||
{
|
{
|
||||||
"name": "provm/database",
|
"name": "provm/database",
|
||||||
"type": "library",
|
"type": "project",
|
||||||
"version": "1.2.0",
|
"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"
|
|
||||||
},
|
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"psr-4": {
|
"psr-4": {
|
||||||
"ProVM\\": "src/"
|
"ProVM\\": "src/"
|
||||||
|
28
phpunit.xml
28
phpunit.xml
@ -1,28 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.5/phpunit.xsd"
|
|
||||||
bootstrap="vendor/autoload.php"
|
|
||||||
cacheResultFile=".cache/test-results"
|
|
||||||
executionOrder="depends,defects"
|
|
||||||
forceCoversAnnotation="false"
|
|
||||||
beStrictAboutCoversAnnotation="true"
|
|
||||||
beStrictAboutOutputDuringTests="true"
|
|
||||||
beStrictAboutTodoAnnotatedTests="true"
|
|
||||||
convertDeprecationsToExceptions="true"
|
|
||||||
colors="true"
|
|
||||||
failOnRisky="true"
|
|
||||||
failOnWarning="true"
|
|
||||||
verbose="true">
|
|
||||||
<testsuites>
|
|
||||||
<testsuite name="default">
|
|
||||||
<directory>tests</directory>
|
|
||||||
</testsuite>
|
|
||||||
</testsuites>
|
|
||||||
|
|
||||||
<coverage cacheDirectory=".cache/code-coverage"
|
|
||||||
processUncoveredFiles="true">
|
|
||||||
<include>
|
|
||||||
<directory suffix=".php">src</directory>
|
|
||||||
</include>
|
|
||||||
</coverage>
|
|
||||||
</phpunit>
|
|
58
src/Alias/Database.php
Normal file
58
src/Alias/Database.php
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
<?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;
|
||||||
|
}
|
||||||
|
}
|
@ -1,18 +1,20 @@
|
|||||||
<?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 getPort(): int|bool;
|
public function setPort(int $port): Database;
|
||||||
|
public function getPort(): int;
|
||||||
|
public function setName(string $name): Database;
|
||||||
public function getName(): string;
|
public function getName(): string;
|
||||||
public function getUser(): string;
|
public function setUsername(string $username): Database;
|
||||||
|
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 setHost(string $host): Database;
|
public function getDSN(): string;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,18 @@
|
|||||||
<?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 connect(): \PDO;
|
public function setDatabase(Database $database): Connection;
|
||||||
|
public function getDatabase(): Database;
|
||||||
public function transaction(): Transaction;
|
public function connect(): Connection;
|
||||||
|
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 $data = null): ResultSet;
|
public function execute(string $query, array $values): ResultSet;
|
||||||
|
public function transaction(): Transaction;
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,14 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace ProVM\Concept\Database;
|
namespace ProVM\Concept\Database;
|
||||||
|
|
||||||
|
use PDOStatement;
|
||||||
|
|
||||||
interface ResultSet
|
interface ResultSet
|
||||||
{
|
{
|
||||||
public function execute(array $data): ResultSet;
|
public function __construct(PDOStatement $statement);
|
||||||
|
public function execute(array $values): ResultSet;
|
||||||
public function fetchFirst(): array;
|
public function getAsArray(): array;
|
||||||
public function fetchAll(): array;
|
public function getAsObject(): array;
|
||||||
public function fetchFirstAsObject(): object;
|
public function getFirstAsArray(): array;
|
||||||
public function fetchAllAsObjects(): array;
|
public function getFirstAsObject(): object;
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,9 @@ 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;
|
||||||
}
|
}
|
||||||
|
@ -2,85 +2,74 @@
|
|||||||
namespace ProVM\Database;
|
namespace ProVM\Database;
|
||||||
|
|
||||||
use PDO;
|
use PDO;
|
||||||
|
use PDOException;
|
||||||
use ProVM\Concept\Database;
|
use ProVM\Concept\Database;
|
||||||
use ProVM\Exception\Database\InvalidQuery;
|
use ProVM\Concept\Database\Connection as ConnectionInterface;
|
||||||
|
use ProVM\Concept\Database\ResultSet as ResultSetInterface;
|
||||||
|
use ProVM\Concept\Database\Transaction as TransactionInterface;
|
||||||
|
|
||||||
class Connection implements Database\Connection
|
class Connection implements ConnectionInterface
|
||||||
{
|
{
|
||||||
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;
|
{
|
||||||
public function connect(): PDO
|
return $this->database;
|
||||||
|
}
|
||||||
|
public function connect(): ConnectionInterface
|
||||||
{
|
{
|
||||||
if (!isset($this->pdo)) {
|
if (!isset($this->pdo)) {
|
||||||
$dsn = $this->getDatabase()->getDsn();
|
|
||||||
if ($this->getDatabase()->needsUser()) {
|
if ($this->getDatabase()->needsUser()) {
|
||||||
$this->pdo = new PDO($dsn, $this->getDatabase()->getUser(), $this->getDatabase()->getPassword());
|
$pdo = new PDO($this->getDatabase()->getDSN(), $this->getDatabase()->getUsername(), $this->getDatabase()->getPassword());
|
||||||
} else {
|
} else {
|
||||||
$this->pdo = new PDO($dsn);
|
$pdo = new PDO($this->getDatabase()->getDSN());
|
||||||
}
|
}
|
||||||
|
$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
|
|
||||||
{
|
{
|
||||||
if (!isset($this->transaction)) {
|
$st = $this->getPDO()->query($query);
|
||||||
$this->transaction = new Transaction($this);
|
if (!$st) {
|
||||||
|
throw new PDOException("Could not run query {$query}");
|
||||||
}
|
}
|
||||||
return $this->transaction;
|
return new ResultSet($st);
|
||||||
}
|
}
|
||||||
|
public function prepare(string $query): ResultSetInterface
|
||||||
public function query(string $query): Database\ResultSet
|
|
||||||
{
|
{
|
||||||
$statement = $this->connect()->query($query);
|
$st = $this->getPDO()->prepare($query);
|
||||||
if ($statement === false) {
|
if (!$st) {
|
||||||
throw new InvalidQuery($query);
|
throw new PDOException("Could not prepare query {$query}");
|
||||||
}
|
}
|
||||||
return new ResultSet($statement);
|
return new ResultSet($st);
|
||||||
}
|
}
|
||||||
public function prepare(string $query): Database\ResultSet
|
public function execute(string $query, array $values): ResultSetInterface
|
||||||
{
|
{
|
||||||
$statement = $this->connect()->prepare($query);
|
return $this->prepare($query)->execute($values);
|
||||||
if ($statement === false) {
|
|
||||||
throw new InvalidQuery($query);
|
|
||||||
}
|
|
||||||
return new ResultSet($statement);
|
|
||||||
}
|
}
|
||||||
public function execute(string $query, ?array $data = null): Database\ResultSet
|
public function transaction(): TransactionInterface
|
||||||
{
|
{
|
||||||
if ($data !== null) {
|
return new Transaction($this->getPDO());
|
||||||
$rs = $this->prepare($query);
|
|
||||||
$rs->execute($data);
|
|
||||||
return $rs;
|
|
||||||
}
|
|
||||||
return $this->query($query);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function fetchOne(string $query, ?array $data = null): array
|
|
||||||
{
|
|
||||||
return $this->execute($query, $data)->fetchFirst();
|
|
||||||
}
|
|
||||||
public function fetchMany(string $query, ?array $data = null): array
|
|
||||||
{
|
|
||||||
return $this->execute($query, $data)->fetchAll();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace ProVM\Database;
|
namespace ProVM\Database;
|
||||||
|
|
||||||
use ProVM\Implement\Database;
|
use ProVM\Alias\Database;
|
||||||
|
|
||||||
class MySQL extends Database
|
class MySQL extends Database
|
||||||
{
|
{
|
||||||
@ -9,13 +9,20 @@ class MySQL extends Database
|
|||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
public function getDsn(): string
|
|
||||||
|
public function getDSN(): string
|
||||||
{
|
{
|
||||||
$dsn = ["mysql:host={$this->getHost()}"];
|
$arr = [
|
||||||
if ($this->getPort()) {
|
"host={$this->getHost()}"
|
||||||
$dsn []= "port={$this->getPort()}";
|
];
|
||||||
|
if (isset($this->port)) {
|
||||||
|
$arr []= "port={$this->getPort()}";
|
||||||
}
|
}
|
||||||
$dsn []= "dbname={$this->getName()}";
|
$arr []= "dbname={$this->getName()}";
|
||||||
return implode(';', $dsn);
|
|
||||||
|
return implode(':', [
|
||||||
|
'mysql',
|
||||||
|
implode(';', $arr)
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,19 +0,0 @@
|
|||||||
<?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);
|
|
||||||
}
|
|
||||||
}
|
|
@ -3,10 +3,9 @@ namespace ProVM\Database;
|
|||||||
|
|
||||||
use PDO;
|
use PDO;
|
||||||
use PDOStatement;
|
use PDOStatement;
|
||||||
use ProVM\Concept\Database;
|
use ProVM\Concept\Database\ResultSet as RSInterface;
|
||||||
use ProVM\Exception\Database\BlankResult;
|
|
||||||
|
|
||||||
class ResultSet implements Database\ResultSet
|
class ResultSet implements RSInterface
|
||||||
{
|
{
|
||||||
public function __construct(PDOStatement $statement)
|
public function __construct(PDOStatement $statement)
|
||||||
{
|
{
|
||||||
@ -14,44 +13,36 @@ class ResultSet implements Database\ResultSet
|
|||||||
}
|
}
|
||||||
|
|
||||||
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
|
||||||
public function execute(array $data): Database\ResultSet
|
|
||||||
{
|
{
|
||||||
$this->statement->execute($data);
|
return $this->statement;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function execute(array $values): RSInterface
|
||||||
|
{
|
||||||
|
$this->getStatement()->execute($values);
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function checkResults(): PDOStatement
|
public function getAsArray(): array
|
||||||
{
|
{
|
||||||
if ($this->getStatement()->rowCount() === 0) {
|
return $this->getStatement()->fetchAll(PDO::FETCH_ASSOC);
|
||||||
throw new BlankResult(query: $this->getStatement()->queryString);
|
|
||||||
}
|
|
||||||
return $this->getStatement();
|
|
||||||
}
|
}
|
||||||
public function fetchFirst(): array
|
public function getAsObject(): array
|
||||||
{
|
{
|
||||||
return $this->checkResults()->fetch(PDO::FETCH_ASSOC);
|
return $this->getStatement()->fetchAll(PDO::FETCH_OBJ);
|
||||||
}
|
}
|
||||||
public function fetchAll(): array
|
public function getFirstAsArray(): array
|
||||||
{
|
{
|
||||||
return $this->checkResults()->fetchAll(PDO::FETCH_ASSOC);
|
return $this->getStatement()->fetch(PDO::FETCH_ASSOC);
|
||||||
}
|
}
|
||||||
public function fetchFirstAsObject(): object
|
public function getFirstAsObject(): object
|
||||||
{
|
{
|
||||||
return $this->checkResults()->fetch(PDO::FETCH_OBJ);
|
return $this->getStatement()->fetch(PDO::FETCH_OBJ);
|
||||||
}
|
|
||||||
public function fetchAllAsObjects(): array
|
|
||||||
{
|
|
||||||
return $this->checkResults()->fetchAll(PDO::FETCH_OBJ);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,12 +0,0 @@
|
|||||||
<?php
|
|
||||||
namespace ProVM\Database;
|
|
||||||
|
|
||||||
use ProVM\Implement\Database;
|
|
||||||
|
|
||||||
class SQLite extends Database
|
|
||||||
{
|
|
||||||
public function getDsn(): string
|
|
||||||
{
|
|
||||||
return "sqlite:{$this->getHost()}";
|
|
||||||
}
|
|
||||||
}
|
|
@ -2,39 +2,58 @@
|
|||||||
namespace ProVM\Database;
|
namespace ProVM\Database;
|
||||||
|
|
||||||
use PDO;
|
use PDO;
|
||||||
use ProVM\Concept;
|
use PDOException;
|
||||||
|
use ProVM\Concept\Database\ResultSet as ResultSetInterface;
|
||||||
|
use ProVM\Concept\Database\Transaction as TransactionInterface;
|
||||||
|
|
||||||
class Transaction implements Concept\Database\Transaction
|
class Transaction implements TransactionInterface
|
||||||
{
|
{
|
||||||
public function __construct(Concept\Database\Connection $connection)
|
public function __construct(PDO $pdo)
|
||||||
{
|
{
|
||||||
$this->setConnection($connection);
|
$this->setPDO($pdo);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Concept\Database\Connection $connection;
|
protected PDO $pdo;
|
||||||
|
public function setPDO(PDO $pdo): TransactionInterface
|
||||||
public function getConnection(): Concept\Database\Connection
|
|
||||||
{
|
{
|
||||||
return $this->connection;
|
$this->pdo = $pdo;
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
{
|
{
|
||||||
$this->getConnection()->connect()->beginTransaction();
|
return $this->pdo;
|
||||||
|
}
|
||||||
|
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->getConnection()->connect()->commit();
|
$this->getPDO()->commit();
|
||||||
}
|
}
|
||||||
public function rollBack(): void
|
public function rollBack(): void
|
||||||
{
|
{
|
||||||
$this->getConnection()->connect()->rollBack();
|
$this->getPDO()->rollBack();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,16 +0,0 @@
|
|||||||
<?php
|
|
||||||
namespace ProVM\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)
|
|
||||||
{
|
|
||||||
$code += Database::BASE_CODE;
|
|
||||||
parent::__construct($message, $code, $previous);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,20 +0,0 @@
|
|||||||
<?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);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,14 +0,0 @@
|
|||||||
<?php
|
|
||||||
namespace ProVM\Exception\Database;
|
|
||||||
|
|
||||||
use Throwable;
|
|
||||||
use ProVM\Exception;
|
|
||||||
|
|
||||||
class InvalidQuery extends Exception\Database
|
|
||||||
{
|
|
||||||
public function __construct(string $query, ?Throwable $previous = null)
|
|
||||||
{
|
|
||||||
$message = "Invalid query \"{$query}\"";
|
|
||||||
parent::__construct($message, 0, $previous);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,65 +0,0 @@
|
|||||||
<?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;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,65 +0,0 @@
|
|||||||
<?php
|
|
||||||
use PHPUnit\Framework\TestCase;
|
|
||||||
|
|
||||||
use ProVM\Database\Connection;
|
|
||||||
use ProVM\Concept;
|
|
||||||
|
|
||||||
class ConnectionTest extends TestCase
|
|
||||||
{
|
|
||||||
protected PDO $pdo;
|
|
||||||
protected function setUp(): void
|
|
||||||
{
|
|
||||||
$this->pdo = new PDO('sqlite::memory:');
|
|
||||||
$query = "CREATE TABLE IF NOT EXISTS test_table (id INTEGER PRIMARY KEY, test TEXT)";
|
|
||||||
$this->pdo->query($query);
|
|
||||||
}
|
|
||||||
protected function tearDown(): void
|
|
||||||
{
|
|
||||||
unset($this->pdo);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testConnection()
|
|
||||||
{
|
|
||||||
$host = "memory";
|
|
||||||
|
|
||||||
$database = $this->getMockBuilder(Concept\Database::class)->getMock();
|
|
||||||
$database->method('getHost')->willReturn($host);
|
|
||||||
$database->method('getDsn')->willReturn("sqlite::{$host}");
|
|
||||||
$database->method('needsUser')->willReturn(false);
|
|
||||||
|
|
||||||
$connection = new Connection($database);
|
|
||||||
$this->assertEquals($this->pdo, $connection->connect());
|
|
||||||
}
|
|
||||||
public function testQuery()
|
|
||||||
{
|
|
||||||
$host = "memory";
|
|
||||||
|
|
||||||
$database = $this->getMockBuilder(Concept\Database::class)->getMock();
|
|
||||||
$database->method('getHost')->willReturn($host);
|
|
||||||
$database->method('getDsn')->willReturn("sqlite::{$host}");
|
|
||||||
$database->method('needsUser')->willReturn(false);
|
|
||||||
|
|
||||||
$connection = new Connection($database);
|
|
||||||
$query = "CREATE TABLE IF NOT EXISTS test_table (id INTEGER PRIMARY KEY, test TEXT)";
|
|
||||||
$connection->query($query);
|
|
||||||
$query = "SELECT * FROM test_table";
|
|
||||||
$result = $connection->query($query);
|
|
||||||
$this->assertInstanceOf(Concept\Database\ResultSet::class, $result);
|
|
||||||
}
|
|
||||||
public function testPrepare()
|
|
||||||
{
|
|
||||||
$host = "memory";
|
|
||||||
|
|
||||||
$database = $this->getMockBuilder(Concept\Database::class)->getMock();
|
|
||||||
$database->method('getHost')->willReturn($host);
|
|
||||||
$database->method('getDsn')->willReturn("sqlite::{$host}");
|
|
||||||
$database->method('needsUser')->willReturn(false);
|
|
||||||
|
|
||||||
$connection = new Connection($database);
|
|
||||||
$query = "CREATE TABLE IF NOT EXISTS test_table (id INTEGER PRIMARY KEY, test TEXT)";
|
|
||||||
$connection->query($query);
|
|
||||||
$query = "SELECT * FROM test_table";
|
|
||||||
$result = $connection->prepare($query);
|
|
||||||
$this->assertInstanceOf(Concept\Database\ResultSet::class, $result);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,32 +0,0 @@
|
|||||||
<?php
|
|
||||||
use PHPUnit\Framework\TestCase;
|
|
||||||
use ProVM\Database\MySQL;
|
|
||||||
|
|
||||||
class MySQLTest extends TestCase
|
|
||||||
{
|
|
||||||
public function testDatabase()
|
|
||||||
{
|
|
||||||
$host = "testhost";
|
|
||||||
$port = 1234;
|
|
||||||
$name = "testdb";
|
|
||||||
$user = "testuser";
|
|
||||||
$pass = "testpass";
|
|
||||||
|
|
||||||
$dsn = "mysql:host={$host};port={$port};dbname={$name}";
|
|
||||||
|
|
||||||
$database = new MySQL();
|
|
||||||
$database->setHost($host);
|
|
||||||
$database->setPort($port);
|
|
||||||
$database->setName($name);
|
|
||||||
$database->setUser($user);
|
|
||||||
$database->setPassword($pass);
|
|
||||||
|
|
||||||
$this->assertEquals($host, $database->getHost());
|
|
||||||
$this->assertEquals($port, $database->getPort());
|
|
||||||
$this->assertEquals($name, $database->getName());
|
|
||||||
$this->assertEquals($user, $database->getUser());
|
|
||||||
$this->assertEquals($pass, $database->getPassword());
|
|
||||||
$this->assertTrue($database->needsUser());
|
|
||||||
$this->assertEquals($dsn, $database->getDsn());
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,32 +0,0 @@
|
|||||||
<?php
|
|
||||||
use PHPUnit\Framework\TestCase;
|
|
||||||
use ProVM\Database\PostgreSQL;
|
|
||||||
|
|
||||||
class PostgreSQLTest extends TestCase
|
|
||||||
{
|
|
||||||
public function testDatabase()
|
|
||||||
{
|
|
||||||
$host = "testhost";
|
|
||||||
$port = 1234;
|
|
||||||
$name = "testdb";
|
|
||||||
$user = "testuser";
|
|
||||||
$pass = "testpass";
|
|
||||||
|
|
||||||
$dsn = "pgsql:host={$host};port={$port};dbname={$name};user={$user};password={$pass}";
|
|
||||||
|
|
||||||
$database = new PostgreSQL();
|
|
||||||
$database->setHost($host);
|
|
||||||
$database->setPort($port);
|
|
||||||
$database->setName($name);
|
|
||||||
$database->setUser($user);
|
|
||||||
$database->setPassword($pass);
|
|
||||||
|
|
||||||
$this->assertEquals($host, $database->getHost());
|
|
||||||
$this->assertEquals($port, $database->getPort());
|
|
||||||
$this->assertEquals($name, $database->getName());
|
|
||||||
$this->assertEquals($user, $database->getUser());
|
|
||||||
$this->assertEquals($pass, $database->getPassword());
|
|
||||||
$this->assertFalse($database->needsUser());
|
|
||||||
$this->assertEquals($dsn, $database->getDsn());
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,26 +0,0 @@
|
|||||||
<?php
|
|
||||||
use PHPUnit\Framework\TestCase;
|
|
||||||
|
|
||||||
use ProVM\Database\ResultSet;
|
|
||||||
|
|
||||||
class ResultSetTest extends TestCase
|
|
||||||
{
|
|
||||||
public function testResultSet()
|
|
||||||
{
|
|
||||||
$result1 = ['col1', 'col2', 'col3'];
|
|
||||||
$result2 = [['col1', 'col2'], ['col3', 'col4']];
|
|
||||||
|
|
||||||
$statement = $this->getMockBuilder(PDOStatement::class)->getMock();
|
|
||||||
$statement->method('execute')->willReturn(true);
|
|
||||||
$statement->method('fetch')->willReturn($result1);
|
|
||||||
$statement->method('fetchAll')->willReturn($result2);
|
|
||||||
$statement->method('rowCount')->willReturn(2);
|
|
||||||
|
|
||||||
$resultSet = new ResultSet($statement);
|
|
||||||
|
|
||||||
$resultSet->execute(['foo' => 'bar']);
|
|
||||||
$this->assertTrue(true);
|
|
||||||
$this->assertEquals($result1, $resultSet->fetchFirst());
|
|
||||||
$this->assertEquals($result2, $resultSet->fetchAll());
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,20 +0,0 @@
|
|||||||
<?php
|
|
||||||
use PHPUnit\Framework\TestCase;
|
|
||||||
use ProVM\Database\SQLite;
|
|
||||||
|
|
||||||
class SQLiteTest extends TestCase
|
|
||||||
{
|
|
||||||
public function testDatabase()
|
|
||||||
{
|
|
||||||
$host = ":memory:";
|
|
||||||
|
|
||||||
$dsn = "sqlite:{$host}";
|
|
||||||
|
|
||||||
$database = new SQLite();
|
|
||||||
$database->setHost($host);
|
|
||||||
|
|
||||||
$this->assertEquals($host, $database->getHost());
|
|
||||||
$this->assertFalse($database->needsUser());
|
|
||||||
$this->assertEquals($dsn, $database->getDsn());
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,19 +0,0 @@
|
|||||||
<?php
|
|
||||||
use PHPUnit\Framework\TestCase;
|
|
||||||
use ProVM\Database\Transaction;
|
|
||||||
|
|
||||||
class TransactionTest extends TestCase
|
|
||||||
{
|
|
||||||
public function testTransaction()
|
|
||||||
{
|
|
||||||
$connection = $this->createMock(ProVM\Concept\Database\Connection::class);
|
|
||||||
$transaction = new Transaction($connection);
|
|
||||||
$transaction->begin();
|
|
||||||
$this->assertTrue(true);
|
|
||||||
$transaction->commit();
|
|
||||||
$this->assertTrue(true);
|
|
||||||
$transaction->begin();
|
|
||||||
$transaction->rollback();
|
|
||||||
$this->assertTrue(true);
|
|
||||||
}
|
|
||||||
}
|
|
Reference in New Issue
Block a user