Compare commits

...

1 Commits

Author SHA1 Message Date
sheychen 47c0be00fb WIP 2018-07-11 14:39:17 +02:00
24 changed files with 1804 additions and 1380 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
vendor

42
LICENSE
View File

@ -1,21 +1,21 @@
MIT License MIT License
Copyright (c) 2017 sheychen Copyright (c) 2017 sheychen
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions: furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software. copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. SOFTWARE.

View File

@ -1,18 +1,17 @@
{ {
"name": "krutush/database", "name": "krutush/database",
"license": "MIT", "license": "MIT",
"authors": [ "authors": [
{ {
"name": "sheychen", "name": "sheychen",
"email": "contact@clementbois.fr" "email": "contact@clementbois.fr"
} }
], ],
"require": { "require": {},
"krutush/krutush": "dev-develop" "autoload": {
}, "psr-4": {
"autoload": { "Krutush\\Database\\": "src/",
"psr-4": { "Krutush\\Database\\Exemple\\": "exemple/"
"Krutush\\Database\\": "src/" }
} }
} }
}

View File

@ -0,0 +1,25 @@
$migration->create(
Krutush\Database\Exemple\Model\UserModel:class,
Krutush\Database\ModelID:class,
[
'id' => [
'column' => 'user_id',
'type' => 'bigint'
],
'first_name' => [
'not_null' => true
],
'last_name' => [
'not_null' => true
],
'supervisor' => [
'foreign' => []
],
'supervised' => [
'virtual' => true,
'foreign' => [
'key' => 'supervisor',
'multiple' => true
]
]
]);

View File

@ -0,0 +1,10 @@
$migration->alter(
Krutush\Database\Exemple\Model\UserModel:class,
[
'first_name' => [
'unique' => 'full_name'
],
'last_name' => [
'unique' => 'full_name'
]
]);

View File

@ -0,0 +1,11 @@
$migration->create(
Krutush\Database\Exemple\Model\OfficeModel:class,
Krutush\Database\ModelID:class,
['name']
)->alter(
Krutush\Database\Exemple\Model\UserModel:class,
[
'office' => [
'foreign' => Krutush\Database\Exemple\Model\OfficeModel:class,
]
]);

View File

@ -0,0 +1,10 @@
<?php
namespace Krutush\Database\Exemple\Model;
use Krutush\Database\ModelID;
class OfficeModel extends ModelID{
public const FIELDS = [
'name'
];
}

View File

@ -0,0 +1,35 @@
<?php
namespace Krutush\Database\Exemple\Model;
use Krutush\Database\ModelID;
class UserModel extends ModelID{
public const FIELDS = [
'id' => [
'column' => 'user_id',
'type' => 'bigint'
],
'first_name' => [
'not_null' => true,
'unique' => 'full_name'
],
'last_name' => [
'not_null' => true,
'unique' => 'full_name'
],
'supervisor' => [
'foreign' => []
],
'supervised' => [
'virtual' => true,
'index' => true,
'foreign' => [
'key' => 'supervisor',
'multiple' => true
]
],
'office' => [
'foreign' => OfficeModel::class,
]
];
}

17
exemple/index.php Normal file
View File

@ -0,0 +1,17 @@
<?php
require_once('../vendor/autoload.php');
(new Krutush\Database\Connection('Databases.php'))->connect();
$UserModel = Krutush\Database\Exemple\Model\UserModel::class;
var_dump($UserModel::getTable());
//var_dump($UserModel::getFields());
var_dump((new $UserModel([
'id' => 42,
'first_name' => 'Pierre De La VIEDDDDDDD',
'last_name' => 'Caillou'
]))->insert());
//TODO: format src before commit

View File

