Files
michaelschiemer/src/Framework/Core/ValueObjects/README.md
Michael Schiemer 55a330b223 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
2025-08-11 20:13:26 +02:00

7.9 KiB

Byte Value Object

The Byte value object provides a type-safe way to work with byte sizes in your application. It offers convenient conversions, arithmetic operations, and human-readable formatting for file sizes, memory usage, and other byte-based measurements.

Basic Usage

Creating Byte Instances

use App\Framework\Core\ValueObjects\Byte;
use App\Framework\Core\ValueObjects\ByteUnit;

// From raw bytes
$size = Byte::fromBytes(1048576); // 1 MB

// From specific units
$fileSize = Byte::fromMegabytes(5.5);
$memoryLimit = Byte::fromGigabytes(2);
$smallFile = Byte::fromKilobytes(256);

// From human-readable strings
$uploadLimit = Byte::parse('10MB');
$cacheSize = Byte::parse('500 KB');
$logSize = Byte::parse('1.5GB');

// Using enum for flexibility
$customSize = Byte::fromUnit(100, ByteUnit::MEGABYTE);

Converting Between Units

$size = Byte::fromMegabytes(5.5);

echo $size->toBytes();       // 5767168
echo $size->toKilobytes();   // 5632.0
echo $size->toMegabytes();   // 5.5
echo $size->toGigabytes();   // 0.01

// Custom precision
echo $size->toGigabytes(4);  // 0.0054

// Using enum for dynamic conversion
$unit = ByteUnit::KILOBYTE;
echo $size->toUnit($unit);   // 5632.0

Human-Readable Formatting

$size = Byte::fromBytes(1536000);

echo $size->toHumanReadable();           // "1.46 MB"
echo $size->toHumanReadable(0);          // "1 MB"
echo (string) $size;                     // "1.46 MB" (same as toHumanReadable())

// Get the best unit for display
$unit = $size->getBestUnit();           // ByteUnit::MEGABYTE
echo $unit->value;                      // "MB"
echo $unit->getName();                  // "Megabyte"

Arithmetic Operations

$file1 = Byte::fromMegabytes(5);
$file2 = Byte::fromMegabytes(3);

// Addition
$total = $file1->add($file2);           // 8 MB

// Subtraction
$difference = $file1->subtract($file2); // 2 MB

// Multiplication
$doubled = $file1->multiply(2);         // 10 MB

// Division
$half = $file1->divide(2);              // 2.5 MB

// Percentage calculation
$percentage = $file1->percentOf($total); // 62.5

Comparisons

$file1 = Byte::fromMegabytes(5);
$file2 = Byte::fromMegabytes(3);
$limit = Byte::fromMegabytes(10);

// Equality
if ($file1->equals($file2)) {
    echo "Files are the same size";
}

// Size comparisons
if ($file1->greaterThan($file2)) {
    echo "File 1 is larger";
}

if ($file1->lessThan($limit)) {
    echo "File is under the limit";
}

// Utility checks
if ($file1->isEmpty()) {
    echo "File is empty";
}

Framework Integration Examples

File Upload Validation

class FileUploadMiddleware
{
    public function validate(UploadedFile $file): void
    {
        $maxSize = Byte::parse($_ENV['MAX_UPLOAD_SIZE'] ?? '10MB');
        $fileSize = Byte::fromBytes($file->getSize());
        
        if ($fileSize->greaterThan($maxSize)) {
            throw new ValidationException(
                "File size {$fileSize} exceeds limit of {$maxSize}"
            );
        }
    }
}

Memory Usage Monitoring

class PerformanceMonitor
{
    public function checkMemoryUsage(): array
    {
        $current = Byte::fromBytes(memory_get_usage(true));
        $peak = Byte::fromBytes(memory_get_peak_usage(true));
        $limit = Byte::parse(ini_get('memory_limit'));
        
        return [
            'current' => $current->toHumanReadable(),
            'peak' => $peak->toHumanReadable(),
            'limit' => $limit->toHumanReadable(),
            'usage_percentage' => $current->percentOf($limit),
        ];
    }
}

Database Entity

use App\Framework\Database\Attributes\Column;
use App\Framework\Database\Attributes\Entity;

