implement FindById, move to proper type alanysis on repository return types

master
Josha von Gizycki 1 week ago
parent 79c0272cec
commit 7783b245df

@ -15,6 +15,7 @@ use Kartierung\Repository\ResolutionStrategy\ResolutionStrategyFactory;
use ReflectionClass;
use ReflectionIntersectionType;
use ReflectionMethod;
use ReflectionNamedType;
use ReflectionUnionType;
/**
@ -54,23 +55,25 @@ readonly class RepositoryAnalyzer
$methods = [];
foreach ($refMethods as $refMethod) {
$query = $this->queryString($refMethod);
$returnType = $this->returnType($refMethod);
list($returnType, $returnsNullable) = $this->returnType($refMethod);
$listType = $this->listType($refMethod);
$params = $this->parameters($refMethod);
$name = $refMethod->name;
$resolutionStrategy = $this->methodValidator->forRepositoryMethod(
$refClass->name,
$name,
$query,
$returnType,
$listType,
$params
repName: $refClass->name,
methodName: $name,
query: $query,
returnType: $returnType,
returnsNullable: $returnsNullable,
listType: $listType,
params: $params
);
$methods[$refMethod->name] = new RepositoryMethod(
query: $query,
returnType: $returnType,
returnsNullable: $returnsNullable,
returnListType: $listType,
name: $name,
parameters: $params,
@ -101,9 +104,9 @@ readonly class RepositoryAnalyzer
/**
* @param ReflectionMethod $refMethod
* @return class-string<object>|string
* @return array{class-string<object>|string, bool}
*/
private function returnType(ReflectionMethod $refMethod): string
private function returnType(ReflectionMethod $refMethod): array
{
$returnType = $refMethod->getReturnType();
@ -116,8 +119,11 @@ readonly class RepositoryAnalyzer
);
}
/** @var class-string<object>|string */
return $returnType->__toString();
/** @var ReflectionNamedType $returnType */
/** @var class-string<object>|string $typeStr */
$typeStr = $returnType->getName();
return [$typeStr, $returnType->allowsNull()];
}
/**

@ -6,6 +6,7 @@ namespace Kartierung\Analyze\Result;
use Kartierung\Repository\ResolutionStrategy\ResolutionStrategy;
use Kartierung\Sql\LazyQuery;
use phpDocumentor\Reflection\Types\Boolean;
readonly class RepositoryMethod
{
@ -16,17 +17,13 @@ readonly class RepositoryMethod
public function __construct(
public ?string $query,
public string $returnType,
public bool $returnsNullable,
public ?string $returnListType,
public string $name,
public array $parameters,
public ResolutionStrategy $resolutionStrategy
) {}
public function returnsNullable(): bool
{
return str_starts_with($this->returnType, '?');
}
/**
* @param array<string, mixed> $parameters
*/