@ -1,74 +1,82 @@
<?php <?php
namespace Krutush\Database; namespace Krutush\Database;
class Connection{ /**
protected static $databases = array(); * Load a config file to provide a list of pdo instances (Database)
*/
protected $settings; class Connection{
/** @var array */
public function __construct(string $path = null){ protected static $databases = array();
if(isset($path))
$this->settings = include($path); /** @var array */
} protected $settings;
public function connect(string $dbname = null){ /** Load settings */
if(static::exists($dbname)) public function __construct(string $path = null){
throw new DatabaseException("Allready connect"); if(isset($path))
$this->settings = include($path);
$dbname = static::parseName($dbname); }
if(!isset($this->settings[$dbname]))
throw new DatabaseException('Can\'t find '.$dbname.' in settings'); /** Setup Database */
public function connect(string $dbname = null): Database{
static::$databases[$dbname] = new Database($this->settings[$dbname]); if(static::exists($dbname))
return static::$databases[$dbname]; throw new \InvalidArgumentException("Allready connect");
}
$dbname = static::parseName($dbname);
public function tryConnect(string $dbname = null, bool $quiet = false) { if(!isset($this->settings[$dbname]))
try { throw new \InvalidArgumentException('Can\'t find '.$dbname.' in settings');
return $this->connect($dbname);
} catch (DatabaseException $e) { static::$databases[$dbname] = new Database($this->settings[$dbname]);
return $quiet ? false : $e; return static::$databases[$dbname];
} }
}
/** If you dont remember how to make a try-catch */
public static function get(string $dbname = null){ public function tryConnect(string $dbname = null, bool $quiet = false) {
$dbname = static::parseName($dbname); try {
if(!static::exists($dbname)) return $this->connect($dbname);
throw new DatabaseException('Can\'t find "'.$dbname.'"'); } catch (\Exception $e) {
return $quiet ? false : $e;
return static::$databases[$dbname]; }
} }
public function getCreate(string $dbname = null){ public static function get(string $dbname = null){
if(!static::exists($dbname)){ $dbname = static::parseName($dbname);
$this->create($dbname); if(!static::exists($dbname))
} throw new \InvalidArgumentException('Can\'t find "'.$dbname.'"');
return static::$databases[static::parseName($dbname)];
} return static::$databases[$dbname];
}
public static function tryGet(string $dbname = null, bool $quiet = false) {
try { public function getCreate(string $dbname = null){
return static::get($dbname); if(!static::exists($dbname)){
} catch (DatabaseException $e) { $this->create($dbname);
return $quiet ? false : $e; }
} return static::$databases[static::parseName($dbname)];
} }
public function tryGetCreate(string $dbname = null, bool $quiet = false) { public static function tryGet(string $dbname = null, bool $quiet = false) {
try { try {
return $this->getCreate($dbname); return static::get($dbname);
} catch (DatabaseException $e) { } catch (\Exception $e) {
return $quiet ? false : $e; return $quiet ? false : $e;
} }
} }
public static function exists(string $dbname = null){ public function tryGetCreate(string $dbname = null, bool $quiet = false) {
$dbname = static::parseName($dbname); try {
return isset(static::$databases[$dbname]); return $this->getCreate($dbname);
} } catch (\Exception $e) {
return $quiet ? false : $e;
private static function parseName(string $dbname = null){ }
return $dbname ?: 'default'; //Edit me }
}
public static function exists(string $dbname = null){
$dbname = static::parseName($dbname);
return isset(static::$databases[$dbname]);
}
private static function parseName(string $dbname = null){
return $dbname ?: 'default'; //Edit me
}
} }

View File

@ -2,11 +2,23 @@
namespace Krutush\Database; namespace Krutush\Database;
/**
* Extention around PDO
*/
class Database{ class Database{
/** @var \PDO */
private $pdo; private $pdo;
private $debug = false;
/**
* Requests history if debug == true
*
* @var array
*/
private $requests = []; private $requests = [];
/** @var bool */
private $debug = false;
public function __construct(array $settings){ public function __construct(array $settings){
$dns = $settings['driver'] . $dns = $settings['driver'] .
':host=' . $settings['host'] . ':host=' . $settings['host'] .
@ -23,22 +35,29 @@ class Database{
} }
public function prepare(string $request){ public function prepare(string $request){
if($this->debug)
$this->requests[] = $request;
return $this->pdo->prepare($request); return $this->pdo->prepare($request);
} }
public function execute(string $request, array $values = null, $row = false){ public function execute(string $request, array $values = null, $row = false){
if($this->debug)
$time_start = microtime(true);
$req = $this->prepare($request); $req = $this->prepare($request);
$req->execute($values); $req->execute($values);
if($row == false) if(!$row)
return $req->fetchAll(); return $req->fetchAll();
if($this->debug)
$this->requests[] = [
'request' => $request,
'values' => $values,
'fetch' => !$row,
'time' => round((microtime(true) - $time_start) * 1000)
];
return $req; return $req;
} }
public function select(array $fields = null){ public function select(array $fields = null): Request\Select{
$select = new Request\Select($this); $select = new Request\Select($this);
if(isset($fields)) if(isset($fields))
return $select->fields($fields); return $select->fields($fields);
@ -46,7 +65,7 @@ class Database{
return $select; return $select;
} }
public function insert(array $fields = null){ public function insert(array $fields = null): Request\Insert{
$insert = new Request\Insert($this); $insert = new Request\Insert($this);
if(isset($fields)) if(isset($fields))
return $insert->fields($fields); return $insert->fields($fields);
@ -54,7 +73,7 @@ class Database{
return $insert; return $insert;
} }
public function update(array $fields = null){ public function update(array $fields = null): Request\Update{
$update = new Request\Update($this); $update = new Request\Update($this);
if(isset($fields)) if(isset($fields))
return $update->fields($fields); return $update->fields($fields);
@ -62,7 +81,7 @@ class Database{
return $update; return $update;
} }
public function create(string $table = null){ public function create(string $table = null): Request\Create{
$create = new Request\Create($this); $create = new Request\Create($this);
if(isset($table)) if(isset($table))
return $create->table($table); return $create->table($table);
@ -70,7 +89,7 @@ class Database{
return $create; return $create;
} }
public function drop(string $table = null){ public function drop(string $table = null): Request\Drop{
$drop = new Request\Drop($this); $drop = new Request\Drop($this);
if(isset($table)) if(isset($table))
return $drop->table($table); return $drop->table($table);
@ -78,7 +97,7 @@ class Database{
return $drop; return $drop;
} }
public function delete(){ public function delete(): Request\Delete{
return new Request\Delete($this); return new Request\Delete($this);
} }
@ -89,5 +108,4 @@ class Database{
public function getRequests(): array{ public function getRequests(): array{
return $this->requests; return $this->requests;
} }
//TODO update, delete
} }

View File

@ -1,7 +0,0 @@
<?php
namespace Krutush\Database;
use \Exception;
class DatabaseException extends Exception {}

12
src/Migration.php Normal file
View File

@ -0,0 +1,12 @@
<?php
require_once('../../autoload.php');
echo "TODO";
/*
- migrate <file>
- roolback <file>
- new <name>
- create <model>
- status
*/

File diff suppressed because it is too large Load Diff

115
src/ModelID.php Normal file
View File

@ -0,0 +1,115 @@
<?php
namespace Krutush\Database;
use Krutush\Database\Request\Request;
class ModelID extends Model {
/** @var string */
public const ID = null;
/** @var bool */
public const ID_INCLUDE_TABLE = false;
/**
* Get table id name for static::ID or default one
*
* @see static::ID_INCLUDE_TABLE
* @return string
*/
public static function getID(): string{
return static::ID ?? (static::ID_INCLUDE_TABLE ? static::getTable().static::WORD_SEPARATOR : '').'id';
}
public static function getFields(): array{
if(empty(static::FIELDS))
trigger_error('Any data fields');
$fields = static::FIELDS;
$id = static::getID();
$fields[$id] = static::getFieldRawOptions($id);
if(!isset(static::$complete_fields))
static::$complete_fields = static::completeFields($fields);
return static::$complete_fields;
}
/**
* static::FIELDS[$field] with some checks
*
* @param string $field
* @return array options
*/
protected static function getFieldRawOptions(string $field): array{
if($field == static::getID())
return array_merge(
[
'type' => 'int',
'primary' => true,
'not_null' => true,
'custom' => 'AUTO_INCREMENT' //TODO: be smart
],
static::FIELDS[$field] ?? []
);
return parent::getFieldRawOptions($field);
}
/**
* add values to static::getInsert and run it
*
* @param boolean $setID must update id value
*/
public function insert(bool $setID = true){
$res = parent::insert();
if($setID)
$this->{static::getID()} = Connection::get(static::getDatabase())->getLastInsertID();
return $res;
}
/**
* Use static:ID to get row
*
* @param mixed $id int is a good idea
* @param array $loads run static::load
* @return self|null
*/
public static function find($id, array $loads = []): ?self{
return static::first([$id], Request::toParam(static::getID()), $loads);
}
/**
* Same as find but throw exception on null
*
* @param mixed $id int is a good idea
* @param array $loads run static::load
* @return self
*/
public static function findOrFail($id, array $loads = []): self{
return static::firstOrFail([$id], Request::toParam(static::getID()), $loads);
}
/**
* Use static:ID to get rows
*
* @param array $ids array(int) is a good idea
* @param array $loads run static::loads
* @return array
*/
public static function finds(array $ids, array $loads = []): array{
return static::all($ids, Request::inParams(static::getID(), count($ids)), $loads);
}
/**
* Same as find but throw exception on empty
*
* @param array $ids array(int) is a good idea
* @param array $loads run static::loads
* @return array
*/
public static function findsOrFail(array $ids, array $loads = []): array{
return static::allOrFail($ids, Request::inParams(static::getID(), count($ids)), $loads);
}
}

View File

@ -1,97 +1,92 @@
<?php <?php
namespace Krutush\Database\Request; namespace Krutush\Database\Request;
use Krutush\Database\Database; use Krutush\Database\Database;
use Krutush\Database\DatabaseException; use Krutush\Database\DatabaseException;
class Create extends Request{ class Create extends Request{
protected $table; protected $table;
protected $columns = []; protected $columns = [];
protected $primary = []; protected $primary = [];
protected $unique = []; protected $unique = [];
protected $index = []; protected $index = [];
protected $foreign = []; protected $foreign = [];
public function table(string $table): Create{ public function table(string $table): Create{
$this->table = $table; $this->table = $table;
return $this; return $this;
} }
public function column(string $name, string $type, int $lenght = null, bool $not_null = false, string $more = null): Create{ //Really ? public function column(string $name, string $type, int $lenght = null, bool $not_null = false, string $more = null): Create{
$this->columns[] = '`'.$name.'` '.$type.($lenght ? '('.$lenght.')' : '').($not_null ? ' NOT NULL' : '').(isset($more) ? ' '.$more : ''); $this->columns[] = compact('name', 'type', 'lenght', 'not_null', 'more');
return $this; return $this;
} }
public function primary(string $name): Create{ public function primary(string $name): Create{
$this->primary[] = '`'.$name.'`'; $this->primary[] = $name;
return $this; return $this;
} }
public function unique(string $name): Create{ public function unique(string $name, array $columns = null): Create{
$this->unique[$name] = ['`'.$name.'`']; $this->unique[$name] = $columns ?? [$name];
return $this; return $this;
} }
public function uniques(string $name, array $columns): Create{ public function index(string $name, array $columns = null): Create{
$this->unique[$name] = [$columns]; $this->index[$name] = $columns ?? [$name];
return $this; return $this;
} }
public function index(string $name): Create{ public function foreign(string $name, string $table, string $column, string $on_delete = null, string $on_update = null): Create{ //TODO: complex foreign
$this->index[$name] = ['`'.$name.'`']; $this->foreign[$name] = compact('name', 'table', 'column', 'on_delete', 'on_update');
return $this; return $this;
} }
public function indexs(string $name, array $columns): Create{ public function sql(){
$this->index[$name] = [$columns]; if(!isset($this->table))
return $this; throw new \UnexpectedValueException('Any table set');
}
if(empty($this->columns))
public function foreign(string $name, string $table, string $column, string $on_delete = null, string $on_update = null): Create{ //TODO: complex foreign throw new \UnexpectedValueException('Any columns set');
$this->foreign[$name] = compact('name', 'table', 'column', 'on_delete', 'on_update');
return $this; $columns = [];
} foreach($this->columns as $column){
$columns[] = $column['name'].' '.$column['type'].($column['lenght'] ? '('.$column['lenght'].')' : '').($column['not_null'] ? ' NOT NULL' : '').(isset($column['more']) ? ' '.$column['more'] : '');
public function sql(){ }
if(!isset($this->table))
throw new DatabaseException('Any table set'); $uniques = [];
foreach ($this->unique as $name => $columns) {
if(empty($this->columns)) $uniques[] = 'CONSTRAINT `UQ_'.ucfirst(strtolower($this->table)).'_'.ucfirst(strtolower($name)).'` UNIQUE ('.implode(', ', $columns).')';
throw new DatabaseException('Any columns set'); }
$uniques = []; $indexs = [];
foreach ($this->unique as $name => $columns) { foreach ($this->index as $name => $columns) {
$uniques[] = 'CONSTRAINT `UQ_'.ucfirst(strtolower($this->table)).'_'.ucfirst(strtolower($name)).'` UNIQUE ('.implode(', ', $columns).')'; $indexs[] = 'INDEX `ID_'.ucfirst(strtolower($this->table)).'_'.ucfirst(strtolower($name)).'` ('.implode(', ', $columns).')';
} }
$indexs = []; $foreigns = [];
foreach ($this->index as $name => $columns) { foreach ($this->foreign as $name => $options) {
$indexs[] = 'INDEX `ID_'.ucfirst(strtolower($this->table)).'_'.ucfirst(strtolower($name)).'` ('.implode(', ', $columns).')'; $foreigns[] = 'CONSTRAINT `FK_'.ucfirst(strtolower($this->table)).'_'.ucfirst(strtolower($name)).'` FOREIGN KEY (`'.$options['name'].'`) REFERENCES `'.$options['table'].'` (`'.$options['column'].'`)'.
} (isset($options['on_delete']) ? 'ON DELETE '.$options['on_delete'] : '').
(isset($options['on_update']) ? 'ON UPDATE '.$options['on_update'] : '');
$foreigns = []; }
foreach ($this->foreign as $name => $options) {
$foreigns[] = 'CONSTRAINT `FK_'.ucfirst(strtolower($this->table)).'_'.ucfirst(strtolower($name)).'` FOREIGN KEY (`'.$options['name'].'`) REFERENCES `'.$options['table'].'` (`'.$options['column'].'`)'. return 'CREATE TABLE '.$this->table.'('."\n".
(isset($options['on_delete']) ? 'ON DELETE '.$options['on_delete'] : ''). implode(",\n",
(isset($options['on_update']) ? 'ON UPDATE '.$options['on_update'] : ''); array_merge(
} $columns,
(empty($this->primary) ? [] : [
return 'CREATE TABLE `'.$this->table.'`('."\n". 'CONSTRAINT `PK_'.ucfirst(strtolower(strtok($this->table, ' '))).'` PRIMARY KEY ('.implode(', ', $this->primary).')'
$sql = implode(",\n", ]),
array_merge( $indexs,
$this->columns, $uniques,
(empty($this->primary) ? [] : [ $foreigns
'CONSTRAINT `PK_'.ucfirst(strtolower(strtok($this->table, ' '))).'` PRIMARY KEY ('.implode(', ', $this->primary).')' )
]), )."\n)";
$indexs, }
$uniques,
$foreigns public function run(array $values = null){
) return parent::execute($this->sql(), $values);
)."\n)"; }
}
public function run(array $values = null){
return parent::execute($this->sql(), $values);
}
} }

View File

@ -1,21 +1,21 @@
<?php <?php
namespace Krutush\Database\Request; namespace Krutush\Database\Request;
class Data extends Request{ /** I'm the WHERE */
protected $values; class Data extends Request{
/** @var array */
public function values(array $values, bool $add = false){ protected $values;
if($add){
$this->values = array_merge($this->values, $values); public function values(array $values, bool $add = false){
}else{ if($add)
$this->values = $values; $this->values = array_merge($this->values, $values);
} else
return $this; $this->values = $values;
} return $this;
}
public function execute(string $sql, array $values = null){
$values = $values ? ($this->values ? array_merge($this->values, $values) : $values) : $this->values; public function execute(string $sql, array $values = null){
return parent::execute($sql, $values); return parent::execute($sql, $values ? ($this->values ? array_merge($this->values, $values) : $values) : $this->values);
} }
} }

View File

@ -1,36 +1,42 @@
<?php <?php
namespace Krutush\Database\Request; namespace Krutush\Database\Request;
//TODO: Split in traits //TODO: Split in traits
//TODO: Add INTO //TODO: Add INTO
//TODO: Add UNION //TODO: Add UNION
use Krutush\Database\DatabaseException; use Krutush\Database\DatabaseException;
class Delete extends Data{ class Delete extends Data{
protected $table; protected $table;
protected $where; protected $where;
public function from(string $table, bool $add = false): Delete{ public function from(string $table, bool $add = false): Delete{
$this->table = ($add && $this->table ? $this->table.', ' : '').$table; $this->table = ($add && $this->table ? $this->table.', ' : '').$table;
return $this; return $this;
} }
public function where(string $where, bool $add = false): Delete{ /**
$this->where = $add && $this->where ? '('.$this->where.') AND ('.$where.')' : $where; * @param string|array $where
return $this; * @param boolean $add
} * @return Delete
*/
public function sql(){ public function where($where, bool $add = false): Delete{
if(!isset($this->table)) $where = is_array($where) ? $where : [$where];
throw new DatabaseException('Any table set'); $this->where = $add && $this->where ? array_merge($this->where, $where) : $where;
return $this;
$sql = 'DELETE FROM '.$this->table. }
($this->where ? ("\n".'WHERE '.$this->where) : '');
return $sql; public function sql(){
} if(!isset($this->table))
throw new \UnexpectedValueException('Any table set');
public function run(array $values = null){
return parent::execute($this->sql(), $values); $sql = 'DELETE FROM '.$this->table.
} ($this->where ? ("\n".'WHERE '.static::combineParams($this->where)) : '');
return $sql;
}
public function run(array $values = null){
return parent::execute($this->sql(), $values);
}
} }

View File

@ -1,26 +1,26 @@
<?php <?php
namespace Krutush\Database\Request; namespace Krutush\Database\Request;
use Krutush\Database\Database; use Krutush\Database\Database;
use Krutush\Database\DatabaseException; use Krutush\Database\DatabaseException;
class Drop extends Request{ class Drop extends Request{
protected $table; protected $table;
public function table(string $table): Drop{ public function table(string $table): Drop{
$this->table = $table; $this->table = $table;
return $this; return $this;
} }
public function sql(){ public function sql(){
if(!isset($this->table)) if(!isset($this->table))
throw new DatabaseException('Any table set'); throw new \UnexpectedValueException('Any table set');
return 'DROP TABLE `'.$this->table.'`'; return 'DROP TABLE `'.$this->table.'`';
} }
public function run(array $values = null){ public function run(array $values = null){
return parent::execute($this->sql(), $values); return parent::execute($this->sql(), $values);
} }
} }

View File

@ -1,33 +1,33 @@
<?php <?php
namespace Krutush\Database\Request; namespace Krutush\Database\Request;
use Krutush\Database\DatabaseException; use Krutush\Database\DatabaseException;
class Insert extends Data{ class Insert extends Data{
protected $fields; protected $fields;
protected $table; protected $table;
public function fields(array $fields = null, bool $add = false): Insert{ public function fields(array $fields = null, bool $add = false): Insert{
$this->fields = $add ? array_merge($this->fields, $fields) : $fields; $this->fields = $add ? array_merge($this->fields, $fields) : $fields;
return $this; return $this;
} }
public function into(string $table): Insert{ public function into(string $table): Insert{
$this->table = $table; $this->table = $table;
return $this; return $this;
} }
public function sql(){ public function sql(){
if(!isset($this->table)) if(!isset($this->table))
throw new DatabaseException('Any table set'); throw new \UnexpectedValueException('Any table set');
return 'INSERT INTO `'.$this->table."`\n". return 'INSERT INTO '.$this->table."\n".
'('.implode(', ', $this->fields).")\n". '('.implode(', ', $this->fields).")\n".
'VALUES ('. str_repeat('?, ', count($this->fields)-1).(count($this->fields) > 0 ? '?' : '').')'; 'VALUES ('.static::paramList(count($this->fields)).')';
} }
public function run(array $values = null){ public function run(array $values = null){
return parent::execute($this->sql(), $values); return parent::execute($this->sql(), $values);
} }
} }

View File

@ -1,17 +1,42 @@
<?php <?php
namespace Krutush\Database\Request; namespace Krutush\Database\Request;
use Krutush\Database\Database; use Krutush\Database\Database;
class Request{ //TODO: escape and slugify /** Base of any SQL request */
protected $db; class Request{
/** @var Database */
public function __construct(Database $db){ protected $db;
$this->db = $db;
} /** Create it */
public function __construct(Database $db){
protected function execute(string $sql, array $values = null){ $this->db = $db;
return $this->db->execute($sql, $values, true); }
}
/** Run it */
protected function execute(string $sql, array $values = null){
return $this->db->execute($sql, $values, true);
}
/*=== TOOLS ===*/
public static function toParam(string $name, string $operator = '='): string{
return $name.' '.$operator.' ?';
}
public static function toParams(array $names): string{
return implode(', ', array_map(function($name){ return static::toParam($name); }, $names));
}
public static function paramList(int $count): string{
return implode(',', array_fill(0, $count, '?'));
}
public static function inParams(string $name, $params): string{
return $name.' IN ('.static::paramList(is_int($params) ? $params : count($params)).')';
}
public static function combineParams(array $params, string $operator = ' AND '): string{
return implode($operator, $params);
}
} }

View File

@ -1,95 +1,102 @@
<?php <?php
namespace Krutush\Database\Request; namespace Krutush\Database\Request;
//TODO: Split in traits //TODO: Split in traits
//TODO: Add INTO //TODO: Add INTO
//TODO: Add UNION //TODO: Add UNION
use Krutush\Database\DatabaseException; use Krutush\Database\DatabaseException;
class Select extends Data{ class Select extends Data{
protected $fields; /** @var array */
protected $table; protected $fields;
protected $where;
protected $group; /** @var string */
protected $order; protected $table;
protected $limit;
protected $offset; /** @var array */
protected $joins; protected $where;
public function fields(array $fields = null, bool $add = false): Select{ /** @var string */
$this->fields = $add ? array_merge($this->fields, $fields) : $fields; protected $group;
return $this; protected $order;
} protected $limit;
protected $offset;
public function from(string $table, bool $add = false): Select{ protected $joins;
$this->table = ($add && $this->table ? $this->table.', ' : '').$table;
return $this; public function fields(array $fields = null, bool $add = false): Select{
} $this->fields = $add ? array_merge($this->fields, $fields) : $fields;
return $this;
public function join(string $joins, string $type = 'INNER', bool $add = false): Select{ }
if(!in_array($type, array('INNER', 'LEFT', 'RIGHT')))
throw new DatabaseException('Unknown JOIN type'); public function from(string $table, bool $add = false): Select{
$this->joins = ($add && $this->joins ? $this->joins."\n" : '').$type.' JOIN '.$joins; $this->table = ($add && $this->table ? $this->table.', ' : '').$table;
return $this; return $this;
} }
public function where(string $where, bool $add = false): Select{ public function join(string $joins, string $type = 'INNER', bool $add = false): Select{
$this->where = $add && $this->where ? '('.$this->where.') AND ('.$where.')' : $where; if(!in_array($type, array('INNER', 'LEFT', 'RIGHT')))
return $this; throw new \InvalidArgumentException('Unknown JOIN type');
} $this->joins = ($add && $this->joins ? $this->joins."\n" : '').$type.' JOIN '.$joins;
return $this;
public function groupby(string $group): Select{ }
$this->group = $group;
return $this; /**
} * @param string|array $where
* @param boolean $add
public function orderby(string $order): Select{ * @return Select
$this->order = $order; */
return $this; public function where($where, bool $add = false): Select{
} $where = is_array($where) ? $where : [$where];
$this->where = $add && $this->where ? array_merge($this->where, $where) : $where;
public function limit(string $limit): Select{ return $this;
$this->limit = $limit; }
return $this;
} public function groupby(string $group): Select{
$this->group = $group;
public function offset(string $offset): Select{ return $this;
$this->offset = $offset; }
return $this;
} public function orderby(string $order): Select{
$this->order = $order;
public function sql(){ return $this;
if(!isset($this->table)) }
throw new DatabaseException('Any table set');
public function limit(string $limit): Select{
$fields = '*'; $this->limit = $limit;
if(isset($this->fields)){ return $this;
$numItems = count($this->fields); }
$i = 0;
$fields = ''; public function offset(string $offset): Select{
foreach($this->fields as $key => $value){ $this->offset = $offset;
$fields .= $value; return $this;
if(is_string($key)) }
$fields .= ' '.$key;
public function sql(){
if(++$i !== $numItems) //Not last if(!isset($this->table))
$fields .= ', '; throw new \UnexpectedValueException('Any table set');
}
} $fields = '*';
if(isset($this->fields)){
$sql = 'SELECT '.$fields. $lines = [];
"\n".'FROM '.$this->table. foreach($this->fields as $key => $value){
($this->joins ? ("\n".$this->joins) : ''). $lines[] = $value.(is_string($key) ? ' '.$key : '');
($this->where ? ("\n".'WHERE '.$this->where) : ''). }
($this->group ? ("\n".'GROUP BY '.$this->group) : ''). $fields = implode(', ', $lines);
($this->order ? ("\n".'ORDER BY '.$this->order) : ''). }
($this->limit ? ("\n".'LIMIT '.$this->limit) : '').
($this->offset ? (($this->limit ? '' : "\n".'LIMIT 18446744073709551615').' OFFSET '.$this->offset) : ''); $sql = 'SELECT '.$fields.
return $sql; "\n".'FROM '.$this->table.
} ($this->joins ? ("\n".$this->joins) : '').
($this->where ? ("\n".'WHERE '.static::combineParams($this->where)) : '').
public function run(array $values = null){ ($this->group ? ("\n".'GROUP BY '.$this->group) : '').
return parent::execute($this->sql(), $values); ($this->order ? ("\n".'ORDER BY '.$this->order) : '').
} ($this->limit ? ("\n".'LIMIT '.$this->limit) : '').
($this->offset ? (($this->limit ? '' : "\n".'LIMIT 18446744073709551615').' OFFSET '.$this->offset) : '');
return $sql;
}
public function run(array $values = null){
return parent::execute($this->sql(), $values);
}
} }

View File

@ -1,39 +1,51 @@
<?php <?php
namespace Krutush\Database\Request; namespace Krutush\Database\Request;
use Krutush\Database\DatabaseException; use Krutush\Database\DatabaseException;
class Update extends Data{ /** UPDATE */
protected $fields; class Update extends Data{
protected $table; /** @var array */
protected $where; protected $fields;
public function fields(array $fields = null, bool $add = false): Update{ /** @var string */
$this->fields = $add ? array_merge($this->fields, $fields) : $fields; protected $table;
return $this;
} /** @var array */
protected $where;
public function table(string $table): Update{
$this->table = $table; public function fields(array $fields = null, bool $add = false): Update{
return $this; $this->fields = $add ? array_merge($this->fields, $fields) : $fields;
} return $this;
}
public function where(string $where, bool $add = false): Update{
$this->where = $add && $this->where ? '('.$this->where.') AND ('.$where.')' : $where; public function table(string $table): Update{
return $this; $this->table = $table;
} return $this;
}
public function sql(){
if(!isset($this->table)) /**
throw new DatabaseException('Any table set'); * @param string|array $where
* @param boolean $add
return 'UPDATE `'.$this->table."`\n". * @return Update
'SET '.implode(', ', array_map(function($field){ return $field.' = ?'; }, $this->fields))."\n". */
(isset($this->where) ? ('WHERE '.$this->where) : ''); public function where($where, bool $add = false): Update{
} $where = is_array($where) ? $where : [$where];
$this->where = $add && $this->where ? array_merge($this->where, $where) : $where;
public function run(array $values = null){ return $this;
return parent::execute($this->sql(), $values); }
}
public function sql(){
if(!isset($this->table))
throw new \UnexpectedValueException('Any table set');
return 'UPDATE '.$this->table."\n".
'SET '.static::toParams($this->fields)."\n".
($this->where ? 'WHERE '.static::combineParams($this->where) : '');
}
public function run(array $values = null){
return parent::execute($this->sql(), $values);
}
} }

21
src/TypeHelper.php Normal file
View File

@ -0,0 +1,21 @@
<?php
namespace Krutush\Database;
class TypeHelper{
private static function dateTimeConverter(string $format, $value): string{
return (is_a($value, \DateTime::class) ? $value : new \DateTime(strval($value)))->format($format);
}
public static function dateConvert($value): string{
return static::dateTimeConverter('Y-m-d', $value);
}
public static function timeConvert($value): string{
return static::dateTimeConverter('H:i:s', $value);
}
public static function datetimeConvert($value): string{
return static::dateTimeConverter('Y-m-d H:i:s', $value);
}
}