diff --git a/src/Analyze/Result/EntityResult.php b/src/Analyze/Result/EntityResult.php index 4f59c36..8e52aa7 100644 --- a/src/Analyze/Result/EntityResult.php +++ b/src/Analyze/Result/EntityResult.php @@ -21,4 +21,12 @@ readonly class EntityResult public array $fields, public EntityField $idField ) {} + + /** + * @return list + */ + public function fieldsWithoutId(): array + { + return array_filter($this->fields, static fn(EntityField $field) => !$field->isIdField); + } } diff --git a/src/Repository/ResolutionStrategy/Execution/UpdateEntity.php b/src/Repository/ResolutionStrategy/Execution/UpdateEntity.php new file mode 100644 index 0000000..f9010d7 --- /dev/null +++ b/src/Repository/ResolutionStrategy/Execution/UpdateEntity.php @@ -0,0 +1,66 @@ + $entityResult + * @param array $data + * @return object + */ + public function update(EntityResult $entityResult, array $data): object + { + $pairs = implode(', ', array_map( + static fn(EntityField $field) => "$field->columnName = ?", + $entityResult->fieldsWithoutId() + )); + $idWhere = $entityResult->idField->columnName . ' = ?'; + + $params = array_map( + static fn(EntityField $field) => $data[$field->columnName] ?? null, + $entityResult->fieldsWithoutId() + ); + $id = $data[$entityResult->idField->columnName] ?? null; + $params[] = $id; + // reindex keys for pdo + $params = array_values($params); + + $sql = "UPDATE $entityResult->tableName SET $pairs WHERE $idWhere"; + $prepStmt = $this->pdo->prepare($sql); + $success = $prepStmt->execute($params); + + if (!$success) { + throw new InvalidCall( + "Database reports failed updated statement." + ); + } + + $rows = $prepStmt->rowCount(); + if ($rows !== 1) { + throw new InvalidCall( + "Database returns $rows affected. Exactly 1 expected." + ); + } + + $entity = (new SelectEntityById($this->pdo))->select($entityResult, $id); + if (!$entity) { + throw new InvalidCall( + "Entity of type $entityResult->classFqcn with id $id can not be selected." + ); + } + + return $entity; + } +} diff --git a/src/Repository/ResolutionStrategy/SaveEntity.php b/src/Repository/ResolutionStrategy/SaveEntity.php index fbd7993..e894d3f 100644 --- a/src/Repository/ResolutionStrategy/SaveEntity.php +++ b/src/Repository/ResolutionStrategy/SaveEntity.php @@ -10,6 +10,7 @@ use Kartierung\Analyze\Result\RepositoryMethod; use Kartierung\Analyze\Result\RepositoryMethodParameter; use Kartierung\Repository\InvalidCall; use Kartierung\Repository\ResolutionStrategy\Execution\InsertEntity; +use Kartierung\Repository\ResolutionStrategy\Execution\UpdateEntity; use Kartierung\Sql\LazyQuery; use PDO; @@ -18,7 +19,7 @@ class SaveEntity implements ResolutionStrategy public function createQuery(RepositoryMethod $method, array $parameters): LazyQuery { return new LazyQuery( - function (PDO $pdo) use ($method, $parameters): object|int { + function (PDO $pdo) use ($method, $parameters): object { /** @var RepositoryMethodParameter $firstDeclaredParam */ $firstDeclaredParam = array_first($method->parameters); /** @var object $firstParam */ @@ -39,7 +40,7 @@ class SaveEntity implements ResolutionStrategy $entityData = (new EntityToDataMapper())->byColumnName($entityResult, $firstParam); if ($this->hasIdValue($entityResult, $entityData)) { - return $this->update(); + return $this->update($pdo, $entityResult, $entityData); } return $this->insert($pdo, $entityResult, $entityData); @@ -47,9 +48,15 @@ class SaveEntity implements ResolutionStrategy ); } - private function update(): int + /** + * @param PDO $pdo + * @param EntityResult $entityResult + * @param array $data + * @return object + */ + private function update(PDO $pdo, EntityResult $entityResult, array $data): object { - return 0; + return (new UpdateEntity($pdo))->update($entityResult, $data); } /** diff --git a/tests/Repository/ResolutionStrategy/SaveEntityTest.php b/tests/Repository/ResolutionStrategy/SaveEntityTest.php index d6bb06e..7570322 100644 --- a/tests/Repository/ResolutionStrategy/SaveEntityTest.php +++ b/tests/Repository/ResolutionStrategy/SaveEntityTest.php @@ -7,6 +7,7 @@ namespace Kartierung\Repository\ResolutionStrategy; use Kartierung\Analyze\Result\ParameterFunction; use Kartierung\Analyze\Result\RepositoryMethod; use Kartierung\Analyze\Result\RepositoryMethodParameter; +use PDO; use PHPUnit\Framework\Attributes\Group; class SaveEntityTest extends SqliteBaseCase @@ -29,7 +30,7 @@ class SaveEntityTest extends SqliteBaseCase } #[Group('integration')] - public function testSelectsData(): void + public function testCreatesNewEntity(): void { // Given $strategy = new SaveEntity(); @@ -57,6 +58,51 @@ class SaveEntityTest extends SqliteBaseCase // Then $this->assertInstanceOf(SimpleEntity::class, $result); $this->assertNotNull($result->intcol); + $this->assertNotSame($result, $entity); + + $stmt = $this->getPdo()->query("SELECT COUNT(*) c FROM SimpleEntity"); + $row = $stmt->fetch(PDO::FETCH_ASSOC); + $this->assertEquals(3, $row['c'], 'Three rows expected'); + } + + #[Group('integration')] + public function testUpdatesEntity(): void + { + // Given + $strategy = new SaveEntity(); + $method = new RepositoryMethod( + query: '', + returnType: '', + returnsNullable: true, + returnListType: '', + name: '', + parameters: [ + new RepositoryMethodParameter( + name: '', + type: SimpleEntity::class, + function: ParameterFunction::STATEMENT_PARAMETER + ) + ], + resolutionStrategy: $strategy + ); + $entity = new SimpleEntity(1, 'foobar'); + $query = $method->createQuery([$entity]); + + // When + $result = $query->execute($this->getPdo()); + + // Then + $this->assertInstanceOf(SimpleEntity::class, $result); + $this->assertNotSame($result, $entity); + $this->assertEquals($entity, $result); + + $stmt = $this->getPdo()->query("SELECT COUNT(*) c FROM SimpleEntity"); + $row = $stmt->fetch(PDO::FETCH_ASSOC); + $this->assertEquals(2, $row['c'], 'Three rows expected'); + + $stmt = $this->getPdo()->query('SELECT stringcol c FROM SimpleEntity WHERE intcol = 1'); + $row = $stmt->fetch(PDO::FETCH_ASSOC); + $this->assertEquals('foobar', $row['c']); } }