SQL expression rewrite, Pagination, some frontend stuff

This commit is contained in:
2023-01-05 22:47:17 +01:00
parent 4bfd6754cf
commit 99bfd7e505
61 changed files with 1745 additions and 570 deletions

View File

@@ -2,10 +2,14 @@
namespace Core\Objects\DatabaseEntity\Controller;
use ArrayAccess;
use Core\Driver\SQL\Condition\Condition;
use Core\Driver\SQL\Expression\Count;
use Core\Driver\SQL\SQL;
use Core\Objects\DatabaseEntity\Attribute\Transient;
use JsonSerializable;
abstract class DatabaseEntity {
abstract class DatabaseEntity implements ArrayAccess, JsonSerializable {
protected static array $entityLogConfig = [
"insert" => false,
@@ -16,11 +20,38 @@ abstract class DatabaseEntity {
private static array $handlers = [];
protected ?int $id;
#[Transient] protected array $customData = [];
public function __construct(?int $id = null) {
$this->id = $id;
}
public function offsetExists(mixed $offset): bool {
return property_exists($this, $offset) || array_key_exists($offset, $this->customData);
}
public function offsetGet(mixed $offset): mixed {
if (property_exists($this, $offset)) {
return $this->{$offset};
} else {
return $this->customData[$offset];
}
}
public function offsetSet(mixed $offset, mixed $value): void {
if (property_exists($this, $offset)) {
$this->{$offset} = $value;
} else {
$this->customData[$offset] = $value;
}
}
public function offsetUnset(mixed $offset): void {
if (array_key_exists($offset, $this->customData)) {
unset($this->customData[$offset]);
}
}
public abstract function jsonSerialize(): array;
public function preInsert(array &$row) { }
@@ -49,7 +80,7 @@ abstract class DatabaseEntity {
public static function exists(SQL $sql, int $id): bool {
$handler = self::getHandler($sql);
$res = $sql->select($sql->count())
$res = $sql->select(new Count())
->from($handler->getTableName())
->whereEq($handler->getTableName() . ".id", $id)
->execute();
@@ -148,7 +179,7 @@ abstract class DatabaseEntity {
public static function count(SQL $sql, ?Condition $condition = null): int|bool {
$handler = self::getHandler($sql);
$query = $sql->select($sql->count())
$query = $sql->select(new Count())
->from($handler->getTableName());
if ($condition) {

View File

@@ -269,7 +269,7 @@ class DatabaseEntityHandler implements Persistable {
return $rel_row;
}
private function getValueFromRow(array $row, string $propertyName, mixed &$value): bool {
private function getValueFromRow(array $row, string $propertyName, mixed &$value, bool $initEntities = false): bool {
$column = $this->columns[$propertyName] ?? null;
if (!$column) {
return false;
@@ -290,8 +290,12 @@ class DatabaseEntityHandler implements Persistable {
if (array_key_exists($relColumnPrefix . "id", $row)) {
$relId = $row[$relColumnPrefix . "id"];
if ($relId !== null) {
$relationHandler = $this->relations[$propertyName];
$value = $relationHandler->entityFromRow(self::getPrefixedRow($row, $relColumnPrefix));
if ($initEntities) {
$relationHandler = $this->relations[$propertyName];
$value = $relationHandler->entityFromRow(self::getPrefixedRow($row, $relColumnPrefix), [], true);
} else {
return false;
}
} else if (!$column->notNull()) {
$value = null;
} else {
@@ -305,7 +309,7 @@ class DatabaseEntityHandler implements Persistable {
return true;
}
public function entityFromRow(array $row): ?DatabaseEntity {
public function entityFromRow(array $row, array $additionalColumns = [], bool $initEntities = false): ?DatabaseEntity {
try {
$constructorClass = $this->entityClass;
@@ -324,12 +328,18 @@ class DatabaseEntityHandler implements Persistable {
}
foreach ($this->properties as $property) {
if ($this->getValueFromRow($row, $property->getName(), $value)) {
if ($this->getValueFromRow($row, $property->getName(), $value, $initEntities)) {
$property->setAccessible(true);
$property->setValue($entity, $value);
}
}
foreach ($additionalColumns as $column) {
if (!in_array($column, $this->columns) && !isset($this->properties[$column])) {
$entity[$column] = $row[$column];
}
}
// init n:m / 1:n properties with empty arrays
foreach ($this->nmRelations as $nmRelation) {
foreach ($nmRelation->getProperties($this) as $property) {
@@ -453,9 +463,12 @@ class DatabaseEntityHandler implements Persistable {
if ($recursive) {
foreach ($entities as $entity) {
foreach ($this->relations as $propertyName => $relHandler) {
$relEntity = $this->properties[$propertyName]->getValue($entity);
if ($relEntity) {
$relHandler->fetchNMRelations([$relEntity->getId() => $relEntity], true);
$property = $this->properties[$propertyName];
if ($property->isInitialized($entity) || true) {
$relEntity = $this->properties[$propertyName]->getValue($entity);
if ($relEntity) {
$relHandler->fetchNMRelations([$relEntity->getId() => $relEntity], true);
}
}
}
}
@@ -483,10 +496,10 @@ class DatabaseEntityHandler implements Persistable {
->addJoin(new InnerJoin($nmTable, "$nmTable.$refIdColumn", "$refTableName.id"))
->where(new CondIn(new Column($thisIdColumn), $entityIds));
$relEntityQuery->addColumn($thisIdColumn);
$relEntityQuery->addSelectValue(new Column($thisIdColumn));
foreach ($dataColumns as $tableDataColumns) {
foreach ($tableDataColumns as $columnName) {
$relEntityQuery->addColumn($columnName);
$relEntityQuery->addSelectValue(new Column($columnName));
}
}
@@ -500,7 +513,7 @@ class DatabaseEntityHandler implements Persistable {
foreach ($rows as $row) {
$relId = $row["id"];
if (!isset($relEntities[$relId])) {
$relEntity = $otherHandler->entityFromRow($row);
$relEntity = $otherHandler->entityFromRow($row, [], $recursive);
$relEntities[$relId] = $relEntity;
}

View File

@@ -3,8 +3,11 @@
namespace Core\Objects\DatabaseEntity\Controller;
use Core\Driver\Logger\Logger;
use Core\Driver\SQL\Column\Column;
use Core\Driver\SQL\Expression\Alias;
use Core\Driver\SQL\Query\Select;
use Core\Driver\SQL\SQL;
use Core\External\PHPMailer\Exception;
/**
* this class is similar to \Driver\SQL\Query\Select but with reduced functionality
@@ -20,6 +23,7 @@ class DatabaseEntityQuery extends Select {
private DatabaseEntityHandler $handler;
private int $resultType;
private bool $logVerbose;
private array $additionalColumns;
private int $fetchSubEntities;
@@ -29,6 +33,7 @@ class DatabaseEntityQuery extends Select {
$this->logger = new Logger("DB-EntityQuery", $handler->getSQL());
$this->resultType = $resultType;
$this->logVerbose = false;
$this->additionalColumns = [];
$this->from($handler->getTableName());
$this->fetchSubEntities = self::FETCH_NONE;
@@ -37,6 +42,26 @@ class DatabaseEntityQuery extends Select {
}
}
public function addCustomValue(mixed $selectValue): Select {
if (is_string($selectValue)) {
$this->additionalColumns[] = $selectValue;
} else if ($selectValue instanceof Alias) {
$this->additionalColumns[] = $selectValue->getAlias();
} else if ($selectValue instanceof Column) {
$this->additionalColumns[] = $selectValue->getName();
} else {
$this->logger->debug("Cannot get selected column name from custom value of type: " . get_class($selectValue));
return $this;
}
$this->addSelectValue($selectValue);
return $this;
}
public function getHandler(): DatabaseEntityHandler {
return $this->handler;
}
public function debug(): DatabaseEntityQuery {
$this->logVerbose = true;
return $this;
@@ -112,7 +137,7 @@ class DatabaseEntityQuery extends Select {
if ($this->resultType === SQL::FETCH_ALL) {
$entities = [];
foreach ($res as $row) {
$entity = $this->handler->entityFromRow($row);
$entity = $this->handler->entityFromRow($row, $this->additionalColumns, $this->fetchSubEntities !== self::FETCH_NONE);
if ($entity) {
$entities[$entity->getId()] = $entity;
}
@@ -124,7 +149,7 @@ class DatabaseEntityQuery extends Select {
return $entities;
} else if ($this->resultType === SQL::FETCH_ONE) {
$entity = $this->handler->entityFromRow($res);
$entity = $this->handler->entityFromRow($res, $this->additionalColumns, $this->fetchSubEntities !== self::FETCH_NONE);
if ($entity instanceof DatabaseEntity && $this->fetchSubEntities !== self::FETCH_NONE) {
$this->handler->fetchNMRelations([$entity->getId() => $entity], $this->fetchSubEntities === self::FETCH_RECURSIVE);
}

View File

@@ -104,6 +104,8 @@ class NMRelation implements Persistable {
}
public static function buildTableName(string ...$tables): string {
// in case of class passed here
$tables = array_map(function ($t) { return isClass($t) ? getClassName($t) : $t; }, $tables);
sort($tables);
return "NM_" . implode("_", $tables);
}