first draft for child entities

recursion check missing
master
Josha von Gizycki 2 weeks ago
parent b10dfdf411
commit 6537a2db81

@ -5,20 +5,19 @@ declare(strict_types=1);
namespace Kartierung\Analyze;
use Kartierung\Analyze\Exception\InvalidEntity;
use Kartierung\Analyze\Exception\InvalidRepository;
use Kartierung\Analyze\Result\ClassType;
use Kartierung\Analyze\Result\EntityField;
use Kartierung\Analyze\Result\EntityResult;
use Kartierung\Analyze\Result\FieldAccess;
use Kartierung\Analyze\Result\PrimitiveType;
use Kartierung\Analyze\Result\Type\ArrayType;
use Kartierung\Analyze\Result\Type\ClassType;
use Kartierung\Analyze\Result\Type\PrimitiveType;
use Kartierung\Attribute\Column;
use Kartierung\Attribute\Id;
use Kartierung\Attribute\ListOf;
use Kartierung\Attribute\Table;
use ReflectionClass;
use ReflectionIntersectionType;
use ReflectionNamedType;
use ReflectionParameter;
use ReflectionUnionType;
/**
* @template E of object
@ -34,6 +33,7 @@ readonly class EntityAnalyzer
/**
* @return EntityResult<E>
* @noinspection PhpDocMissingThrowsInspection
*/
public function analyze(): EntityResult
{
@ -102,9 +102,6 @@ readonly class EntityAnalyzer
return $idFields[array_key_first($idFields)];
}
/**
* @return EntityField
*/
private function fieldFromParameter(ReflectionParameter $param): EntityField
{
$attrs = $param->getAttributes(Column::class);
@ -130,7 +127,7 @@ readonly class EntityAnalyzer
);
}
private function parameterType(ReflectionParameter $param): PrimitiveType|ClassType
private function parameterType(ReflectionParameter $param): PrimitiveType|ClassType|ArrayType
{
if (!$param->hasType()) {
throw new InvalidEntity(
@ -140,9 +137,9 @@ readonly class EntityAnalyzer
$type = $param->getType();
if (!$type instanceof ReflectionNamedType) {
throw new InvalidRepository(
throw new InvalidEntity(
"Entity parameter $this->entity::$param->name has an invalid return type. "
. 'Simple type expected. Unions, Intersections or no type are not simple.'
. "Simple type expected. Unions, Intersections or no type are not simple."
);
}
@ -150,6 +147,23 @@ readonly class EntityAnalyzer
/** @var class-string<object> $classType */
$classType = $type->getName();
if ($classType === "array") {
$listAttr = $param->getAttributes(ListOf::class);
if (empty($listAttr) || count($listAttr) > 1) {
throw new InvalidEntity(
"Entity parameter $this->entity::$param->name declares its typr as array. "
. "Exactly one #[ListOf(...)] attribute expected."
);
}
/** @var ListOf $listAttrInstance */
$listAttrInstance = $listAttr[0]->newInstance();
return new ArrayType(
(new EntityAnalyzer($listAttrInstance->entitiyFqcn))->analyze()
);
}
return match ($type->getName()) {
"string" => PrimitiveType::STRING,
"bool" => PrimitiveType::BOOLEAN,
@ -161,7 +175,7 @@ readonly class EntityAnalyzer
/**
* @param ReflectionClass<E> $refClass
* @return FieldAccess
* @noinspection PhpDocMissingThrowsInspection
*/
private function readAccess(ReflectionClass $refClass, ReflectionParameter $param): FieldAccess
{

@ -9,7 +9,7 @@ use Kartierung\Analyze\Result\ParameterFunction;
use Kartierung\Analyze\Result\RepositoryMethod;
use Kartierung\Analyze\Result\RepositoryMethodParameter;
use Kartierung\Analyze\Result\RepositoryResult;
use Kartierung\Attribute\ListResultOf;
use Kartierung\Attribute\ListOf;
use Kartierung\Attribute\Query;
use Kartierung\Repository\ResolutionStrategy\ResolutionStrategyFactory;
use ReflectionClass;
@ -126,11 +126,11 @@ readonly class RepositoryAnalyzer
*/
private function listType(ReflectionMethod $refMethod): ?string
{
$listResultOfAttr = $refMethod->getAttributes(ListResultOf::class);
$listResultOfAttr = $refMethod->getAttributes(ListOf::class);
$listType = null;
if (count($listResultOfAttr) === 1) {
/** @var ListResultOf $inst */
/** @var ListOf $inst */
$inst = $listResultOfAttr[0]->newInstance();
$listType = $inst->entitiyFqcn;

@ -4,11 +4,15 @@ declare(strict_types=1);
namespace Kartierung\Analyze\Result;
use Kartierung\Analyze\Result\Type\ArrayType;
use Kartierung\Analyze\Result\Type\ClassType;
use Kartierung\Analyze\Result\Type\PrimitiveType;
readonly class EntityField
{
public function __construct(
public string $name,
public PrimitiveType|ClassType $type,
public PrimitiveType|ClassType|ArrayType $type,
public string $columnName,
public bool $isIdField,
public FieldAccess $readAccess,

@ -0,0 +1,18 @@
<?php
declare(strict_types=1);
namespace Kartierung\Analyze\Result\Type;
use Kartierung\Analyze\Result\EntityResult;
use Kartierung\Attribute\ListOf;
readonly class ArrayType
{
/**
* @param EntityResult<object> $entity
*/
public function __construct(
public EntityResult $entity
) {}
}

@ -2,7 +2,7 @@
declare(strict_types=1);
namespace Kartierung\Analyze\Result;
namespace Kartierung\Analyze\Result\Type;
readonly class ClassType
{

@ -2,7 +2,7 @@
declare(strict_types=1);
namespace Kartierung\Analyze\Result;
namespace Kartierung\Analyze\Result\Type;
enum PrimitiveType
{

@ -6,8 +6,8 @@ namespace Kartierung\Attribute;
use Attribute;
#[Attribute(Attribute::TARGET_METHOD)]
readonly class ListResultOf
#[Attribute(Attribute::TARGET_METHOD | Attribute::TARGET_PARAMETER)]
readonly class ListOf
{
/**
* @param class-string $entitiyFqcn

@ -6,8 +6,10 @@ namespace Kartierung\Analyze;
use Kartierung\Analyze\Exception\InvalidEntity;
use Kartierung\Analyze\Result\EntityField;
use Kartierung\Analyze\Result\EntityResult;
use Kartierung\Analyze\Result\FieldAccess;
use Kartierung\Analyze\Result\PrimitiveType;
use Kartierung\Analyze\Result\Type\ArrayType;
use Kartierung\Analyze\Result\Type\PrimitiveType;
use Kartierung\FullEntity;
use Kartierung\PropertyPropagatedEntity;
use PHPUnit\Framework\TestCase;
@ -114,4 +116,56 @@ class EntityAnalyzerTest extends TestCase
// Then
$this->assertEquals("EntityWithoutTableAttribute", $result->tableName);
}
public function testArrayOfChildEntities(): void
{
// Given
$entity = EntityWithListOfFullEntities::class;
// When
$result = (new EntityAnalyzer($entity))->analyze();
// Then
$this->assertEquals(
new EntityField(
name: 'id',
type: PrimitiveType::INTEGER,
columnName: 'id',
isIdField: true,
readAccess: FieldAccess::PUBLIC
),
$result->fields[0]
);
$this->assertEquals(
new EntityField(
name: 'children',
type: new ArrayType(
new EntityResult(
classFqcn: IdOnlyEntity::class,
tableName: 'IdOnlyEntity',
fields: [
new EntityField(
name: 'id',
type: PrimitiveType::INTEGER,
columnName: 'id',
isIdField: true,
readAccess: FieldAccess::PUBLIC
)
],
idField: new EntityField(
name: 'id',
type: PrimitiveType::INTEGER,
columnName: 'id',
isIdField: true,
readAccess: FieldAccess::PUBLIC
)
)
),
columnName: 'children',
isIdField: false,
readAccess: FieldAccess::PUBLIC
),
$result->fields[1]
);
}
}

@ -0,0 +1,18 @@
<?php
declare(strict_types=1);
namespace Kartierung\Analyze;
use Kartierung\Attribute\Id;
use Kartierung\Attribute\ListOf;
class EntityWithListOfFullEntities
{
public function __construct(
#[Id]
public int $id,
#[ListOf(IdOnlyEntity::class)]
public array $children
) {}
}

@ -0,0 +1,15 @@
<?php
declare(strict_types=1);
namespace Kartierung\Analyze;
use Kartierung\Attribute\Id;
class IdOnlyEntity
{
public function __construct(
#[Id]
public int $id
) {}
}

@ -4,10 +4,10 @@ declare(strict_types=1);
namespace Kartierung\Analyze;
use Kartierung\Attribute\ListResultOf;
use Kartierung\Attribute\ListOf;
interface InvalidListResultOfRepository
{
#[ListResultOf('void')]
#[ListOf('void')]
public function invalidListResultOf(): array;
}

@ -4,7 +4,7 @@ declare(strict_types=1);
namespace Kartierung\Analyze;
use Kartierung\Attribute\ListResultOf;
use Kartierung\Attribute\ListOf;
use Kartierung\Attribute\Query;
use Kartierung\FullEntity;
@ -14,7 +14,7 @@ interface Repository
public function fetchWithQuery(): FullEntity;
#[Query("SELECT something")]
#[ListResultOf(FullEntity::class)]
#[ListOf(FullEntity::class)]
public function fetchArray(): array;
#[Query("SELECT something")]

@ -7,7 +7,7 @@ namespace Kartierung\Sql;
use Kartierung\Analyze\Result\EntityField;
use Kartierung\Analyze\Result\EntityResult;
use Kartierung\Analyze\Result\FieldAccess;
use Kartierung\Analyze\Result\PrimitiveType;
use Kartierung\Analyze\Result\Type\PrimitiveType;
use PHPUnit\Framework\TestCase;
class DataToEntityMapperTest extends TestCase

Loading…
Cancel
Save