Enable Discovery debug logging for production troubleshooting

- Add DISCOVERY_LOG_LEVEL=debug
- Add DISCOVERY_SHOW_PROGRESS=true
- Temporary changes for debugging InitializerProcessor fixes on production
This commit is contained in:
2025-08-11 20:13:26 +02:00
parent 59fd3dd3b1
commit 55a330b223
3683 changed files with 2956207 additions and 16948 deletions

View File

@@ -15,7 +15,8 @@ final readonly class EntityMetadata
public string $idProperty,
public ReflectionClass $reflection,
public array $properties
) {}
) {
}
public function getProperty(string $name): ?PropertyMetadata
{
@@ -25,6 +26,7 @@ final readonly class EntityMetadata
public function getColumnName(string $propertyName): string
{
$property = $this->getProperty($propertyName);
return $property?->columnName ?? $propertyName;
}
}

View File

@@ -4,14 +4,15 @@ declare(strict_types=1);
namespace App\Framework\Database\Metadata;
use App\Framework\Database\Attributes\Entity;
use App\Framework\Core\ValueObjects\ClassName;
use App\Framework\Database\Attributes\Column;
use App\Framework\Database\Attributes\Entity;
use App\Framework\Database\Attributes\Type;
use App\Framework\Database\Exception\DatabaseException;
use ReflectionClass;
use ReflectionProperty;
use ReflectionParameter;
use ReflectionNamedType;
use ReflectionParameter;
use ReflectionProperty;
use ReflectionUnionType;
final class MetadataExtractor
@@ -22,7 +23,7 @@ final class MetadataExtractor
$reflection = new ReflectionClass($entityClass);
$entityAttribute = $this->getEntityAttribute($reflection);
if (!$entityAttribute) {
if (! $entityAttribute) {
throw new DatabaseException("Class {$entityClass} is not marked as Entity");
}
@@ -52,7 +53,7 @@ final class MetadataExtractor
$properties = [];
$constructor = $reflection->getConstructor();
if (!$constructor) {
if (! $constructor) {
return $properties;
}
@@ -82,6 +83,7 @@ final class MetadataExtractor
if ($typeAttribute) {
$relationMetadata = $this->extractRelationMetadata($property, $typeAttribute, $reflection);
$relations[$property->getName()] = $relationMetadata;
continue;
}
@@ -91,9 +93,10 @@ final class MetadataExtractor
$typeName = $propertyType->getName();
// Prüfe ob die Typ-Klasse eine Entity ist
if (class_exists($typeName) && $this->isEntityClass($typeName)) {
if (! empty($typeName) && ClassName::create($typeName)->exists() && $this->isEntityClass($typeName)) {
$relationMetadata = $this->createRelationMetadataForEntityProperty($property, $typeName, $reflection);
$relations[$property->getName()] = $relationMetadata;
continue;
}
}
@@ -106,6 +109,7 @@ final class MetadataExtractor
{
try {
$classReflection = new \ReflectionClass($className);
return $this->getEntityAttribute($classReflection) !== null;
} catch (\ReflectionException) {
return false;
@@ -121,62 +125,62 @@ final class MetadataExtractor
$relationType = $this->determineRelationType($property);
if($relationType === 'belongsTo') {
if ($relationType === 'belongsTo') {
return $this->createBelongsToRelationMetadata($property, $targetClass, $parentReflection);
}
return $this->createHasRelationMetadata($property, $targetClass, $parentReflection, $relationType);
/*
// Foreign Key ist der Primary Key der Ziel-Entity
$targetReflection = new \ReflectionClass($targetClass);
$targetEntityAttribute = $this->getEntityAttribute($targetReflection);
$foreignKey = $targetEntityAttribute?->idColumn ?? 'id';
/*
// Foreign Key ist der Primary Key der Ziel-Entity
$targetReflection = new \ReflectionClass($targetClass);
$targetEntityAttribute = $this->getEntityAttribute($targetReflection);
$foreignKey = $targetEntityAttribute?->idColumn ?? 'id';
// Local Key ist die entsprechende Spalte in der aktuellen Entity
// Für "image" Property -> "image_id"
$localKey = $propertyName . '_id';
// Local Key ist die entsprechende Spalte in der aktuellen Entity
// Für "image" Property -> "image_id"
$localKey = $propertyName . '_id';
// Typ-Analyse der Property
$type = $property->getType();
$typeInfo = $this->analyzeType($type);
// Typ-Analyse der Property
$type = $property->getType();
$typeInfo = $this->analyzeType($type);
return new PropertyMetadata(
name: $propertyName,
columnName: '',
type: $typeInfo['mainType'],
nullable: $typeInfo['nullable'],
hasDefault: true,
defaultValue: null,
allTypes: $typeInfo['allTypes'],
primary: false,
autoIncrement: false,
isRelation: true,
relationTargetClass: $targetClass,
relationForeignKey: $foreignKey,
relationLocalKey: $localKey,
relationType: 'one-to-one'
);*/
return new PropertyMetadata(
name: $propertyName,
columnName: '',
type: $typeInfo['mainType'],
nullable: $typeInfo['nullable'],
hasDefault: true,
defaultValue: null,
allTypes: $typeInfo['allTypes'],
primary: false,
autoIncrement: false,
isRelation: true,
relationTargetClass: $targetClass,
relationForeignKey: $foreignKey,
relationLocalKey: $localKey,
relationType: 'one-to-one'
);*/
}
public function determineRelationType(\ReflectionProperty $property): string
{
$propertyType = $property->getType();
if($propertyType instanceof \ReflectionNamedType && $propertyType->getName() === 'array') {
if ($propertyType instanceof \ReflectionNamedType && $propertyType->getName() === 'array') {
return 'hasMany';
}
$parentReflection = $property->getDeclaringClass();
$possibleForeignKeyProperty = $property->getName() . 'Id';
if($this->hasConstructorParameter($parentReflection, $possibleForeignKeyProperty)) {
if ($this->hasConstructorParameter($parentReflection, $possibleForeignKeyProperty)) {
return 'belongsTo';
}
$possibleForeignKeyProperty2 = $property->getName() . '_id';
if($this->hasConstructorParameter($parentReflection, $possibleForeignKeyProperty2)) {
if ($this->hasConstructorParameter($parentReflection, $possibleForeignKeyProperty2)) {
return 'belongsTo';
}
@@ -186,15 +190,16 @@ final class MetadataExtractor
private function hasConstructorParameter(ReflectionClass $reflection, string $paramName): bool
{
$constructor = $reflection->getConstructor();
if(!$constructor) {
if (! $constructor) {
return false;
}
foreach($constructor->getParameters() as $param) {
if($param->getName() === $paramName) {
foreach ($constructor->getParameters() as $param) {
if ($param->getName() === $paramName) {
return true;
}
}
return false;
}
@@ -204,7 +209,7 @@ final class MetadataExtractor
$foreignKeyProperty = $this->findForeignKeyProperty($propertyName, $parentReflection);
if(!$foreignKeyProperty) {
if (! $foreignKeyProperty) {
throw new DatabaseException("Could not find foreign key property for property {$propertyName} in class {$parentReflection->getName()}");
}
@@ -234,7 +239,7 @@ final class MetadataExtractor
private function findForeignKeyProperty(string $propertyName, ReflectionClass $parentReflection): ?string
{
$constructor = $parentReflection->getConstructor();
if (!$constructor) {
if (! $constructor) {
return null;
}
@@ -287,14 +292,13 @@ final class MetadataExtractor
);
}
private function extractRelationMetadata(ReflectionProperty $property, Type $typeAttribute, ReflectionClass $classReflection): PropertyMetadata
{
$propertyName = $property->getName();
// Ermittle foreign key automatisch falls nicht gesetzt
$foreignKey = $typeAttribute->foreignKey;
if (!$foreignKey) {
if (! $foreignKey) {
// Konvention: {parent_class}_id
$shortName = strtolower($classReflection->getShortName());
$foreignKey = $shortName . '_id';
@@ -302,7 +306,7 @@ final class MetadataExtractor
// Ermittle local key automatisch falls nicht gesetzt
$localKey = $typeAttribute->localKey;
if (!$localKey) {
if (! $localKey) {
// Verwende ID-Property der Entity
$entityAttribute = $this->getEntityAttribute($classReflection);
$localKey = $entityAttribute?->idColumn ?? 'id';
@@ -383,6 +387,7 @@ final class MetadataExtractor
try {
$property = $classReflection->getProperty($paramName);
$columnAttribute = $this->getColumnAttribute($property);
return $columnAttribute?->name ?? $paramName;
} catch (\ReflectionException) {
return $paramName;
@@ -391,11 +396,11 @@ final class MetadataExtractor
private function analyzeType(?\ReflectionType $type): array
{
if (!$type) {
if (! $type) {
return [
'mainType' => 'mixed',
'allTypes' => ['mixed'],
'nullable' => true
'nullable' => true,
];
}
@@ -403,7 +408,7 @@ final class MetadataExtractor
return [
'mainType' => $type->getName(),
'allTypes' => [$type->getName()],
'nullable' => $type->allowsNull()
'nullable' => $type->allowsNull(),
];
}
@@ -425,38 +430,42 @@ final class MetadataExtractor
return [
'mainType' => $types[0] ?? 'mixed',
'allTypes' => $types,
'nullable' => $nullable
'nullable' => $nullable,
];
}
return [
'mainType' => 'mixed',
'allTypes' => ['mixed'],
'nullable' => true
'nullable' => true,
];
}
private function getEntityAttribute(ReflectionClass $reflection): ?Entity
{
$attributes = $reflection->getAttributes(Entity::class);
return $attributes ? $attributes[0]->newInstance() : null;
}
private function getColumnAttribute(ReflectionProperty $property): ?Column
{
$attributes = $property->getAttributes(Column::class);
return $attributes ? $attributes[0]->newInstance() : null;
}
private function getTypeAttribute(ReflectionProperty $property): ?Type
{
$attributes = $property->getAttributes(Type::class);
return $attributes ? $attributes[0]->newInstance() : null;
}
private function getTableNameFromClass(string $className): string
{
$shortName = new ReflectionClass($className)->getShortName();
return strtolower($shortName) . 's';
}
@@ -492,7 +501,7 @@ final class MetadataExtractor
}
// 4. Wenn nichts passt: Erste Property (nicht ideal, aber besser als nichts)
if (!empty($properties)) {
if (! empty($properties)) {
return array_key_first($properties);
}

View File

@@ -10,11 +10,12 @@ final class MetadataRegistry
public function __construct(
private readonly MetadataExtractor $extractor
) {}
) {
}
public function getMetadata(string $entityClass): EntityMetadata
{
if (!isset($this->metadata[$entityClass])) {
if (! isset($this->metadata[$entityClass])) {
$this->metadata[$entityClass] = $this->extractor->extractMetadata($entityClass);
}

View File

@@ -1,5 +1,7 @@
<?php
declare(strict_types=1);
namespace App\Framework\Database\Metadata;
final readonly class PropertyMetadata
@@ -20,7 +22,8 @@ final readonly class PropertyMetadata
public ?string $relationForeignKey = null,
public ?string $relationLocalKey = null,
public string $relationType = 'hasMany'
) {}
) {
}
public function isUnionType(): bool
{