@ -4,17 +4,51 @@ declare(strict_types=1);
namespace Kartierung\Repository\ResolutionStrategy;
use Kartierung\Analyze\EntityAnalyzer;
use Kartierung\Analyze\Result\EntityField;
use Kartierung\Analyze\Result\RepositoryMethod;
use Kartierung\Sql\DataToEntityMapper;
use Kartierung\Sql\LazyQuery;
use PDO;
use PDOStatement;
class FindById implements ResolutionStrategy
readonly class FindById implements ResolutionStrategy
{
public function createQuery(RepositoryMethod $method, array $parameters): LazyQuery
{
return new LazyQuery(
function (PDO $pdo) {
static function (PDO $pdo) use ($method, $parameters) {
/** @var class-string<object> $type */
$type = $method->returnType;
$entityResult = (new EntityAnalyzer($type))->analyze();
$mapper = new DataToEntityMapper($entityResult);
$fields = implode(
', ',
array_map(
static fn(EntityField $e) => $e->columnName, $entityResult->fields
)
);
$idField = $entityResult->idField->name;
$sql = "
SELECT $fields
FROM {$entityResult->tableName}
WHERE $idField = ?
";
/** @var PDOStatement $stmt */
$stmt = $pdo->prepare($sql);
$stmt->execute([array_first($parameters)]);
/** @var array<string, mixed>|false $row */
$row = $stmt->fetch(mode: PDO::FETCH_ASSOC);
if($row) {
return $mapper->toEntity($row);
}
return null;
}
);
}

@ -17,12 +17,12 @@ class ResolutionStrategyFactory
string $methodName,
?string $query,
string $returnType,
bool $returnsNullable,
?string $listType,
array $params
): ResolutionStrategy
{
$oneParam = count($params) === 1;
$returnsNullable = str_starts_with($returnType, '?');
return match (true) {
$query !== null => new UserDefinedQuery(),

@ -130,7 +130,7 @@ class RepositoryAnalyzerTest extends TestCase
// Then
$method = $result->methods['findById'];
$this->assertEquals('?Kartierung\FullEntity', $method->returnType);
$this->assertTrue($method->returnsNullable());
$this->assertEquals('Kartierung\FullEntity', $method->returnType);
$this->assertTrue($method->returnsNullable);
}
}

@ -34,6 +34,7 @@ class FindAllTest extends SqliteBaseCase
$method = new RepositoryMethod(
query: '',
returnType: '',
returnsNullable: true,
returnListType: SimpleEntity::class,
name: '',
parameters: [],

@ -0,0 +1,101 @@
<?php
declare(strict_types=1);
namespace Kartierung\Repository\ResolutionStrategy;
use Kartierung\Analyze\Result\RepositoryMethod;
use PHPUnit\Framework\Attributes\Group;
class FindByIdTest extends SqliteBaseCase
{
protected function setUp(): void
{
parent::setUp();
$this->getPdo()->exec(
"
CREATE TABLE SimpleEntity (
stringcol VARCHAR(250),
intcol INT
);
INSERT INTO SimpleEntity(stringcol, intcol)
VALUES ('dings', 1),
('bumms', 2),
('foobar', 3);
"
);
}
#[Group('integration')]
public function testSelectsFirstEntry(): void
{
// Given
$method = new RepositoryMethod(
query: '',
returnType: SimpleEntity::class,
returnsNullable: true,
returnListType: '',
name: '',
parameters: [],
resolutionStrategy: new FindById()
);
$query = $method->createQuery([1]);
// When
$result = $query->execute($this->getPdo());
// Then
$this->assertEquals(
new SimpleEntity(1, 'dings'),
$result
);
}
#[Group('integration')]
public function testSelectsThirdEntry(): void
{
// Given
$method = new RepositoryMethod(
query: '',
returnType: SimpleEntity::class,
returnsNullable: true,
returnListType: '',
name: '',
parameters: [],
resolutionStrategy: new FindById()
);
$query = $method->createQuery([3]);
// When
$result = $query->execute($this->getPdo());
// Then
$this->assertEquals(
new SimpleEntity(3, 'foobar'),
$result
);
}
#[Group('integration')]
public function testSelectsNothingMatching(): void
{
// Given
$method = new RepositoryMethod(
query: '',
returnType: SimpleEntity::class,
returnsNullable: true,
returnListType: '',
name: '',
parameters: [],
resolutionStrategy: new FindById()
);
$query = $method->createQuery([4]);
// When
$result = $query->execute($this->getPdo());
// Then
$this->assertNull($result);
}
}

@ -13,11 +13,11 @@ class ResolutionStrategyFactoryTest extends TestCase
public static function validFunctionsProvider(): array
{
return [
['R', 'save', null, '', null, [1], SaveEntity::class],
['R', 'delete', null, 'int', null, [1], DeleteEntity::class],
['R', 'findById', null, '?int', null, [1], FindById::class],
['R', 'findAll', null, 'array', FullEntity::class, [], FindAll::class],
['R', 'something', 'SELECT', 'int', null, [], UserDefinedQuery::class]
['R', 'save', null, '', false, null, [1], SaveEntity::class],
['R', 'delete', null, 'int', false, null, [1], DeleteEntity::class],
['R', 'findById', null, 'int', true, null, [1], FindById::class],
['R', 'findAll', null, 'array', false, FullEntity::class, [], FindAll::class],
['R', 'something', 'SELECT', 'int', false, null, [], UserDefinedQuery::class]
];
}
@ -27,6 +27,7 @@ class ResolutionStrategyFactoryTest extends TestCase
string $name,
?string $query,
string $returnType,
bool $returnsNullable,
?string $listType,
array $params,
string $strategyClass
@ -38,6 +39,7 @@ class ResolutionStrategyFactoryTest extends TestCase
methodName: $name,
query: $query,
returnType: $returnType,
returnsNullable: $returnsNullable,
listType: $listType,
params: $params
);
@ -69,12 +71,13 @@ class ResolutionStrategyFactoryTest extends TestCase
{
// When
$function = (new ResolutionStrategyFactory())->forRepositoryMethod(
$repName,
$name,
$query,
$returnType,
$listType,
$params
repName: $repName,
methodName: $name,
query: $query,
returnType: $returnType,
returnsNullable: false,
listType: $listType,
params: $params
);
// Then

@ -13,12 +13,4 @@ class SimpleEntity
public int $intcol,
public string $stringcol
) {}
public function withStringCol(string $value): self
{
$new = new self();
$new->stringcol = $value;
return $new;
}
}

Loading…
Cancel
Save