more precise type analysis: add distinction between primitive and class types

master
Josha von Gizycki 3 weeks ago
parent f2047c3917
commit b10dfdf411

@ -14,21 +14,24 @@ return static function (DeptracConfig $config): void {
->paths('./src')
->excludeFiles('#.*test.*#')
->layers(
$analyzePublic = Layer::withName('AnalyzePublic')->collectors(
ClassLikeConfig::create('Kartierung\\Analyze\\Exception\\.+'),
ClassLikeConfig::create('Kartierung\\Analyze\\Result\\.+')
),
$analyze = Layer::withName('Analyze')->collectors(
BoolConfig::create(
must: [ClassLikeConfig::create('Kartierung\\Analyze\\.+')],
mustNot: [
LayerConfig::create($analyzePublic)
]
)
),
$attribute = Layer::withName('Attribute')->collectors(
ClassLikeConfig::create('Kartierung\\Attribute\\.*'),
),
$analyzePublic = Layer::withName('AnalyzePublic')
->collectors(
ClassLikeConfig::create('Kartierung\\Analyze\\Exception\\.+'),
ClassLikeConfig::create('Kartierung\\Analyze\\Result\\.+')
),
$analyze = Layer::withName('Analyze')
->collectors(
BoolConfig::create(
must: [ClassLikeConfig::create('Kartierung\\Analyze\\.+')],
mustNot: [
LayerConfig::create($analyzePublic)
]
)
),
$attribute = Layer::withName('Attribute')
->collectors(
ClassLikeConfig::create('Kartierung\\Attribute\\.*'),
),
)
->rulesets(
Ruleset::forLayer($analyze)

@ -5,14 +5,20 @@ 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\Attribute\Column;
use Kartierung\Attribute\Id;
use Kartierung\Attribute\Table;
use ReflectionClass;
use ReflectionIntersectionType;
use ReflectionNamedType;
use ReflectionParameter;
use ReflectionUnionType;
/**
* @template E of object
@ -61,7 +67,7 @@ readonly class EntityAnalyzer
/**
* @param ReflectionClass<E> $refClass
* @return list<EntityField<E>>
* @return list<EntityField>
*/
private function fields(ReflectionClass $refClass): array
{
@ -79,8 +85,8 @@ readonly class EntityAnalyzer
}
/**
* @param list<EntityField<E>> $fields
* @return EntityField<E>
* @param list<EntityField> $fields
* @return EntityField
*/
private function idField(array $fields): EntityField
{
@ -97,7 +103,7 @@ readonly class EntityAnalyzer
}
/**
* @return EntityField<E>
* @return EntityField
*/
private function fieldFromParameter(ReflectionParameter $param): EntityField
{
@ -117,18 +123,47 @@ readonly class EntityAnalyzer
return new EntityField(
name: $param->name,
fqcn: $this->entity,
type: $this->parameterType($param),
columnName: $name,
isIdField: count($param->getAttributes(Id::class)) > 0,
readAccess: $readAccess
);
}
private function parameterType(ReflectionParameter $param): PrimitiveType|ClassType
{
if (!$param->hasType()) {
throw new InvalidEntity(
"Entity parameter $this->entity::$param->name has no type declaration. Add one."
);
}
$type = $param->getType();
if (!$type instanceof ReflectionNamedType) {
throw new InvalidRepository(
"Entity parameter $this->entity::$param->name has an invalid return type. "
. 'Simple type expected. Unions, Intersections or no type are not simple.'
);
}
// workaround for phpstan
/** @var class-string<object> $classType */
$classType = $type->getName();
return match ($type->getName()) {
"string" => PrimitiveType::STRING,
"bool" => PrimitiveType::BOOLEAN,
"int" => PrimitiveType::INTEGER,
"float" => PrimitiveType::FLOAT,
default => new ClassType($classType)
};
}
/**
* @param ReflectionClass<E> $refClass
* @return FieldAccess
*/
public function readAccess(ReflectionClass $refClass, ReflectionParameter $param): FieldAccess
private function readAccess(ReflectionClass $refClass, ReflectionParameter $param): FieldAccess
{
$getter = 'get' . ucfirst($param->getName());

@ -0,0 +1,15 @@
<?php
declare(strict_types=1);
namespace Kartierung\Analyze\Result;
readonly class ClassType
{
/**
* @param class-string<object> $fqcn
*/
public function __construct(
public string $fqcn
) {}
}

@ -4,17 +4,11 @@ declare(strict_types=1);
namespace Kartierung\Analyze\Result;
/**
* @template P of object
*/
readonly class EntityField
{
/**
* @param class-string<P> $fqcn
*/
public function __construct(
public string $name,
public string $fqcn,
public PrimitiveType|ClassType $type,
public string $columnName,
public bool $isIdField,
public FieldAccess $readAccess,

@ -11,8 +11,9 @@ readonly class EntityResult
{
/**
* @param class-string<E> $classFqcn
* @param EntityField $fields
* @param EntityField<E> $idField
* @param string $tableName
* @param list<EntityField> $fields
* @param EntityField $idField
*/
public function __construct(
public string $classFqcn,

@ -0,0 +1,13 @@
<?php
declare(strict_types=1);
namespace Kartierung\Analyze\Result;
enum PrimitiveType
{
case INTEGER;
case BOOLEAN;
case FLOAT;
case STRING;
}

@ -7,6 +7,7 @@ namespace Kartierung\Analyze;
use Kartierung\Analyze\Exception\InvalidEntity;
use Kartierung\Analyze\Result\EntityField;
use Kartierung\Analyze\Result\FieldAccess;
use Kartierung\Analyze\Result\PrimitiveType;
use Kartierung\FullEntity;
use Kartierung\PropertyPropagatedEntity;
use PHPUnit\Framework\TestCase;
@ -38,7 +39,7 @@ class EntityAnalyzerTest extends TestCase
$this->assertContainsEquals(
new EntityField(
name: 'intField',
fqcn: $entity,
type: PrimitiveType::INTEGER,
columnName: 'int-field',
isIdField: false,
readAccess: FieldAccess::GETTER
@ -48,7 +49,7 @@ class EntityAnalyzerTest extends TestCase
$this->assertContainsEquals(
new EntityField(
name: 'idField',
fqcn: $entity,
type: PrimitiveType::INTEGER,
columnName: 'renamed-id-field',
isIdField: true,
readAccess: FieldAccess::PUBLIC
@ -69,7 +70,7 @@ class EntityAnalyzerTest extends TestCase
$this->assertEquals(
new EntityField(
name: 'idField',
fqcn: $entity,
type: PrimitiveType::INTEGER,
columnName: 'renamed-id-field',
isIdField: true,
readAccess: FieldAccess::PUBLIC

@ -10,6 +10,6 @@ class EntityWithoutTableAttribute
{
public function __construct(
#[Id]
public $id
public int $id
) {}
}

@ -7,6 +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 PHPUnit\Framework\TestCase;
class DataToEntityMapperTest extends TestCase
@ -21,14 +22,14 @@ class DataToEntityMapperTest extends TestCase
fields: [
new EntityField(
name: 'publicVal',
fqcn: 'int',
type: PrimitiveType::INTEGER,
columnName: 'public_val',
isIdField: false,
readAccess: FieldAccess::PUBLIC
),
new EntityField(
name: 'setterVal',
fqcn: 'int',
type: PrimitiveType::INTEGER,
columnName: 'setter_val',
isIdField: false,
readAccess: FieldAccess::GETTER
@ -36,7 +37,7 @@ class DataToEntityMapperTest extends TestCase
],
idField: new EntityField(
name: '',
fqcn: '',
type: PrimitiveType::INTEGER,
columnName: '',
isIdField: false,
readAccess: FieldAccess::GETTER

Loading…
Cancel
Save