2022-06-20 19:52:31 +02:00
|
|
|
<?php
|
|
|
|
|
2022-11-20 17:13:53 +01:00
|
|
|
namespace Core\Objects\DatabaseEntity\Controller;
|
2022-06-20 19:52:31 +02:00
|
|
|
|
2022-11-19 01:15:34 +01:00
|
|
|
use Core\Driver\Logger\Logger;
|
2023-01-05 22:47:17 +01:00
|
|
|
use Core\Driver\SQL\Column\Column;
|
|
|
|
use Core\Driver\SQL\Expression\Alias;
|
2022-11-18 18:06:46 +01:00
|
|
|
use Core\Driver\SQL\Query\Select;
|
|
|
|
use Core\Driver\SQL\SQL;
|
2023-01-05 22:47:17 +01:00
|
|
|
use Core\External\PHPMailer\Exception;
|
2022-06-20 19:52:31 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* this class is similar to \Driver\SQL\Query\Select but with reduced functionality
|
|
|
|
* and more adapted to entities.
|
|
|
|
*/
|
2022-11-26 23:57:28 +01:00
|
|
|
class DatabaseEntityQuery extends Select {
|
2022-06-20 19:52:31 +02:00
|
|
|
|
2022-11-20 17:13:53 +01:00
|
|
|
const FETCH_NONE = 0;
|
|
|
|
const FETCH_DIRECT = 1;
|
|
|
|
const FETCH_RECURSIVE = 2;
|
|
|
|
|
2022-11-19 01:15:34 +01:00
|
|
|
private Logger $logger;
|
2022-06-20 19:52:31 +02:00
|
|
|
private DatabaseEntityHandler $handler;
|
|
|
|
private int $resultType;
|
2022-11-19 01:15:34 +01:00
|
|
|
private bool $logVerbose;
|
2023-01-05 22:47:17 +01:00
|
|
|
private array $additionalColumns;
|
2022-06-20 19:52:31 +02:00
|
|
|
|
2022-11-20 17:13:53 +01:00
|
|
|
private int $fetchSubEntities;
|
|
|
|
|
2022-06-20 19:52:31 +02:00
|
|
|
private function __construct(DatabaseEntityHandler $handler, int $resultType) {
|
2022-11-26 23:57:28 +01:00
|
|
|
parent::__construct($handler->getSQL(), ...$handler->getColumnNames());
|
2022-06-20 19:52:31 +02:00
|
|
|
$this->handler = $handler;
|
2022-11-19 01:15:34 +01:00
|
|
|
$this->logger = new Logger("DB-EntityQuery", $handler->getSQL());
|
2022-06-20 19:52:31 +02:00
|
|
|
$this->resultType = $resultType;
|
2022-11-19 01:15:34 +01:00
|
|
|
$this->logVerbose = false;
|
2023-01-05 22:47:17 +01:00
|
|
|
$this->additionalColumns = [];
|
2022-06-20 19:52:31 +02:00
|
|
|
|
2022-11-26 23:57:28 +01:00
|
|
|
$this->from($handler->getTableName());
|
|
|
|
$this->fetchSubEntities = self::FETCH_NONE;
|
2022-06-20 19:52:31 +02:00
|
|
|
if ($this->resultType === SQL::FETCH_ONE) {
|
2022-11-26 23:57:28 +01:00
|
|
|
$this->first();
|
2022-06-20 19:52:31 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-07 15:34:05 +01:00
|
|
|
public function only(array $fields): DatabaseEntityQuery {
|
|
|
|
if (!in_array("id", $fields)) {
|
|
|
|
$fields[] = "id";
|
|
|
|
}
|
|
|
|
|
|
|
|
$this->select(array_map(function ($field) {
|
|
|
|
return $this->handler->getColumnName($field);
|
|
|
|
}, $fields));
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function addCustomValue(mixed $selectValue): DatabaseEntityQuery {
|
2023-01-05 22:47:17 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2022-11-19 01:15:34 +01:00
|
|
|
public function debug(): DatabaseEntityQuery {
|
|
|
|
$this->logVerbose = true;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2022-06-20 19:52:31 +02:00
|
|
|
public static function fetchAll(DatabaseEntityHandler $handler): DatabaseEntityQuery {
|
|
|
|
return new DatabaseEntityQuery($handler, SQL::FETCH_ALL);
|
|
|
|
}
|
|
|
|
|
|
|
|
public static function fetchOne(DatabaseEntityHandler $handler): DatabaseEntityQuery {
|
|
|
|
return new DatabaseEntityQuery($handler, SQL::FETCH_ONE);
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: clean this up
|
|
|
|
public function fetchEntities(bool $recursive = false): DatabaseEntityQuery {
|
|
|
|
|
|
|
|
// $this->selectQuery->dump();
|
2022-11-20 17:13:53 +01:00
|
|
|
$this->fetchSubEntities = ($recursive ? self::FETCH_RECURSIVE : self::FETCH_DIRECT);
|
2022-06-20 19:52:31 +02:00
|
|
|
|
|
|
|
$relIndex = 1;
|
|
|
|
foreach ($this->handler->getRelations() as $propertyName => $relationHandler) {
|
2023-01-15 00:32:17 +01:00
|
|
|
if ($this->handler !== $relationHandler) {
|
|
|
|
$this->fetchRelation($propertyName, $this->handler->getTableName(), $this->handler, $relationHandler, $relIndex, $recursive);
|
|
|
|
}
|
2022-06-20 19:52:31 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
private function fetchRelation(string $propertyName, string $tableName, DatabaseEntityHandler $src, DatabaseEntityHandler $relationHandler,
|
|
|
|
int &$relIndex = 1, bool $recursive = false, string $relationColumnPrefix = "") {
|
|
|
|
|
2023-01-12 20:55:32 +01:00
|
|
|
// TODO: fix recursion here...
|
|
|
|
if ($src === $relationHandler && $recursive) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-06-20 19:52:31 +02:00
|
|
|
$columns = $src->getColumns();
|
|
|
|
|
|
|
|
$foreignColumn = $columns[$propertyName];
|
|
|
|
$foreignColumnName = $foreignColumn->getName();
|
|
|
|
$referencedTable = $relationHandler->getTableName();
|
|
|
|
$isNullable = !$foreignColumn->notNull();
|
|
|
|
$alias = "t$relIndex"; // t1, t2, t3, ...
|
|
|
|
$relIndex++;
|
|
|
|
|
|
|
|
if ($isNullable) {
|
2022-11-26 23:57:28 +01:00
|
|
|
$this->leftJoin($referencedTable, "$tableName.$foreignColumnName", "$alias.id", $alias);
|
2022-06-20 19:52:31 +02:00
|
|
|
} else {
|
2022-11-26 23:57:28 +01:00
|
|
|
$this->innerJoin($referencedTable, "$tableName.$foreignColumnName", "$alias.id", $alias);
|
2022-06-20 19:52:31 +02:00
|
|
|
}
|
|
|
|
|
2023-01-07 15:34:05 +01:00
|
|
|
$relationColumnPrefix .= DatabaseEntityHandler::buildColumnName($propertyName) . "_";
|
2022-06-20 19:52:31 +02:00
|
|
|
$recursiveRelations = $relationHandler->getRelations();
|
|
|
|
foreach ($relationHandler->getColumns() as $relPropertyName => $relColumn) {
|
|
|
|
$relColumnName = $relColumn->getName();
|
|
|
|
if (!isset($recursiveRelations[$relPropertyName]) || $recursive) {
|
2022-11-26 23:57:28 +01:00
|
|
|
$this->addValue("$alias.$relColumnName as $relationColumnPrefix$relColumnName");
|
2022-06-20 19:52:31 +02:00
|
|
|
if (isset($recursiveRelations[$relPropertyName]) && $recursive) {
|
|
|
|
$this->fetchRelation($relPropertyName, $alias, $relationHandler, $recursiveRelations[$relPropertyName], $relIndex, $recursive, $relationColumnPrefix);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public function execute(): DatabaseEntity|array|null {
|
2022-11-19 01:15:34 +01:00
|
|
|
|
|
|
|
if ($this->logVerbose) {
|
|
|
|
$params = [];
|
2022-11-26 23:57:28 +01:00
|
|
|
$query = $this->build($params);
|
2022-11-19 01:15:34 +01:00
|
|
|
$this->logger->debug("QUERY: $query\nARGS: " . print_r($params, true));
|
|
|
|
}
|
|
|
|
|
2022-11-26 23:57:28 +01:00
|
|
|
$res = parent::execute();
|
2022-06-20 19:52:31 +02:00
|
|
|
if ($res === null || $res === false) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($this->resultType === SQL::FETCH_ALL) {
|
|
|
|
$entities = [];
|
|
|
|
foreach ($res as $row) {
|
2023-01-15 00:32:17 +01:00
|
|
|
$entity = $this->handler->entityFromRow($row, $this->additionalColumns, $this->fetchSubEntities);
|
2022-06-20 19:52:31 +02:00
|
|
|
if ($entity) {
|
|
|
|
$entities[$entity->getId()] = $entity;
|
|
|
|
}
|
|
|
|
}
|
2022-11-20 17:13:53 +01:00
|
|
|
|
|
|
|
if ($this->fetchSubEntities !== self::FETCH_NONE) {
|
2023-01-15 00:32:17 +01:00
|
|
|
$this->handler->fetchNMRelations($entities, $this->fetchSubEntities);
|
2022-11-20 17:13:53 +01:00
|
|
|
}
|
|
|
|
|
2022-06-20 19:52:31 +02:00
|
|
|
return $entities;
|
|
|
|
} else if ($this->resultType === SQL::FETCH_ONE) {
|
2023-01-15 00:32:17 +01:00
|
|
|
$entity = $this->handler->entityFromRow($res, $this->additionalColumns, $this->fetchSubEntities);
|
2022-11-20 17:13:53 +01:00
|
|
|
if ($entity instanceof DatabaseEntity && $this->fetchSubEntities !== self::FETCH_NONE) {
|
2023-01-15 00:32:17 +01:00
|
|
|
$this->handler->fetchNMRelations([$entity->getId() => $entity], $this->fetchSubEntities);
|
2022-11-20 17:13:53 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return $entity;
|
2022-06-20 19:52:31 +02:00
|
|
|
} else {
|
|
|
|
$this->handler->getLogger()->error("Invalid result type for query builder, must be FETCH_ALL or FETCH_ONE");
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
2022-11-27 12:33:27 +01:00
|
|
|
|
|
|
|
public function executeSQL() {
|
|
|
|
return parent::execute();
|
|
|
|
}
|
2022-06-20 19:52:31 +02:00
|
|
|
}
|