- Still working on Update and Insert statements
This commit is contained in:
parent
828daffec8
commit
3dc82b1f0d
|
@ -9,6 +9,7 @@ class Id extends \Ulmus\Annotation\Property\Field {
|
||||||
$this->nullable = false;
|
$this->nullable = false;
|
||||||
$this->attributes['unsigned'] = true;
|
$this->attributes['unsigned'] = true;
|
||||||
$this->attributes['primary_key'] = true;
|
$this->attributes['primary_key'] = true;
|
||||||
|
$this->attributes['auto_increment'] = true;
|
||||||
|
|
||||||
parent::__construct('int');
|
parent::__construct('int');
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,56 +2,57 @@
|
||||||
|
|
||||||
namespace Ulmus\Common;
|
namespace Ulmus\Common;
|
||||||
|
|
||||||
use PDO, PDOStatement;
|
use PDO,
|
||||||
|
PDOStatement;
|
||||||
|
|
||||||
class PdoObject extends PDO {
|
class PdoObject extends PDO {
|
||||||
|
|
||||||
public function select(string $sql, array $parameters = []) : PDOStatement
|
public function select(string $sql, array $parameters = []): PDOStatement {
|
||||||
{
|
|
||||||
# var_dump($sql, $parameters);
|
|
||||||
# die();
|
|
||||||
try {
|
try {
|
||||||
if ( false !== ( $statement = $this->prepare($sql) ) ) {
|
if (false !== ( $statement = $this->prepare($sql) )) {
|
||||||
$statement = $this->execute($statement, $parameters, false);
|
$statement = $this->execute($statement, $parameters, false);
|
||||||
$statement->setFetchMode(\PDO::FETCH_ASSOC);
|
$statement->setFetchMode(\PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
return $statement;
|
return $statement;
|
||||||
}
|
}
|
||||||
} catch (\PDOException $e) { throw $e; }
|
} catch (\PDOException $e) {
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function runQuery(string $sql, array $parameters = []) : PDOStatement
|
public function runQuery(string $sql, array $parameters = []): PDOStatement {
|
||||||
{
|
|
||||||
try {
|
try {
|
||||||
if ( false !== ( $statement = $this->prepare($sql) ) ) {
|
if (false !== ( $statement = $this->prepare($sql) )) {
|
||||||
return $this->execute($statement, $parameters, true);
|
return $this->execute($statement, $parameters, true);
|
||||||
}
|
}
|
||||||
} catch (\PDOException $e) { throw $e; }
|
} catch (\PDOException $e) {
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function execute(PDOStatement $statement, array $parameters = [], bool $commit = true) : ? PDOStatement
|
public function execute(PDOStatement $statement, array $parameters = [], bool $commit = true): ?PDOStatement {
|
||||||
{
|
try {
|
||||||
try {
|
if (!$this->inTransaction()) {
|
||||||
if (! $this->inTransaction() ) {
|
$this->beginTransaction();
|
||||||
$this->beginTransaction();
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if ( empty($parameters) ? $statement->execute() : $statement->execute($parameters) ) {
|
if (empty($parameters) ? $statement->execute() : $statement->execute($parameters)) {
|
||||||
if ( $commit ) {
|
$statement->lastInsertId = $this->lastInsertId();
|
||||||
$this->commit();
|
|
||||||
|
if ($commit) {
|
||||||
|
$this->commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
return $statement;
|
return $statement;
|
||||||
}
|
} else {
|
||||||
else {
|
throw new PDOException('Could not begin transaction or given statement is invalid.');
|
||||||
throw new PDOException('Could not begin transaction or given statement is invalid.');
|
}
|
||||||
}
|
} catch (\PDOException $e) {
|
||||||
} catch (\PDOException $e) {
|
$this->rollback();
|
||||||
$this->rollback();
|
throw $e;
|
||||||
throw $e;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -121,11 +121,21 @@ trait EntityTrait {
|
||||||
|
|
||||||
public function entityGetDataset() : array
|
public function entityGetDataset() : array
|
||||||
{
|
{
|
||||||
$fields = array_keys($this->resolveEntity()->fieldList());
|
$dataset = [];
|
||||||
|
$entityResolver = $this->resolveEntity();
|
||||||
|
|
||||||
return array_combine($fields, array_map(function(string $key) {
|
foreach($entityResolver->fieldList() as $key => $field) {
|
||||||
return $this->$key;
|
$annotation = $entityResolver->searchFieldAnnotation($key, new Field() );
|
||||||
}, $fields));
|
|
||||||
|
if ( isset($this->$key) ) {
|
||||||
|
$dataset[ $annotation->name ?? $key ] = $this->$key;
|
||||||
|
}
|
||||||
|
elseif ( $field['nullable'] ) {
|
||||||
|
$dataset[ $annotation->name ?? $key ] = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $dataset;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function toArray() : array
|
public function toArray() : array
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Ulmus\Exception;
|
||||||
|
|
||||||
|
class EntityRequiredField extends \RuntimeException {}
|
|
@ -31,6 +31,6 @@ class Insert extends Fragment {
|
||||||
|
|
||||||
protected function renderTable() : string
|
protected function renderTable() : string
|
||||||
{
|
{
|
||||||
return $this->table . ( $this->alias ? " {$this->alias}" : "" );
|
return $this->table;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Ulmus\Query;
|
||||||
|
|
||||||
|
use Ulmus\QueryBuilder;
|
||||||
|
|
||||||
|
class Set extends Fragment {
|
||||||
|
|
||||||
|
public int $order = 0;
|
||||||
|
|
||||||
|
public array $dataset;
|
||||||
|
|
||||||
|
public QueryBuilder $queryBuilder;
|
||||||
|
|
||||||
|
public function __construct(QueryBuilder $queryBuilder)
|
||||||
|
{
|
||||||
|
$this->queryBuilder = $queryBuilder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function set(array $dataset) : self
|
||||||
|
{
|
||||||
|
$this->dataset = $dataset;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function render() : string
|
||||||
|
{
|
||||||
|
return $this->renderSegments([
|
||||||
|
'SET', $this->renderParameterPlaceholders(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function renderParameterPlaceholders() : string
|
||||||
|
{
|
||||||
|
$keys = [];
|
||||||
|
|
||||||
|
foreach($this->dataset as $key =>$value) {
|
||||||
|
$this->queryBuilder->addParameter($value, ":v_$key");
|
||||||
|
$keys[] = "$key=:v_$key";
|
||||||
|
}
|
||||||
|
|
||||||
|
return implode(",", $keys);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Ulmus\Query;
|
||||||
|
|
||||||
|
class Update extends Fragment {
|
||||||
|
|
||||||
|
public int $order = -100;
|
||||||
|
|
||||||
|
public bool $quick = false;
|
||||||
|
|
||||||
|
public bool $ignore = false;
|
||||||
|
|
||||||
|
public array $fieldlist = [];
|
||||||
|
|
||||||
|
public string $priority;
|
||||||
|
|
||||||
|
public string $table;
|
||||||
|
|
||||||
|
public ? string $alias = null;
|
||||||
|
|
||||||
|
public function render() : string
|
||||||
|
{
|
||||||
|
return $this->renderSegments([
|
||||||
|
'UPDATE',
|
||||||
|
( $this->priority ?? false ),
|
||||||
|
( $this->ignore ? 'IGNORE' : false ),
|
||||||
|
$this->table,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function renderTable() : string
|
||||||
|
{
|
||||||
|
return $this->table;
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,10 +2,14 @@
|
||||||
|
|
||||||
namespace Ulmus\Query;
|
namespace Ulmus\Query;
|
||||||
|
|
||||||
|
use Ulmus\QueryBuilder;
|
||||||
|
|
||||||
class Values extends Fragment {
|
class Values extends Fragment {
|
||||||
|
|
||||||
public int $order = 0;
|
public int $order = 0;
|
||||||
|
|
||||||
|
public ? int $fieldCount = null;
|
||||||
|
|
||||||
public array $rows;
|
public array $rows;
|
||||||
|
|
||||||
public QueryBuilder $queryBuilder;
|
public QueryBuilder $queryBuilder;
|
||||||
|
@ -17,36 +21,38 @@ class Values extends Fragment {
|
||||||
|
|
||||||
public function add(array $row) : self
|
public function add(array $row) : self
|
||||||
{
|
{
|
||||||
$this->rows[] = $row;
|
if ($this->fieldCount === null) {
|
||||||
|
$this->fieldCount = count($row);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->rows[] = array_values($row);
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function render() : string
|
public function render() : string
|
||||||
{
|
{
|
||||||
$this->queryBuilder->addParameter($this->flattenRowsArray());
|
$this->queryBuilder->addValues($this->flattenRowsArray());
|
||||||
|
|
||||||
return $this->renderSegments([
|
return $this->renderSegments([
|
||||||
'VALUES', '(' . $this->renderParameterPlaceholders() . ')',
|
'VALUES', $this->renderParameterPlaceholders(),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function renderParameterPlaceholders() : string
|
public function renderParameterPlaceholders() : string
|
||||||
{
|
{
|
||||||
$return = [];
|
$return = [];
|
||||||
$count = null;
|
|
||||||
|
|
||||||
foreach($this->rows as $row) {
|
foreach($this->rows as $row) {
|
||||||
if ($count === null) {
|
if ($this->fieldCount === null) {
|
||||||
$count = count($row);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (count($row) !== $count) {
|
if (count($row) !== $this->fieldCount) {
|
||||||
throw new \Exception("Insert statement must contains the same number of values for each rows.");
|
throw new \Exception("Insert statement must contains the same number of values for each rows.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$return[] = implode(',', array_fill(0, $this->parameterCount, '?'));
|
$return[] = implode(',', array_fill(0, $this->fieldCount, '?'));
|
||||||
}
|
}
|
||||||
|
|
||||||
return "(" . implode('),(', $return) . ")";
|
return "(" . implode('),(', $return) . ")";
|
||||||
|
@ -54,6 +60,6 @@ class Values extends Fragment {
|
||||||
|
|
||||||
public function flattenRowsArray() : array
|
public function flattenRowsArray() : array
|
||||||
{
|
{
|
||||||
return iterator_to_array(new RecursiveIteratorIterator(new RecursiveArrayIterator($this->rows)));
|
return \iterator_to_array(new \RecursiveIteratorIterator(new \RecursiveArrayIterator($this->rows)));
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -51,7 +51,7 @@ class QueryBuilder
|
||||||
$insert = new Query\Insert();
|
$insert = new Query\Insert();
|
||||||
$this->push($insert);
|
$this->push($insert);
|
||||||
|
|
||||||
$insert->fieldist = $fieldlist;
|
$insert->fieldlist = $fieldlist;
|
||||||
$insert->alias = $alias;
|
$insert->alias = $alias;
|
||||||
$insert->table = $table;
|
$insert->table = $table;
|
||||||
}
|
}
|
||||||
|
@ -63,7 +63,7 @@ class QueryBuilder
|
||||||
{
|
{
|
||||||
|
|
||||||
if ( false === ( $values = $this->has(Query\Values::class) ) ) {
|
if ( false === ( $values = $this->has(Query\Values::class) ) ) {
|
||||||
$values = new Query\Values();
|
$values = new Query\Values($this);
|
||||||
$this->push($values);
|
$this->push($values);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,6 +72,40 @@ class QueryBuilder
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function update(string $table, ? string $alias = null, ? string $database = null, ? string $schema = null) : self
|
||||||
|
{
|
||||||
|
if ( ! $this->has(Query\Update::class) ) {
|
||||||
|
if ( $database ) {
|
||||||
|
$table = "\"$database\".$table";
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( $schema ) {
|
||||||
|
$table = "\"$schema\".$table";
|
||||||
|
}
|
||||||
|
|
||||||
|
$update = new Query\Update();
|
||||||
|
$this->push($update);
|
||||||
|
|
||||||
|
$update->alias = $alias;
|
||||||
|
$update->table = $table;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function set(array $dataset) : self
|
||||||
|
{
|
||||||
|
|
||||||
|
if ( false === ( $values = $this->has(Query\Set::class) ) ) {
|
||||||
|
$set = new Query\Set($this);
|
||||||
|
$this->push($set);
|
||||||
|
}
|
||||||
|
|
||||||
|
$set->set($dataset);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
public function delete() : self
|
public function delete() : self
|
||||||
{
|
{
|
||||||
if ( ! $this->has(Query\Delete::class) ) {
|
if ( ! $this->has(Query\Delete::class) ) {
|
||||||
|
@ -180,12 +214,14 @@ class QueryBuilder
|
||||||
}
|
}
|
||||||
|
|
||||||
$orderBy->add($field, $direction);
|
$orderBy->add($field, $direction);
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function push(Query\Fragment $queryFragment) : self
|
public function push(Query\Fragment $queryFragment) : self
|
||||||
{
|
{
|
||||||
$this->queryStack[] = $queryFragment;
|
$this->queryStack[] = $queryFragment;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -226,10 +262,12 @@ class QueryBuilder
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->parameters[$key] = $value;
|
$this->parameters[$key] = $value;
|
||||||
|
|
||||||
return $key;
|
return $key;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function addValues(array $values) {
|
public function addValues(array $values) : void
|
||||||
|
{
|
||||||
$this->values = $values;
|
$this->values = $values;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,12 +75,28 @@ class Repository
|
||||||
public function save(object $entity) : bool
|
public function save(object $entity) : bool
|
||||||
{
|
{
|
||||||
$dataset = $entity->toArray();
|
$dataset = $entity->toArray();
|
||||||
|
$primaryKeyDefinition = Ulmus::resolveEntity($this->entityClass)->getPrimaryKeyField();
|
||||||
|
|
||||||
if ( ! $entity->isLoaded() ) {
|
if ( ! $entity->isLoaded() ) {
|
||||||
$save = $this->insertSqlQuery($dataset)->runQuery();
|
$statement = $this->insertSqlQuery($dataset)->runQuery();
|
||||||
|
|
||||||
|
if ( ( 0 !== $statement->lastInsertId ) &&
|
||||||
|
( null !== $primaryKeyDefinition )) {
|
||||||
|
$pkField = key($primaryKeyDefinition);
|
||||||
|
$entity->$pkField = $statement->lastInsertId;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$save = $this->updateSqlQuery($dataset)->runQuery();
|
if ($primaryKeyDefinition === null) {
|
||||||
|
throw new \Exception(sprintf("No primary key found for entity %s", $this->entityClass));
|
||||||
|
}
|
||||||
|
|
||||||
|
$pkField = key($primaryKeyDefinition);
|
||||||
|
$pkFieldName = $primaryKeyDefinition[$pkField]->name ?? $pkField;
|
||||||
|
$this->where($pkFieldName, $dataset[$pkFieldName]);
|
||||||
|
|
||||||
|
# DATASET MUST BE DIFF OF MODIF ONLY !
|
||||||
|
$update = $this->updateSqlQuery($dataset)->runQuery();
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -119,6 +135,20 @@ class Repository
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function update(array $fieldlist, string $table, string $alias, ? string $schema) : self
|
||||||
|
{
|
||||||
|
$this->queryBuilder->update($table, $alias, $schema);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function set(array $dataset) : self
|
||||||
|
{
|
||||||
|
$this->queryBuilder->set($dataset);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
public function delete() : self
|
public function delete() : self
|
||||||
{
|
{
|
||||||
$this->queryBuilder->delete($this->alias);
|
$this->queryBuilder->delete($this->alias);
|
||||||
|
@ -176,7 +206,7 @@ class Repository
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function notWhere(array $condition) : self
|
public function notWhere($field, $value, string $operator = Query\Where::OPERATOR_NOT_EQUAL) : self
|
||||||
{
|
{
|
||||||
$this->queryBuilder->where($field, $value, $operator, Query\Where::CONDITION_AND, true);
|
$this->queryBuilder->where($field, $value, $operator, Query\Where::CONDITION_AND, true);
|
||||||
|
|
||||||
|
@ -269,18 +299,21 @@ class Repository
|
||||||
public function orderBy(string $field, ? string $direction = null) : self
|
public function orderBy(string $field, ? string $direction = null) : self
|
||||||
{
|
{
|
||||||
$this->queryBuilder->orderBy($field, $direction);
|
$this->queryBuilder->orderBy($field, $direction);
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function limit(int $value) : self
|
public function limit(int $value) : self
|
||||||
{
|
{
|
||||||
$this->queryBuilder->limit($value);
|
$this->queryBuilder->limit($value);
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function offset(int $value) : self
|
public function offset(int $value) : self
|
||||||
{
|
{
|
||||||
$this->queryBuilder->offset($value);
|
$this->queryBuilder->offset($value);
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -314,7 +347,7 @@ class Repository
|
||||||
return $entityCollection;
|
return $entityCollection;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function runQuery()
|
public function runQuery() : \PDOStatement
|
||||||
{
|
{
|
||||||
return Ulmus::runQuery($this->queryBuilder);
|
return Ulmus::runQuery($this->queryBuilder);
|
||||||
}
|
}
|
||||||
|
@ -322,10 +355,10 @@ class Repository
|
||||||
protected function insertSqlQuery(array $dataset) : self
|
protected function insertSqlQuery(array $dataset) : self
|
||||||
{
|
{
|
||||||
if ( ! $this->queryBuilder->has(Query\Insert::class) ) {
|
if ( ! $this->queryBuilder->has(Query\Insert::class) ) {
|
||||||
$this->insert(array_keys($dataset));
|
$this->insert(array_keys($dataset), $this->entityResolver->tableName(), $this->alias, $this->entityResolver->schemaName());
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->values(count($dataset));
|
$this->values($dataset);
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
@ -333,9 +366,11 @@ class Repository
|
||||||
protected function updateSqlQuery(array $dataset) : self
|
protected function updateSqlQuery(array $dataset) : self
|
||||||
{
|
{
|
||||||
if ( ! $this->queryBuilder->has(Query\Update::class) ) {
|
if ( ! $this->queryBuilder->has(Query\Update::class) ) {
|
||||||
# $this->insert();
|
$this->update($dataset, $this->entityResolver->tableName(), $this->alias, $this->entityResolver->schemaName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->set($dataset);
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,9 +32,14 @@ abstract class Ulmus
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function pdo(?ConnectionAdapter $adapter = null) : Common\PdoObject
|
||||||
|
{
|
||||||
|
return ( $adapter ?: static::$defaultAdapter )->pdo;
|
||||||
|
}
|
||||||
|
|
||||||
public static function runQuery(QueryBuilder $queryBuilder, ?ConnectionAdapter $adapter = null)
|
public static function runQuery(QueryBuilder $queryBuilder, ?ConnectionAdapter $adapter = null)
|
||||||
{
|
{
|
||||||
return ( $adapter ?: static::$defaultAdapter )->pdo->runQuery($queryBuilder->render(), $queryBuilder->parameters ?? []);
|
return static::pdo($adapter)->runQuery($queryBuilder->render(), array_merge($queryBuilder->values ?? [], $queryBuilder->parameters ?? []));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function resolveEntity(string $entityClass) : Common\EntityResolver
|
public static function resolveEntity(string $entityClass) : Common\EntityResolver
|
||||||
|
|
Loading…
Reference in New Issue