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:
213
src/Framework/Discovery/ValueObjects/DiscoveredAttribute.php
Normal file
213
src/Framework/Discovery/ValueObjects/DiscoveredAttribute.php
Normal file
@@ -0,0 +1,213 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Framework\Discovery\ValueObjects;
|
||||
|
||||
use App\Framework\Core\ValueObjects\Byte;
|
||||
use App\Framework\Core\ValueObjects\ClassName;
|
||||
use App\Framework\Core\ValueObjects\MethodName;
|
||||
use App\Framework\Filesystem\FilePath;
|
||||
use Attribute;
|
||||
|
||||
/**
|
||||
* Represents a discovered attribute with all its metadata
|
||||
*/
|
||||
final readonly class DiscoveredAttribute
|
||||
{
|
||||
/**
|
||||
* @param array<string, mixed> $arguments
|
||||
* @param array<string, mixed> $additionalData
|
||||
*/
|
||||
public function __construct(
|
||||
public ClassName $className,
|
||||
public string $attributeClass,
|
||||
public AttributeTarget $target,
|
||||
public ?MethodName $methodName = null,
|
||||
public ?string $propertyName = null,
|
||||
public array $arguments = [],
|
||||
public ?FilePath $filePath = null,
|
||||
public array $additionalData = []
|
||||
) {
|
||||
}
|
||||
|
||||
public function isClassAttribute(): bool
|
||||
{
|
||||
return $this->target === AttributeTarget::TARGET_CLASS;
|
||||
}
|
||||
|
||||
public function isMethodAttribute(): bool
|
||||
{
|
||||
return $this->target === AttributeTarget::METHOD;
|
||||
}
|
||||
|
||||
public function isPropertyAttribute(): bool
|
||||
{
|
||||
return $this->target === AttributeTarget::PROPERTY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create from legacy array format (for cache compatibility)
|
||||
* @param array<string, mixed> $data
|
||||
*/
|
||||
public static function fromArray(array $data): self
|
||||
{
|
||||
// Handle both new DiscoveredAttribute format and old AttributeMapping format
|
||||
$classData = $data['class'] ?? $data['className'] ?? '';
|
||||
if (is_object($classData)) {
|
||||
// Check if it's a complete ClassName object or incomplete class
|
||||
if ($classData instanceof ClassName) {
|
||||
$className = $classData;
|
||||
} elseif (is_object($classData) && method_exists($classData, 'getFullyQualified')) {
|
||||
try {
|
||||
$className = ClassName::create($classData->getFullyQualified());
|
||||
} catch (\Throwable) {
|
||||
// Fallback: try to extract from object properties or use empty string
|
||||
$className = ClassName::create('');
|
||||
}
|
||||
} else {
|
||||
// Incomplete class or other object - skip or use fallback
|
||||
$className = ClassName::create('');
|
||||
}
|
||||
} else {
|
||||
$className = ClassName::create($classData);
|
||||
}
|
||||
|
||||
$attributeClass = $data['attribute_class'] ?? $data['attributeClass'] ?? $data['attribute'] ?? '';
|
||||
$target = AttributeTarget::from($data['target_type'] ?? $data['target'] ?? 'class');
|
||||
|
||||
$methodName = null;
|
||||
$methodData = $data['method'] ?? $data['methodName'] ?? null;
|
||||
if ($methodData !== null) {
|
||||
if (is_object($methodData)) {
|
||||
// Check if it's a complete MethodName object
|
||||
if ($methodData instanceof MethodName) {
|
||||
$methodName = $methodData;
|
||||
} elseif (method_exists($methodData, 'toString')) {
|
||||
try {
|
||||
$methodName = MethodName::create($methodData->toString());
|
||||
} catch (\Throwable) {
|
||||
$methodName = null;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$methodName = MethodName::create($methodData);
|
||||
}
|
||||
}
|
||||
|
||||
$filePath = null;
|
||||
$fileData = $data['file'] ?? $data['filePath'] ?? null;
|
||||
if ($fileData !== null && ! empty($fileData)) {
|
||||
if (is_object($fileData)) {
|
||||
// Check if it's a complete FilePath object
|
||||
if ($fileData instanceof FilePath) {
|
||||
$filePath = $fileData;
|
||||
} elseif (method_exists($fileData, 'toString')) {
|
||||
try {
|
||||
$filePath = FilePath::create($fileData->toString());
|
||||
} catch (\Throwable) {
|
||||
$filePath = null;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$filePath = FilePath::create($fileData);
|
||||
}
|
||||
}
|
||||
|
||||
$arguments = $data['arguments'] ?? [];
|
||||
$additionalData = $data;
|
||||
|
||||
// Remove standard fields from additionalData
|
||||
unset($additionalData['class'], $additionalData['attribute'], $additionalData['attribute_class']);
|
||||
unset($additionalData['target'], $additionalData['target_type'], $additionalData['method']);
|
||||
unset($additionalData['file'], $additionalData['arguments']);
|
||||
|
||||
return new self(
|
||||
className: $className,
|
||||
attributeClass: $attributeClass,
|
||||
target: $target,
|
||||
methodName: $methodName,
|
||||
propertyName: $data['property'] ?? null,
|
||||
arguments: $arguments,
|
||||
filePath: $filePath,
|
||||
additionalData: $additionalData
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get unique identifier for deduplication
|
||||
*/
|
||||
public function getUniqueId(): string
|
||||
{
|
||||
$base = $this->className->getFullyQualified() . '::' . $this->attributeClass;
|
||||
|
||||
if ($this->methodName !== null) {
|
||||
$base .= '::' . $this->methodName->toString();
|
||||
} elseif ($this->propertyName !== null) {
|
||||
$base .= '::$' . $this->propertyName;
|
||||
}
|
||||
|
||||
return $base;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of the attribute class with the stored arguments
|
||||
*/
|
||||
public function createAttributeInstance(): ?object
|
||||
{
|
||||
try {
|
||||
// Use PHP 8's named arguments with unpacking
|
||||
return new $this->attributeClass(...$this->arguments);
|
||||
} catch (\Throwable) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get memory footprint estimate
|
||||
*/
|
||||
public function getMemoryFootprint(): Byte
|
||||
{
|
||||
$bytes = strlen($this->className->getFullyQualified()) +
|
||||
strlen($this->attributeClass) +
|
||||
($this->methodName ? strlen($this->methodName->toString()) : 0) +
|
||||
($this->propertyName ?? 0) +
|
||||
($this->filePath ? strlen($this->filePath->toString()) : 0) +
|
||||
strlen($this->target->value) +
|
||||
(count($this->arguments) * 50) + // Rough estimate
|
||||
(count($this->additionalData) * 30); // Rough estimate
|
||||
|
||||
return Byte::fromBytes($bytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert to array for backwards compatibility
|
||||
* @deprecated Use object properties instead
|
||||
*/
|
||||
public function toArray(): array
|
||||
{
|
||||
$data = [
|
||||
'class' => $this->className->getFullyQualified(),
|
||||
'attribute_class' => $this->attributeClass,
|
||||
'target_type' => $this->target->value,
|
||||
];
|
||||
|
||||
if ($this->methodName !== null) {
|
||||
$data['method'] = $this->methodName->toString();
|
||||
}
|
||||
|
||||
if ($this->propertyName !== null) {
|
||||
$data['property'] = $this->propertyName;
|
||||
}
|
||||
|
||||
if (! empty($this->arguments)) {
|
||||
$data['arguments'] = $this->arguments;
|
||||
}
|
||||
|
||||
if ($this->filePath !== null) {
|
||||
$data['file'] = $this->filePath->toString();
|
||||
}
|
||||
|
||||
return array_merge($data, $this->additionalData);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user