getSQL(), ...$handler->getColumnNames()); $this->handler = $handler; $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; if ($this->resultType === SQL::FETCH_ONE) { $this->first(); } } 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 { 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; } 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(); $this->fetchSubEntities = ($recursive ? self::FETCH_RECURSIVE : self::FETCH_DIRECT); $relIndex = 1; foreach ($this->handler->getRelations() as $propertyName => $relationHandler) { if ($this->handler !== $relationHandler || !$recursive) { $this->fetchRelation($propertyName, $this->handler->getTableName(), $this->handler, $relationHandler, $relIndex, $recursive); } } return $this; } private function fetchRelation(string $propertyName, string $tableName, DatabaseEntityHandler $src, DatabaseEntityHandler $relationHandler, int &$relIndex = 1, bool $recursive = false, string $relationColumnPrefix = "") { // TODO: fix recursion here... if ($src === $relationHandler && $recursive) { return; } $columns = $src->getColumns(); $foreignColumn = $columns[$propertyName]; $foreignColumnName = $foreignColumn->getName(); $referencedTable = $relationHandler->getTableName(); $isNullable = !$foreignColumn->notNull(); $alias = "t$relIndex"; // t1, t2, t3, ... $relIndex++; if ($isNullable) { $this->leftJoin($referencedTable, "$tableName.$foreignColumnName", "$alias.id", $alias); } else { $this->innerJoin($referencedTable, "$tableName.$foreignColumnName", "$alias.id", $alias); } $relationColumnPrefix .= DatabaseEntityHandler::buildColumnName($propertyName) . "_"; $recursiveRelations = $relationHandler->getRelations(); foreach ($relationHandler->getColumns() as $relPropertyName => $relColumn) { $relColumnName = $relColumn->getName(); if (!isset($recursiveRelations[$relPropertyName]) || $recursive) { $this->addValue("$alias.$relColumnName as $relationColumnPrefix$relColumnName"); if (isset($recursiveRelations[$relPropertyName]) && $recursive) { $this->fetchRelation($relPropertyName, $alias, $relationHandler, $recursiveRelations[$relPropertyName], $relIndex, $recursive, $relationColumnPrefix); } } } } public function execute(): DatabaseEntity|array|null|false { if ($this->logVerbose) { $params = []; $query = $this->build($params); $this->logger->debug("QUERY: $query\nARGS: " . print_r($params, true)); } $res = parent::execute(); if ($res === null || $res === false) { return $res; } if ($this->resultType === SQL::FETCH_ALL) { $entities = []; foreach ($res as $row) { $entity = $this->handler->entityFromRow($row, $this->additionalColumns, $this->fetchSubEntities); if ($entity) { $entities[$entity->getId()] = $entity; } } if ($this->fetchSubEntities !== self::FETCH_NONE) { $this->handler->fetchNMRelations($entities, $this->fetchSubEntities); } return $entities; } else if ($this->resultType === SQL::FETCH_ONE) { $entity = $this->handler->entityFromRow($res, $this->additionalColumns, $this->fetchSubEntities); if ($entity instanceof DatabaseEntity && $this->fetchSubEntities !== self::FETCH_NONE) { $this->handler->fetchNMRelations([$entity->getId() => $entity], $this->fetchSubEntities); } return $entity; } else { $this->handler->getLogger()->error("Invalid result type for query builder, must be FETCH_ALL or FETCH_ONE"); return null; } } public function executeSQL() { return parent::execute(); } }