Tests + Bugfix

This commit is contained in:
Roman 2022-06-17 23:29:24 +02:00
parent fc5c279cd4
commit 9ecbb2775d
3 changed files with 148 additions and 9 deletions

@ -8,10 +8,9 @@ use Driver\SQL\SQL;
abstract class DatabaseEntity { abstract class DatabaseEntity {
private static array $handlers = []; private static array $handlers = [];
private ?int $id; private ?int $id = null;
public function __construct() { public function __construct() {
$this->id = null;
} }
public static function find(SQL $sql, int $id): ?DatabaseEntity { public static function find(SQL $sql, int $id): ?DatabaseEntity {
@ -19,7 +18,7 @@ abstract class DatabaseEntity {
return $handler->fetchOne($id); return $handler->fetchOne($id);
} }
public static function findAll(SQL $sql, ?Condition $condition): ?array { public static function findAll(SQL $sql, ?Condition $condition = null): ?array {
$handler = self::getHandler($sql); $handler = self::getHandler($sql);
return $handler->fetchMultiple($condition); return $handler->fetchMultiple($condition);
} }
@ -43,7 +42,12 @@ abstract class DatabaseEntity {
return false; return false;
} }
return $handler->delete($this->id); if ($handler->delete($this->id)) {
$this->id = null;
return true;
}
return false;
} }
public static function getHandler(SQL $sql, $obj_or_class = null): DatabaseEntityHandler { public static function getHandler(SQL $sql, $obj_or_class = null): DatabaseEntityHandler {

@ -21,9 +21,11 @@ use PHPUnit\Util\Exception;
class DatabaseEntityHandler { class DatabaseEntityHandler {
private \ReflectionClass $entityClass; private \ReflectionClass $entityClass;
private static \ReflectionProperty $ID_FIELD;
private string $tableName; private string $tableName;
private array $columns; private array $columns;
private array $properties; private array $properties;
private array $relations;
private SQL $sql; private SQL $sql;
private Logger $logger; private Logger $logger;
@ -42,6 +44,10 @@ class DatabaseEntityHandler {
$this->properties = []; $this->properties = [];
$this->relations = []; $this->relations = [];
if (!isset(self::$ID_FIELD)) {
self::$ID_FIELD = (new \ReflectionClass(DatabaseEntity::class))->getProperty("id");
}
foreach ($this->entityClass->getProperties() as $property) { foreach ($this->entityClass->getProperties() as $property) {
$propertyName = $property->getName(); $propertyName = $property->getName();
$propertyType = $property->getType(); $propertyType = $property->getType();
@ -98,12 +104,26 @@ class DatabaseEntityHandler {
return $this->logger; return $this->logger;
} }
public function getTableName(): string {
return $this->tableName;
}
private function entityFromRow(array $row): DatabaseEntity { private function entityFromRow(array $row): DatabaseEntity {
try { try {
$entity = $this->entityClass->newInstanceWithoutConstructor(); $entity = $this->entityClass->newInstanceWithoutConstructor();
foreach ($this->columns as $propertyName => $column) { foreach ($this->columns as $propertyName => $column) {
$this->properties[$propertyName]->setValue($entity, $row[$column]); $value = $row[$column->getName()];
$property = $this->properties[$propertyName];
if ($property->getType()->getName() === "DateTime") {
$value = new \DateTime($value);
} }
$property->setValue($entity, $value);
}
self::$ID_FIELD->setAccessible(true);
self::$ID_FIELD->setValue($entity, $row["id"]);
return $entity; return $entity;
} catch (\Exception $exception) { } catch (\Exception $exception) {
$this->logger->error("Error creating entity from database row: " . $exception->getMessage()); $this->logger->error("Error creating entity from database row: " . $exception->getMessage());
@ -112,7 +132,7 @@ class DatabaseEntityHandler {
} }
public function fetchOne(int $id): ?DatabaseEntity { public function fetchOne(int $id): ?DatabaseEntity {
$res = $this->sql->select(...array_keys($this->columns)) $res = $this->sql->select("id", ...array_keys($this->columns))
->from($this->tableName) ->from($this->tableName)
->where(new Compare("id", $id)) ->where(new Compare("id", $id))
->first() ->first()
@ -126,7 +146,7 @@ class DatabaseEntityHandler {
} }
public function fetchMultiple(?Condition $condition = null): ?array { public function fetchMultiple(?Condition $condition = null): ?array {
$query = $this->sql->select(...array_keys($this->columns)) $query = $this->sql->select("id", ...array_keys($this->columns))
->from($this->tableName); ->from($this->tableName);
if ($condition) { if ($condition) {
@ -175,7 +195,17 @@ class DatabaseEntityHandler {
foreach ($this->columns as $propertyName => $column) { foreach ($this->columns as $propertyName => $column) {
$columns[] = $column->getName(); $columns[] = $column->getName();
$row[] = $this->properties[$propertyName]->getValue($entity); $property = $this->properties[$propertyName];
if ($property->isInitialized($entity)) {
$value = $property->getValue($entity);
} else if (!$this->columns[$propertyName]->notNull()) {
$value = null;
} else {
$this->logger->error("Cannot insert entity: property '$propertyName' was not initialized yet.");
return false;
}
$row[] = $value;
} }
$res = $this->sql->insert($this->tableName, $columns) $res = $this->sql->insert($this->tableName, $columns)
@ -194,7 +224,16 @@ class DatabaseEntityHandler {
foreach ($this->columns as $propertyName => $column) { foreach ($this->columns as $propertyName => $column) {
$columnName = $column->getName(); $columnName = $column->getName();
$value = $this->properties[$propertyName]->getValue($entity); $property = $this->properties[$propertyName];
if ($property->isInitialized($entity)) {
$value = $property->getValue($entity);
} else if (!$this->columns[$propertyName]->notNull()) {
$value = null;
} else {
$this->logger->error("Cannot update entity: property '$propertyName' was not initialized yet.");
return false;
}
$query->set($columnName, $value); $query->set($columnName, $value);
} }
@ -210,4 +249,8 @@ class DatabaseEntityHandler {
$this->logger->error($message); $this->logger->error($message);
throw new Exception($message); throw new Exception($message);
} }
private function getPropertyValue() {
}
} }

@ -0,0 +1,92 @@
<?php
// TODO: disable logging for tests
class DatabaseEntityTest extends \PHPUnit\Framework\TestCase {
static \Objects\User $USER;
static \Driver\SQL\SQL $SQL;
static \Objects\DatabaseEntity\DatabaseEntityHandler $HANDLER;
public static function setUpBeforeClass(): void {
parent::setUpBeforeClass();
self::$USER = new Objects\User(new \Configuration\Configuration());
self::$SQL = self::$USER->getSQL();
self::$HANDLER = TestEntity::getHandler(self::$SQL);
}
public function testCreateTable() {
$this->assertInstanceOf(\Driver\SQL\Query\CreateTable::class, self::$HANDLER->getTableQuery());
$this->assertTrue(self::$HANDLER->createTable());
}
public function testInsertEntity() {
$entity = new TestEntity();
$entity->a = 1;
$entity->b = "test";
$entity->c = true;
$entity->d = 1.23;
$entity->e = new DateTime();
$entity->f = null;
// insert
$this->assertTrue($entity->save(self::$SQL));
$entityId = $entity->getId();
$this->assertNotNull($entityId);
// fetch
$entity2 = TestEntity::find(self::$SQL, $entityId);
$this->assertNotNull($entity2);
$this->assertEquals($entity2->a, $entity->a);
$this->assertEquals($entity2->b, $entity->b);
$this->assertEquals($entity2->c, $entity->c);
$this->assertEquals($entity2->d, $entity->d);
$this->assertNotNull($entity2->e);
$this->assertEquals(
$entity2->e->format(\Api\Parameter\Parameter::DATE_TIME_FORMAT),
$entity->e->format(\Api\Parameter\Parameter::DATE_TIME_FORMAT)
);
$this->assertNull($entity2->f);
// update
$entity2->a = 100;
$this->assertTrue($entity2->save(self::$SQL));
$this->assertEquals($entity2->getId(), $entityId);
// re-fetch
$this->assertEquals($entity2->a, TestEntity::find(self::$SQL, $entityId)->a);
// check table contents
$allEntities = TestEntity::findAll(self::$SQL);
$this->assertIsArray($allEntities);
$this->assertCount(1, $allEntities);
$this->assertEquals($entityId, $allEntities[0]->getId());
// delete
$this->assertTrue($entity->delete(self::$SQL));
$this->assertNull($entity->getId());
// check table contents
$allEntities = TestEntity::findAll(self::$SQL);
$this->assertIsArray($allEntities);
$this->assertCount(0, $allEntities);
}
public function testInsertFail() {
$entity = new TestEntity();
$this->assertFalse($entity->save(self::$SQL));
}
public function testDropTable() {
$this->assertTrue(self::$SQL->drop(self::$HANDLER->getTableName())->execute());
}
}
class TestEntity extends \Objects\DatabaseEntity\DatabaseEntity {
public int $a;
public string $b;
public bool $c;
public float $d;
public \DateTime $e;
public ?int $f;
}