- WIP on insert/update statement
This commit is contained in:
parent
bad5123447
commit
828daffec8
|
@ -149,9 +149,27 @@ class EntityResolver {
|
|||
return $table->schema ?? null;
|
||||
}
|
||||
|
||||
public function primaryKeys() : array
|
||||
public function getPrimaryKeyField() : ? array
|
||||
{
|
||||
foreach($this->fieldList() as $key => $value) {
|
||||
if ( null !== ( $field = $this->searchFieldAnnotation($key, new Field() ) ) ) {
|
||||
if (false !== $field->attributes['primary_key'] ?? false ) {
|
||||
return [ $key => $field ];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getCompoundKeyFields() : ? array
|
||||
{
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getUniqueFields() : ? array
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
<?php
|
||||
|
||||
namespace Ulmus\Entity\Field;
|
||||
|
||||
use DateTime;
|
||||
|
||||
class Date extends DateTime {
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
return $this->format("Y-m-d");
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
|
||||
namespace Ulmus\Entity\Field;
|
||||
|
||||
class Datetime extends \DateTime {
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
return $this->format("Y-m-d H:i:s");
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
<?php
|
||||
|
||||
namespace Ulmus\Entity\Field;
|
||||
|
||||
use DateTime;
|
||||
|
||||
class Time extends DateTime {
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
return $this->format("H:i:s");
|
||||
}
|
||||
|
||||
}
|
|
@ -34,12 +34,21 @@ class EntityCollection extends \ArrayObject {
|
|||
}
|
||||
}
|
||||
|
||||
public function buildArray(string $keyColumn, string $valueColumn) : array
|
||||
public function buildArray(string $keyColumn, /* string|callable */ $value) : array
|
||||
{
|
||||
|
||||
$list = [];
|
||||
|
||||
foreach($this as $key => $item) {
|
||||
$list[$item->$keyColumn] = $item->$valueColumn;
|
||||
switch (true) {
|
||||
case is_string($value):
|
||||
$list[$item->$keyColumn] = $item->$value;
|
||||
break;
|
||||
|
||||
case is_callable($value):
|
||||
$list[$item->$keyColumn] = $value($item);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $list;
|
||||
|
|
|
@ -6,7 +6,7 @@ use Ulmus\Repository,
|
|||
Ulmus\Common\EntityResolver,
|
||||
Ulmus\Common\EntityField;
|
||||
|
||||
use Ulmus\Annotation\Classes\{ Method, Table, Collation as Test, };
|
||||
use Ulmus\Annotation\Classes\{ Method, Table, Collation, };
|
||||
use Ulmus\Annotation\Property\{ Field, Relation, OrderBy, Where, };
|
||||
use Ulmus\Annotation\Property\Field\{ Id, ForeignKey, CreatedAt, UpdatedAt, };
|
||||
|
||||
|
@ -53,7 +53,7 @@ trait EntityTrait {
|
|||
|
||||
switch($relation->type) {
|
||||
case 'oneToMany':
|
||||
$repository->where( $baseEntity->field($relation->foreignKey), 2166); # <<<<<<<<< CHANGE $THIS->ID WITH PROPER NOMENCLATURE
|
||||
$repository->where( $baseEntity->field($relation->foreignKey), $this->$field); # <<<<<<<<< CHANGE $THIS->ID WITH PROPER NOMENCLATURE
|
||||
|
||||
return $this->$name = $repository->loadAll();
|
||||
|
||||
|
@ -71,19 +71,25 @@ trait EntityTrait {
|
|||
|
||||
return;
|
||||
}
|
||||
|
||||
throw new \Exception(sprintf("[%s] - Undefined variable: %s", static::class, $name));
|
||||
}
|
||||
|
||||
/**
|
||||
* @Ignore
|
||||
*/
|
||||
public function entityFillFromDataset($dataset) : self
|
||||
public function entityFillFromDataset(iterable $dataset) : self
|
||||
{
|
||||
$fields = $this->resolveEntity();
|
||||
|
||||
foreach($dataset as $key => $value) {
|
||||
$key = strtolower($key);
|
||||
$field = $fields->field(strtolower($key), EntityResolver::KEY_COLUMN_NAME, false) ?? null;
|
||||
|
||||
if ( null === $field = $fields->field($key, EntityResolver::KEY_COLUMN_NAME, false) ?? null ) {
|
||||
if ( $field === null ) {
|
||||
$field = $fields->field($key, EntityResolver::KEY_ENTITY_NAME, false);
|
||||
}
|
||||
|
||||
if ( $field === null ) {
|
||||
if ($this->strictEntityFieldsDeclaration ) {
|
||||
throw new \Exception("Field `$key` can not be found within your entity ".static::class);
|
||||
}
|
||||
|
@ -108,6 +114,11 @@ trait EntityTrait {
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function fromArray(iterable $dataset) : self
|
||||
{
|
||||
return $this->entityFillFromDataset($dataset);
|
||||
}
|
||||
|
||||
public function entityGetDataset() : array
|
||||
{
|
||||
$fields = array_keys($this->resolveEntity()->fieldList());
|
||||
|
@ -117,6 +128,28 @@ trait EntityTrait {
|
|||
}, $fields));
|
||||
}
|
||||
|
||||
public function toArray() : array
|
||||
{
|
||||
return $this->entityGetDataset();
|
||||
}
|
||||
|
||||
public function toCollection() : array
|
||||
{
|
||||
return new EntityCollection($this->toArray());
|
||||
}
|
||||
|
||||
public function isLoaded() : bool
|
||||
{
|
||||
if ( null === $pkField = $this->resolveEntity()->getPrimaryKeyField($this) ) {
|
||||
throw new Exception\EntityPrimaryKeyUnknown("Entity has no field containing attributes 'primary_key'");
|
||||
}
|
||||
|
||||
$key = key($pkField);
|
||||
|
||||
return isset($this->$key);
|
||||
}
|
||||
|
||||
|
||||
public function __sleep()
|
||||
{
|
||||
return array_keys($this->resolveEntity()->fieldList());
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
<?php
|
||||
|
||||
namespace Ulmus\Exception;
|
||||
|
||||
class EntityPrimaryKeyUnknown extends \RuntimeException {}
|
|
@ -5,21 +5,18 @@ namespace Ulmus\Query;
|
|||
class Delete extends Fragment {
|
||||
|
||||
public int $order = -100;
|
||||
|
||||
public bool $lowPriority = false;
|
||||
|
||||
public bool $quick = false;
|
||||
|
||||
public bool $ignore = false;
|
||||
|
||||
public string $alias;
|
||||
|
||||
public string $priority;
|
||||
|
||||
public function render() : string
|
||||
{
|
||||
return $this->renderSegments([
|
||||
'DELETE',
|
||||
( $this->alias ?? false ),
|
||||
( $this->lowPriority ? 'LOW_PRIORITY' : false ),
|
||||
( $this->priority ?? false ),
|
||||
( $this->quick ? 'QUICK' : false ),
|
||||
( $this->ignore ? 'IGNORE' : false ),
|
||||
]);
|
||||
|
|
|
@ -2,28 +2,20 @@
|
|||
|
||||
namespace Ulmus\Query;
|
||||
|
||||
use Ulmus\QueryBuilder;
|
||||
|
||||
class From extends Fragment {
|
||||
|
||||
public int $order = -80;
|
||||
|
||||
protected $tables = [];
|
||||
|
||||
public QueryBuilder $queryBuilder;
|
||||
public array $tables = [];
|
||||
|
||||
public function __construct(QueryBuilder $queryBuilder)
|
||||
{
|
||||
$this->queryBuilder = $queryBuilder;
|
||||
}
|
||||
|
||||
public function set(array $tables) : self
|
||||
{
|
||||
$this->tables = $tables;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function add($table) : self
|
||||
public function add(/* array|string */ $table) : self
|
||||
{
|
||||
foreach((array) $table as $alias => $name) {
|
||||
$this->tables[$alias] = $name;
|
||||
|
|
|
@ -4,6 +4,33 @@ namespace Ulmus\Query;
|
|||
|
||||
class Insert extends Fragment {
|
||||
|
||||
public bool $ignore = false;
|
||||
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([
|
||||
'INSERT',
|
||||
( $this->priority ?? false ),
|
||||
( $this->ignore ? 'IGNORE' : false ),
|
||||
'INTO', $this->renderTable(),
|
||||
"(" . implode(',', $this->fieldlist) . ")",
|
||||
]);
|
||||
}
|
||||
|
||||
protected function renderTable() : string
|
||||
{
|
||||
return $this->table . ( $this->alias ? " {$this->alias}" : "" );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
<?php
|
||||
|
||||
namespace Ulmus\Query;
|
||||
|
||||
class Values extends Fragment {
|
||||
|
||||
public int $order = 0;
|
||||
|
||||
public array $rows;
|
||||
|
||||
public QueryBuilder $queryBuilder;
|
||||
|
||||
public function __construct(QueryBuilder $queryBuilder)
|
||||
{
|
||||
$this->queryBuilder = $queryBuilder;
|
||||
}
|
||||
|
||||
public function add(array $row) : self
|
||||
{
|
||||
$this->rows[] = $row;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function render() : string
|
||||
{
|
||||
$this->queryBuilder->addParameter($this->flattenRowsArray());
|
||||
|
||||
return $this->renderSegments([
|
||||
'VALUES', '(' . $this->renderParameterPlaceholders() . ')',
|
||||
]);
|
||||
}
|
||||
|
||||
public function renderParameterPlaceholders() : string
|
||||
{
|
||||
$return = [];
|
||||
$count = null;
|
||||
|
||||
foreach($this->rows as $row) {
|
||||
if ($count === null) {
|
||||
$count = count($row);
|
||||
}
|
||||
else {
|
||||
if (count($row) !== $count) {
|
||||
throw new \Exception("Insert statement must contains the same number of values for each rows.");
|
||||
}
|
||||
}
|
||||
|
||||
$return[] = implode(',', array_fill(0, $this->parameterCount, '?'));
|
||||
}
|
||||
|
||||
return "(" . implode('),(', $return) . ")";
|
||||
}
|
||||
|
||||
public function flattenRowsArray() : array
|
||||
{
|
||||
return iterator_to_array(new RecursiveIteratorIterator(new RecursiveArrayIterator($this->rows)));
|
||||
}
|
||||
}
|
|
@ -10,6 +10,12 @@ class QueryBuilder
|
|||
* Those are the parameters we are going to bind to PDO.
|
||||
*/
|
||||
public array $parameters = [];
|
||||
|
||||
/**
|
||||
*
|
||||
* Those values are to be inserted or updated
|
||||
*/
|
||||
public array $values = [];
|
||||
|
||||
public string $conditionOperator = Query\Where::CONDITION_AND;
|
||||
|
||||
|
@ -31,13 +37,45 @@ class QueryBuilder
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function delete(string $alias = "") : self
|
||||
public function insert(array $fieldlist, string $table, ? string $alias = null, ? string $database = null, ? string $schema = null) : self
|
||||
{
|
||||
if ( ! $this->has(Query\Insert::class) ) {
|
||||
if ( $database ) {
|
||||
$table = "\"$database\".$table";
|
||||
}
|
||||
|
||||
if ( $schema ) {
|
||||
$table = "\"$schema\".$table";
|
||||
}
|
||||
|
||||
$insert = new Query\Insert();
|
||||
$this->push($insert);
|
||||
|
||||
$insert->fieldist = $fieldlist;
|
||||
$insert->alias = $alias;
|
||||
$insert->table = $table;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function values(array $dataset) : self
|
||||
{
|
||||
|
||||
if ( false === ( $values = $this->has(Query\Values::class) ) ) {
|
||||
$values = new Query\Values();
|
||||
$this->push($values);
|
||||
}
|
||||
|
||||
$values->add($dataset);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function delete() : self
|
||||
{
|
||||
if ( ! $this->has(Query\Delete::class) ) {
|
||||
$delete = new Query\Delete();
|
||||
|
||||
$delete->alias = $alias;
|
||||
$this->push($delete);
|
||||
$this->push(new Query\Delete());
|
||||
}
|
||||
|
||||
return $this;
|
||||
|
@ -45,8 +83,6 @@ class QueryBuilder
|
|||
|
||||
public function from(string $table, ? string $alias = null, ? string $database = null, ? string $schema = null) : self
|
||||
{
|
||||
// $table = "\"$table\"";
|
||||
|
||||
if ( $database ) {
|
||||
$table = "\"$database\".$table";
|
||||
}
|
||||
|
@ -61,6 +97,7 @@ class QueryBuilder
|
|||
else {
|
||||
$from = new Query\From($this);
|
||||
$this->push($from);
|
||||
|
||||
$from->set($alias ? [ $alias => $table ] : $table);
|
||||
}
|
||||
|
||||
|
@ -98,6 +135,7 @@ class QueryBuilder
|
|||
|
||||
$this->conditionOperator = $operator;
|
||||
$where->add($field, $value, $operator, $condition, $not);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
@ -181,7 +219,8 @@ class QueryBuilder
|
|||
return $this->render();
|
||||
}
|
||||
|
||||
public function addParameter($value, $key = null) {
|
||||
public function addParameter($value, string $key = null) : string
|
||||
{
|
||||
if ( $key === null ) {
|
||||
$key = ":p" . $this->parameterIndex++;
|
||||
}
|
||||
|
@ -189,4 +228,8 @@ class QueryBuilder
|
|||
$this->parameters[$key] = $value;
|
||||
return $key;
|
||||
}
|
||||
|
||||
public function addValues(array $values) {
|
||||
$this->values = $values;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -74,12 +74,23 @@ class Repository
|
|||
|
||||
public function save(object $entity) : bool
|
||||
{
|
||||
$dataset = $entity->toArray();
|
||||
|
||||
if ( ! $entity->isLoaded() ) {
|
||||
$save = $this->insertSqlQuery($dataset)->runQuery();
|
||||
}
|
||||
else {
|
||||
$save = $this->updateSqlQuery($dataset)->runQuery();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function saveAll(EntityCollection $collection) : bool
|
||||
{
|
||||
|
||||
foreach($collection as $entity) {
|
||||
$this->save($entity);
|
||||
}
|
||||
}
|
||||
|
||||
public function yieldAll() : \Generator
|
||||
|
@ -94,6 +105,20 @@ class Repository
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function insert(array $fieldlist, string $table, string $alias, ? string $schema) : self
|
||||
{
|
||||
$this->queryBuilder->insert($fieldlist, $table, $alias, $schema);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function values(array $dataset) : self
|
||||
{
|
||||
$this->queryBuilder->values($dataset);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function delete() : self
|
||||
{
|
||||
$this->queryBuilder->delete($this->alias);
|
||||
|
@ -269,6 +294,13 @@ class Repository
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function wherePrimaryKey($value) : self
|
||||
{
|
||||
if ( null === $primaryKeyField = Ulmus::resolveEntity($this->entityClass)->getPrimaryKeyField() ) {
|
||||
throw new Exception\EntityPrimaryKeyUnknown("Entity has no field containing attributes 'primary_key'");
|
||||
}
|
||||
}
|
||||
|
||||
protected function collectionFromQuery() : EntityCollection
|
||||
{
|
||||
$class = $this->entityClass;
|
||||
|
@ -287,6 +319,26 @@ class Repository
|
|||
return Ulmus::runQuery($this->queryBuilder);
|
||||
}
|
||||
|
||||
protected function insertSqlQuery(array $dataset) : self
|
||||
{
|
||||
if ( ! $this->queryBuilder->has(Query\Insert::class) ) {
|
||||
$this->insert(array_keys($dataset));
|
||||
}
|
||||
|
||||
$this->values(count($dataset));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function updateSqlQuery(array $dataset) : self
|
||||
{
|
||||
if ( ! $this->queryBuilder->has(Query\Update::class) ) {
|
||||
# $this->insert();
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function selectSqlQuery() : self
|
||||
{
|
||||
if ( ! $this->queryBuilder->has(Query\Select::class) ) {
|
||||
|
|
Loading…
Reference in New Issue