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:
334
src/Framework/Core/ValueObjects/README.md
Normal file
334
src/Framework/Core/ValueObjects/README.md
Normal file
@@ -0,0 +1,334 @@
|
||||
# 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
|
||||
|
||||
```php
|
||||
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
|
||||
|
||||
```php
|
||||
$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
|
||||
|
||||
```php
|
||||
$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
|
||||
|
||||
```php
|
||||
$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
|
||||
|
||||
```php
|
||||
$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
|
||||
|
||||
```php
|
||||
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
|
||||
|
||||
```php
|
||||
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
|
||||
|
||||
```php
|
||||
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
|
||||
|
||||
```php
|
||||
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:
|
||||
|
||||
```php
|
||||
// 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
|
||||
|
||||
```php
|
||||
// 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
|
||||
|
||||
```bash
|
||||
# .env file
|
||||
MAX_UPLOAD_SIZE=10MB
|
||||
CACHE_MAX_SIZE=1GB
|
||||
LOG_MAX_SIZE=100MB
|
||||
MEMORY_LIMIT_WARNING=512MB
|
||||
```
|
||||
|
||||
### Application Usage
|
||||
|
||||
```php
|
||||
// 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
|
||||
|
||||
```php
|
||||
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
|
||||
Reference in New Issue
Block a user