#[Entity(tableName: 'files')]
final readonly class File
{
    public function __construct(
        #[Column(name: 'id', primary: true)]
        public int $id,
        #[Column(name: 'filename')]
        public string $filename,
        #[Column(name: 'file_size')]
        public int $fileSizeBytes,
    ) {}
    
    public function getFileSize(): Byte
    {
        return Byte::fromBytes($this->fileSizeBytes);
    }
    
    public function isLargeFile(): bool
    {
        return $this->getFileSize()->greaterThan(Byte::fromMegabytes(50));
    }
}

Cache Size Management

class CacheManager
{
    public function cleanupIfNeeded(): void
    {
        $cacheSize = $this->getCurrentCacheSize();
        $maxSize = Byte::parse($_ENV['CACHE_MAX_SIZE'] ?? '1GB');
        
        if ($cacheSize->greaterThan($maxSize)) {
            $this->clearOldEntries();
            
            $newSize = $this->getCurrentCacheSize();
            $freed = $cacheSize->subtract($newSize);
            
            $this->logger->info("Cache cleanup freed {$freed}");
        }
    }
    
    private function getCurrentCacheSize(): Byte
    {
        $totalBytes = 0;
        foreach ($this->getCacheFiles() as $file) {
            $totalBytes += filesize($file);
        }
        return Byte::fromBytes($totalBytes);
    }
}

ByteUnit Enum

The ByteUnit enum provides type-safe unit definitions:

// Available units
ByteUnit::BYTE      // 'B'
ByteUnit::KILOBYTE  // 'KB' 
ByteUnit::MEGABYTE  // 'MB'
ByteUnit::GIGABYTE  // 'GB'
ByteUnit::TERABYTE  // 'TB'

// Get multiplier
$multiplier = ByteUnit::MEGABYTE->getMultiplier(); // 1048576

// Get human name
$name = ByteUnit::GIGABYTE->getName(); // "Gigabyte"

// Find best unit for a size
$unit = ByteUnit::bestUnitFor(1048576); // ByteUnit::MEGABYTE

// Parse from string
$unit = ByteUnit::fromString('MB'); // ByteUnit::MEGABYTE
$unit = ByteUnit::fromString('megabytes'); // ByteUnit::MEGABYTE

Constants

// Common sizes
$empty = Byte::zero();              // 0 B
$kb = Byte::oneKilobyte();          // 1 KB
$mb = Byte::oneMegabyte();          // 1 MB  
$gb = Byte::oneGigabyte();          // 1 GB

Configuration Examples

Environment Variables

# .env file
MAX_UPLOAD_SIZE=10MB
CACHE_MAX_SIZE=1GB
LOG_MAX_SIZE=100MB
MEMORY_LIMIT_WARNING=512MB

Application Usage

// Configuration class
class AppConfig
{
    public static function getMaxUploadSize(): Byte
    {
        return Byte::parse($_ENV['MAX_UPLOAD_SIZE'] ?? '5MB');
    }
    
    public static function getCacheLimit(): Byte
    {
        return Byte::parse($_ENV['CACHE_MAX_SIZE'] ?? '500MB');
    }
}

// Usage in controllers
class FileController
{
    public function upload(Request $request): Response
    {
        $maxSize = AppConfig::getMaxUploadSize();
        
        foreach ($request->files as $file) {
            $fileSize = Byte::fromBytes($file->getSize());
            
            if ($fileSize->greaterThan($maxSize)) {
                return new JsonResponse([
                    'error' => "File {$file->getName()} ({$fileSize}) exceeds maximum size of {$maxSize}"
                ], 413);
            }
        }
        
        // Process upload...
    }
}

Error Handling

try {
    // Invalid format
    $size = Byte::parse('invalid');
} catch (InvalidArgumentException $e) {
    echo $e->getMessage(); // "Invalid byte format: invalid"
}

try {
    // Negative bytes
    $size = Byte::fromBytes(-100);
} catch (InvalidArgumentException $e) {
    echo $e->getMessage(); // "Bytes cannot be negative"
}

try {
    // Subtraction resulting in negative
    $result = Byte::fromBytes(100)->subtract(Byte::fromBytes(200));
} catch (InvalidArgumentException $e) {
    echo $e->getMessage(); // "Subtraction would result in negative bytes"
}

Best Practices

  1. Use in Configuration: Store all size limits as Byte objects for type safety
  2. Database Storage: Store raw bytes as integers, convert to Byte objects in getters
  3. Validation: Use Byte objects for all size-related validation logic
  4. Logging: Use toHumanReadable() for user-friendly log messages
  5. APIs: Accept string formats and parse them into Byte objects
  6. Performance: Create Byte objects lazily when needed, store raw bytes when possible