- Move 12 markdown files from root to docs/ subdirectories - Organize documentation by category: • docs/troubleshooting/ (1 file) - Technical troubleshooting guides • docs/deployment/ (4 files) - Deployment and security documentation • docs/guides/ (3 files) - Feature-specific guides • docs/planning/ (4 files) - Planning and improvement proposals Root directory cleanup: - Reduced from 16 to 4 markdown files in root - Only essential project files remain: • CLAUDE.md (AI instructions) • README.md (Main project readme) • CLEANUP_PLAN.md (Current cleanup plan) • SRC_STRUCTURE_IMPROVEMENTS.md (Structure improvements) This improves: ✅ Documentation discoverability ✅ Logical organization by purpose ✅ Clean root directory ✅ Better maintainability
163 lines
6.2 KiB
PHP
163 lines
6.2 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
/**
|
|
* Einfacher Test für Batch Loading Performance Verbesserungen (ohne Framework Bootstrap)
|
|
*/
|
|
|
|
require_once __DIR__ . '/../../vendor/autoload.php';
|
|
|
|
use App\Framework\Core\ValueObjects\Duration;
|
|
use App\Framework\Database\Performance\QueryMonitor;
|
|
use App\Framework\Database\Performance\QueryStatistics;
|
|
use App\Framework\Database\Repository\PaginatedResult;
|
|
|
|
try {
|
|
echo "🧪 Testing Batch Loading Components (Unit Tests)\n";
|
|
echo "=" . str_repeat("=", 55) . "\n\n";
|
|
|
|
// Test 1: PaginatedResult Value Object
|
|
echo "🔍 Test 1: PaginatedResult Value Object\n";
|
|
echo "-" . str_repeat("-", 40) . "\n";
|
|
|
|
$mockItems = ['item1', 'item2', 'item3'];
|
|
$paginatedResult = PaginatedResult::fromQuery($mockItems, 100, 2, 10);
|
|
|
|
echo "Total Items: {$paginatedResult->totalItems}\n";
|
|
echo "Current Page: {$paginatedResult->currentPage}\n";
|
|
echo "Items per Page: {$paginatedResult->itemsPerPage}\n";
|
|
echo "Total Pages: {$paginatedResult->totalPages}\n";
|
|
echo "Has Next Page: " . ($paginatedResult->hasNextPage() ? 'Yes' : 'No') . "\n";
|
|
echo "Display Range: {$paginatedResult->getDisplayRange()}\n";
|
|
|
|
$arrayData = $paginatedResult->toArray();
|
|
echo "Array Export: " . json_encode($arrayData['pagination'], JSON_PRETTY_PRINT) . "\n\n";
|
|
|
|
// Test 2: QueryMonitor mit Duration Value Objects
|
|
echo "🔍 Test 2: QueryMonitor mit Duration Value Objects\n";
|
|
echo "-" . str_repeat("-", 40) . "\n";
|
|
|
|
$queryMonitor = new QueryMonitor();
|
|
|
|
// Simuliere verschiedene Queries
|
|
$queryMonitor->logQuery(
|
|
"SELECT * FROM users WHERE id = ?",
|
|
[1],
|
|
Duration::fromMilliseconds(50)
|
|
);
|
|
|
|
// Simuliere N+1 Pattern
|
|
for ($i = 1; $i <= 5; $i++) {
|
|
$queryMonitor->logQuery(
|
|
"SELECT * FROM profiles WHERE user_id = ?",
|
|
[$i],
|
|
Duration::fromMilliseconds(25)
|
|
);
|
|
}
|
|
|
|
// Simuliere slow query
|
|
$queryMonitor->logQuery(
|
|
"SELECT * FROM large_table WHERE complex_condition = ?",
|
|
['complex'],
|
|
Duration::fromMilliseconds(150)
|
|
);
|
|
|
|
$stats = $queryMonitor->getStatistics();
|
|
|
|
echo "Query Statistics:\n";
|
|
echo $stats->getSummary() . "\n\n";
|
|
|
|
echo "Detailed Statistics:\n";
|
|
print_r($stats->toArray());
|
|
echo "\n";
|
|
|
|
echo "Performance Issues Detected: " . ($stats->hasPerformanceIssues() ? 'Yes' : 'No') . "\n";
|
|
echo "Exceeds 200ms limit: " . ($stats->exceedsTimeLimit(Duration::fromMilliseconds(200)) ? 'Yes' : 'No') . "\n\n";
|
|
|
|
// Test 3: Performance Recommendations
|
|
echo "🔍 Test 3: Performance Recommendations\n";
|
|
echo "-" . str_repeat("-", 40) . "\n";
|
|
|
|
$recommendations = $queryMonitor->getRecommendations();
|
|
foreach ($recommendations as $rec) {
|
|
echo "⚠️ {$rec['type']} ({$rec['severity']}): {$rec['message']}\n";
|
|
echo " Impact: {$rec['impact']}\n";
|
|
echo " Solution: {$rec['solution']}\n\n";
|
|
}
|
|
|
|
// Test 4: Duration Value Object Integration
|
|
echo "🔍 Test 4: Duration Value Object Integration\n";
|
|
echo "-" . str_repeat("-", 40) . "\n";
|
|
|
|
$duration1 = Duration::fromMilliseconds(150);
|
|
$duration2 = Duration::fromSeconds(0.1); // 100ms
|
|
$duration3 = Duration::zero();
|
|
|
|
echo "Duration 1: {$duration1->toMilliseconds()}ms\n";
|
|
echo "Duration 2: {$duration2->toMilliseconds()}ms\n";
|
|
echo "Duration 3: {$duration3->toMilliseconds()}ms\n";
|
|
|
|
echo "Duration1 > Duration2: " . ($duration1->greaterThan($duration2) ? 'Yes' : 'No') . "\n";
|
|
echo "Duration2 > Duration3: " . ($duration2->greaterThan($duration3) ? 'Yes' : 'No') . "\n\n";
|
|
|
|
// Test 5: QueryStatistics Value Object
|
|
echo "🔍 Test 5: QueryStatistics Value Object\n";
|
|
echo "-" . str_repeat("-", 40) . "\n";
|
|
|
|
$testStats = QueryStatistics::fromRawData(
|
|
totalQueries: 10,
|
|
totalTimeSeconds: 0.5,
|
|
uniquePatterns: 3,
|
|
n1QueryPatterns: 1,
|
|
slowQueries: 2,
|
|
queryPatterns: [],
|
|
queryLog: []
|
|
);
|
|
|
|
echo "Total Queries: {$testStats->totalQueries}\n";
|
|
echo "Total Time: {$testStats->totalTime->toMilliseconds()}ms\n";
|
|
echo "Average Time: {$testStats->averageTime->toMilliseconds()}ms\n";
|
|
echo "Has Performance Issues: " . ($testStats->hasPerformanceIssues() ? 'Yes' : 'No') . "\n";
|
|
echo "Exceeds 400ms limit: " . ($testStats->exceedsTimeLimit(Duration::fromMilliseconds(400)) ? 'Yes' : 'No') . "\n";
|
|
echo "Average Exceeds 60ms: " . ($testStats->averageExceedsLimit(Duration::fromMilliseconds(60)) ? 'Yes' : 'No') . "\n\n";
|
|
|
|
// Test 6: Framework Architecture Compliance
|
|
echo "🔍 Test 6: Framework Architecture Compliance Check\n";
|
|
echo "-" . str_repeat("-", 40) . "\n";
|
|
|
|
$reflectionQueryMonitor = new \ReflectionClass(QueryMonitor::class);
|
|
$reflectionPaginatedResult = new \ReflectionClass(PaginatedResult::class);
|
|
$reflectionQueryStats = new \ReflectionClass(QueryStatistics::class);
|
|
|
|
// Check if classes are final and readonly (framework compliance)
|
|
$tests = [
|
|
'QueryMonitor is final' => $reflectionQueryMonitor->isFinal(),
|
|
'PaginatedResult is final' => $reflectionPaginatedResult->isFinal(),
|
|
'PaginatedResult is readonly' => $reflectionPaginatedResult->isReadOnly(),
|
|
'QueryStatistics is final' => $reflectionQueryStats->isFinal(),
|
|
'QueryStatistics is readonly' => $reflectionQueryStats->isReadOnly(),
|
|
];
|
|
|
|
foreach ($tests as $test => $result) {
|
|
$status = $result ? '✅' : '❌';
|
|
echo " {$status} {$test}\n";
|
|
}
|
|
|
|
echo "\n🎉 All Batch Loading Component Tests completed successfully!\n\n";
|
|
|
|
echo "📋 Summary of Improvements:\n";
|
|
echo " ✅ PaginatedResult Value Object (readonly final)\n";
|
|
echo " ✅ QueryMonitor mit Duration Value Objects (final)\n";
|
|
echo " ✅ QueryStatistics mit Duration Integration (readonly final)\n";
|
|
echo " ✅ N+1 Query Detection funktionsfähig\n";
|
|
echo " ✅ Performance Recommendations System\n";
|
|
echo " ✅ Framework-konforme Architektur (final/readonly)\n";
|
|
echo " ✅ Komposition statt Vererbung Pattern\n";
|
|
|
|
} catch (Exception $e) {
|
|
echo "❌ Test failed with error: " . $e->getMessage() . "\n";
|
|
echo "Stack trace:\n" . $e->getTraceAsString() . "\n";
|
|
exit(1);
|
|
}
|