fix: DockerSecretsResolver - don't normalize absolute paths like /var/www/html/...
Some checks failed
Deploy Application / deploy (push) Has been cancelled

This commit is contained in:
2025-11-24 21:28:25 +01:00
parent 4eb7134853
commit 77abc65cd7
1327 changed files with 91915 additions and 9909 deletions

View File

@@ -1,44 +0,0 @@
<?php
declare(strict_types=1);
require __DIR__ . '/../../vendor/autoload.php';
use App\Framework\Discovery\DiscoveryRegistryInitializer;
use App\Framework\DI\DefaultContainer;
use App\Framework\Config\Environment;
echo "=== Command Discovery Debug ===\n\n";
$container = new DefaultContainer();
$env = new Environment();
$initializer = new DiscoveryRegistryInitializer($env);
$registry = $initializer->__invoke($container);
// Get all ConsoleCommand attributes
$commands = $registry->getAttributesByType('App\\Framework\\Attributes\\ConsoleCommand');
echo "Total ConsoleCommand attributes found: " . count($commands) . "\n\n";
// Filter for log-related commands
echo "Log-related commands:\n";
echo str_repeat("=", 50) . "\n";
foreach ($commands as $info) {
if (stripos($info['class'], 'Log') !== false) {
echo "\nClass: " . $info['class'] . "\n";
echo "Method: " . $info['method'] . "\n";
if (isset($info['attribute'])) {
$attr = $info['attribute'];
if (method_exists($attr, 'name')) {
echo "Command Name: " . $attr->name . "\n";
}
if (method_exists($attr, 'description')) {
echo "Description: " . $attr->description . "\n";
}
}
echo str_repeat("-", 50) . "\n";
}
}

View File

@@ -0,0 +1,80 @@
<?php
declare(strict_types=1);
require __DIR__ . '/../../vendor/autoload.php';
use App\Framework\DI\DefaultContainer;
use App\Framework\Core\PathProvider;
use App\Framework\Discovery\Storage\DiscoveryCacheManager;
use App\Framework\Discovery\ValueObjects\DiscoveryContext;
use App\Framework\Discovery\ValueObjects\ScanType;
use App\Framework\Discovery\ValueObjects\DiscoveryOptions;
use App\Framework\Core\ValueObjects\ExecutionContext;
use App\Framework\DateTime\SystemClock;
echo "=== Discovery Cache Inspector ===\n\n";
// Use console.php bootstrap instead
$container = require __DIR__ . '/../../bootstrap/container.php';
$pathProvider = $container->get(PathProvider::class);
$clock = new SystemClock();
$cacheManager = $container->get(DiscoveryCacheManager::class);
$context = new DiscoveryContext(
paths: [$pathProvider->getSourcePath()->toString()],
scanType: ScanType::FULL,
options: DiscoveryOptions::default(),
startTime: $clock->now(),
executionContext: ExecutionContext::detect()
);
echo "Cache Key: " . $context->getCacheKey()->toString() . "\n\n";
$registry = $cacheManager->get($context);
if ($registry) {
echo "✓ Cached registry found\n";
echo " Items: " . count($registry) . "\n";
echo " Empty: " . ($registry->isEmpty() ? 'yes' : 'no') . "\n\n";
// Check LiveComponents
$liveComponents = $registry->attributes()->get('App\Framework\LiveComponents\Attributes\LiveComponent');
echo "LiveComponents found: " . count($liveComponents) . "\n";
foreach ($liveComponents as $lc) {
if (str_contains($lc->className->toString(), 'Popover')) {
echo "\n [POPOVER LiveComponent]\n";
echo " Class: " . $lc->className->toString() . "\n";
echo " Arguments: " . json_encode($lc->arguments) . "\n";
echo " File: " . ($lc->filePath?->toString() ?? 'unknown') . "\n";
$attr = $lc->createAttributeInstance();
if ($attr) {
echo " Name: " . $attr->name . "\n";
}
}
}
// Check StaticComponents
$staticComponents = $registry->attributes()->get('App\Framework\View\Attributes\ComponentName');
echo "\nStaticComponents found: " . count($staticComponents) . "\n";
foreach ($staticComponents as $sc) {
if (str_contains($sc->className->toString(), 'Popover')) {
echo "\n [POPOVER StaticComponent]\n";
echo " Class: " . $sc->className->toString() . "\n";
echo " Arguments: " . json_encode($sc->arguments) . "\n";
echo " File: " . ($sc->filePath?->toString() ?? 'unknown') . "\n";
$attr = $sc->createAttributeInstance();
if ($attr) {
echo " Tag: " . $attr->tag . "\n";
}
}
}
} else {
echo "✗ No cached registry found\n";
}
echo "\n=== Done ===\n";

View File

@@ -0,0 +1,156 @@
#!/usr/bin/env php
<?php
declare(strict_types=1);
echo "=== PHP 8.5 clone with Syntax Test ===\n\n";
// Test 1: Einfache readonly Klasse mit clone with
echo "Test 1: Einfache Property-Änderung\n";
final readonly class TestState
{
public function __construct(
public int $count = 0,
public string $name = ''
) {
}
public function withCount(int $count): self
{
// Test: clone with syntax - korrekte Syntax: clone($object, [...])
return clone($this, ['count' => $count]);
}
public function withName(string $name): self
{
return clone($this, ['name' => $name]);
}
}
try {
$state1 = new TestState(count: 5, name: 'Test');
echo "Original: count={$state1->count}, name={$state1->name}\n";
$state2 = $state1->withCount(10);
echo "Nach withCount(10): count={$state2->count}, name={$state2->name}\n";
echo "Original unverändert: count={$state1->count}, name={$state1->name}\n";
if ($state2->count === 10 && $state2->name === 'Test' && $state1->count === 5) {
echo "✅ Test 1 erfolgreich\n\n";
} else {
echo "❌ Test 1 fehlgeschlagen\n\n";
}
} catch (\Throwable $e) {
echo "❌ Test 1 fehlgeschlagen: " . $e->getMessage() . "\n\n";
}
// Test 2: Mehrere Properties ändern
echo "Test 2: Mehrere Properties ändern\n";
final readonly class CounterState
{
public function __construct(
public int $count = 0,
public string $lastUpdate = '',
public int $renderCount = 0
) {
}
public function increment(): self
{
return clone($this, [
'count' => $this->count + 1,
'lastUpdate' => date('H:i:s')
]);
}
}
try {
$counter1 = new CounterState(count: 5, lastUpdate: '10:00:00', renderCount: 3);
echo "Original: count={$counter1->count}, lastUpdate={$counter1->lastUpdate}, renderCount={$counter1->renderCount}\n";
$counter2 = $counter1->increment();
echo "Nach increment(): count={$counter2->count}, lastUpdate={$counter2->lastUpdate}, renderCount={$counter2->renderCount}\n";
echo "Original unverändert: count={$counter1->count}, renderCount={$counter1->renderCount}\n";
if ($counter2->count === 6 && $counter2->renderCount === 3 && $counter1->count === 5) {
echo "✅ Test 2 erfolgreich\n\n";
} else {
echo "❌ Test 2 fehlgeschlagen\n\n";
}
} catch (\Throwable $e) {
echo "❌ Test 2 fehlgeschlagen: " . $e->getMessage() . "\n\n";
}
// Test 3: Komplexere Transformation mit berechneten Werten
echo "Test 3: Komplexere Transformation\n";
final readonly class SearchState
{
public function __construct(
public string $query = '',
public array $results = [],
public int $resultCount = 0
) {
}
public function clear(): self
{
return clone($this, [
'query' => '',
'results' => [],
'resultCount' => 0
]);
}
}
try {
$search1 = new SearchState(query: 'test', results: ['item1', 'item2'], resultCount: 2);
echo "Original: query={$search1->query}, resultCount={$search1->resultCount}\n";
$search2 = $search1->clear();
echo "Nach clear(): query={$search2->query}, resultCount={$search2->resultCount}\n";
echo "Original unverändert: query={$search1->query}, resultCount={$search1->resultCount}\n";
if ($search2->query === '' && $search2->resultCount === 0 && $search1->query === 'test') {
echo "✅ Test 3 erfolgreich\n\n";
} else {
echo "❌ Test 3 fehlgeschlagen\n\n";
}
} catch (\Throwable $e) {
echo "❌ Test 3 fehlgeschlagen: " . $e->getMessage() . "\n\n";
}
// Test 4: Nullable Properties
echo "Test 4: Nullable Properties\n";
final readonly class AssetState
{
public function __construct(
public ?string $selectedAssetId = null,
public bool $isOpen = false
) {
}
public function withSelectedAsset(?string $assetId): self
{
return clone($this, ['selectedAssetId' => $assetId]);
}
}
try {
$asset1 = new AssetState(selectedAssetId: 'asset-123', isOpen: true);
echo "Original: selectedAssetId={$asset1->selectedAssetId}, isOpen=" . ($asset1->isOpen ? 'true' : 'false') . "\n";
$asset2 = $asset1->withSelectedAsset(null);
echo "Nach withSelectedAsset(null): selectedAssetId=" . ($asset2->selectedAssetId ?? 'null') . ", isOpen=" . ($asset2->isOpen ? 'true' : 'false') . "\n";
if ($asset2->selectedAssetId === null && $asset2->isOpen === true && $asset1->selectedAssetId === 'asset-123') {
echo "✅ Test 4 erfolgreich\n\n";
} else {
echo "❌ Test 4 fehlgeschlagen\n\n";
}
} catch (\Throwable $e) {
echo "❌ Test 4 fehlgeschlagen: " . $e->getMessage() . "\n\n";
}
echo "=== Test Complete ===\n";
echo "PHP Version: " . PHP_VERSION . "\n";

View File

@@ -0,0 +1,83 @@
<?php
declare(strict_types=1);
require_once __DIR__ . '/../../vendor/autoload.php';
use App\Framework\Core\PathProvider;
use App\Framework\Discovery\UnifiedDiscoveryService;
use App\Framework\Discovery\ValueObjects\DiscoveryOptions;
use App\Framework\Discovery\ValueObjects\ScanType;
use App\Framework\Cache\Driver\NullCache;
use App\Framework\Cache\GeneralCache;
use App\Framework\Serializer\Php\PhpSerializer;
use App\Framework\Cache\Compression\NullCompression;
use App\Framework\DateTime\SystemClock;
use App\Framework\ReflectionLegacy\CachedReflectionProvider;
use App\Framework\Discovery\ValueObjects\DiscoveryConfiguration;
echo "\n=== Testing Component Discovery ===\n\n";
$pathProvider = new PathProvider('/var/www/html');
$nullCache = new GeneralCache(new NullCache(), new PhpSerializer(), new NullCompression());
$clock = new SystemClock();
$reflectionProvider = new CachedReflectionProvider();
$config = DiscoveryConfiguration::development();
$discoveryService = new UnifiedDiscoveryService(
pathProvider: $pathProvider,
cache: $nullCache, // Use null cache to force fresh discovery
clock: $clock,
reflectionProvider: $reflectionProvider,
configuration: $config
);
$options = DiscoveryOptions::default()
->withPaths([$pathProvider->getSourcePath()->toString()])
->withScanType(ScanType::FULL);
$options = new DiscoveryOptions(
paths: [$pathProvider->getSourcePath()->toString()],
scanType: ScanType::FULL,
useCache: false // Explicitly disable cache
);
echo "Starting discovery without cache...\n";
$registry = $discoveryService->discoverWithOptions($options);
echo "\nDiscovery completed.\n";
echo "Total files processed: " . $registry->getFileCount() . "\n";
$components = $registry->attributes()->get('App\Framework\View\Attributes\ComponentName');
echo "Total ComponentName attributes found: " . count($components) . "\n\n";
$found = [];
foreach ($components as $c) {
$attr = $c->createAttributeInstance();
if ($attr) {
$found[] = [
'class' => $c->className->toString(),
'tag' => $attr->tag
];
}
}
echo "All ComponentName attributes:\n";
foreach ($found as $item) {
echo " - {$item['class']} -> {$item['tag']}\n";
}
echo "\nSearch/Popover components:\n";
$searchPopover = array_filter($found, function($item) {
return str_contains($item['class'], 'Search') || str_contains($item['class'], 'Popover');
});
if (empty($searchPopover)) {
echo " ❌ NOT FOUND\n";
} else {
foreach ($searchPopover as $item) {
echo "{$item['class']} -> {$item['tag']}\n";
}
}
echo "\n";

View File

@@ -0,0 +1,39 @@
<?php
declare(strict_types=1);
require_once __DIR__ . '/../../vendor/autoload.php';
use App\Framework\View\Linting\ComponentLinter;
$linter = new ComponentLinter();
// Test mit einem Template das noch alte Syntax hat
$testFile = __DIR__ . '/../../src/Application/Admin/templates/database/table-detail.view.php';
echo "Testing ComponentLinter on: $testFile\n";
echo str_repeat('=', 80) . "\n\n";
$issues = $linter->lint($testFile);
if (empty($issues)) {
echo "✅ No issues found!\n";
} else {
echo "Found " . count($issues) . " issues:\n\n";
foreach ($issues as $issue) {
echo sprintf(
"Line %d: [%s] %s\n",
$issue['line'],
strtoupper($issue['type']),
$issue['message']
);
if (isset($issue['suggestion'])) {
echo " 💡 Suggestion: {$issue['suggestion']}\n";
}
echo "\n";
}
}

View File

@@ -0,0 +1,61 @@
<?php
declare(strict_types=1);
require_once __DIR__ . '/../../vendor/autoload.php';
use App\Framework\View\Linting\ComponentLinter;
$linter = new ComponentLinter();
// Test mit Test-Template
$testFile = __DIR__ . '/test-template.view.php';
echo "Testing ComponentLinter comprehensively\n";
echo str_repeat('=', 80) . "\n\n";
$issues = $linter->lint($testFile);
if (empty($issues)) {
echo "✅ No issues found!\n";
} else {
echo "Found " . count($issues) . " issues:\n\n";
// Gruppiere nach Typ
$byType = [];
foreach ($issues as $issue) {
$type = $issue['type'];
if (!isset($byType[$type])) {
$byType[$type] = [];
}
$byType[$type][] = $issue;
}
foreach ($byType as $type => $typeIssues) {
echo "\n" . str_repeat('-', 80) . "\n";
echo "Type: " . strtoupper($type) . " (" . count($typeIssues) . " issues)\n";
echo str_repeat('-', 80) . "\n\n";
foreach ($typeIssues as $issue) {
echo sprintf(
"Line %d: %s\n",
$issue['line'],
$issue['message']
);
if (isset($issue['suggestion'])) {
echo " 💡 Suggestion: {$issue['suggestion']}\n";
}
echo "\n";
}
}
echo "\n" . str_repeat('=', 80) . "\n";
echo "Summary:\n";
echo " Total issues: " . count($issues) . "\n";
foreach ($byType as $type => $typeIssues) {
echo " - {$type}: " . count($typeIssues) . "\n";
}
}

View File

@@ -0,0 +1,105 @@
<?php
declare(strict_types=1);
require __DIR__ . '/../../vendor/autoload.php';
putenv('APP_DEBUG=true');
use App\Framework\View\Dom\Parser\HtmlParser;
use App\Framework\View\Dom\Transformer\ForTransformer;
use App\Framework\View\RenderContext;
use App\Framework\DI\DefaultContainer;
echo "=== Testing Navigation Parsing ===\n\n";
// Test 1: Parse simple link with placeholder
echo "Test 1: Parse <a href=\"{{$item['url']}}\">\n";
$html1 = '<a href="{{' . '$item' . '[\'url\']}}">test</a>';
$parser = new HtmlParser();
$doc1 = $parser->parse($html1);
$body1 = $doc1->getChildren()[0];
foreach ($body1->getChildren() as $child) {
if ($child instanceof \App\Framework\View\Dom\ElementNode && $child->getTagName() === 'a') {
$a1 = $child;
break;
}
}
if (isset($a1)) {
$href1 = $a1->getAttribute('href');
echo " href attribute: [$href1]\n";
$decoded1 = html_entity_decode($href1, ENT_QUOTES | ENT_HTML5, 'UTF-8');
echo " decoded: [$decoded1]\n";
echo " contains {{: " . (str_contains($decoded1, '{{') ? 'YES' : 'NO') . "\n\n";
} else {
echo " ERROR: Could not find <a> element\n\n";
}
// Test 2: Parse foreach with placeholder
echo "Test 2: Parse <li foreach=\"\$items as \$item\"><a href=\"{{$item['url']}}\">\n";
$html2 = '<li foreach="$items as $item"><a href="{{' . '$item' . '[\'url\']}}">test</a></li>';
$doc2 = $parser->parse($html2);
$body2 = $doc2->getChildren()[0];
foreach ($body2->getChildren() as $child) {
if ($child instanceof \App\Framework\View\Dom\ElementNode && $child->getTagName() === 'li') {
$li2 = $child;
break;
}
}
if (isset($li2)) {
echo " LI foreach: " . ($li2->getAttribute('foreach') ?? 'NULL') . "\n";
foreach ($li2->getChildren() as $child) {
if ($child instanceof \App\Framework\View\Dom\ElementNode && $child->getTagName() === 'a') {
$a2 = $child;
break;
}
}
if (isset($a2)) {
$href2 = $a2->getAttribute('href');
echo " href attribute: [$href2]\n";
$decoded2 = html_entity_decode($href2, ENT_QUOTES | ENT_HTML5, 'UTF-8');
echo " decoded: [$decoded2]\n";
echo " contains {{: " . (str_contains($decoded2, '{{') ? 'YES' : 'NO') . "\n\n";
} else {
echo " ERROR: Could not find <a> element\n\n";
}
} else {
echo " ERROR: Could not find <li> element\n\n";
}
// Test 3: Test ForTransformer processing
echo "Test 3: Test ForTransformer with mock data\n";
$container = new DefaultContainer();
$transformer = new ForTransformer($container);
$context = new RenderContext(
template: 'test',
metaData: [],
data: [
'items' => [
['url' => '/home', 'name' => 'Home'],
['url' => '/about', 'name' => 'About'],
]
],
controllerClass: null
);
$html3 = '<li foreach="$items as $item"><a href="{{' . '$item' . '[\'url\']}}">test</a></li>';
$doc3 = $parser->parse($html3);
$transformer->transform($doc3, $context);
echo " After transformation:\n";
$body3 = $doc3->getChildren()[0];
$children3 = $body3->getChildren();
echo " Children count: " . count($children3) . "\n";
foreach ($children3 as $idx => $child) {
if ($child instanceof \App\Framework\View\Dom\ElementNode) {
foreach ($child->getChildren() as $grandChild) {
if ($grandChild instanceof \App\Framework\View\Dom\ElementNode && $grandChild->getTagName() === 'a') {
$href3 = $grandChild->getAttribute('href');
echo " Child $idx href: [$href3]\n";
break;
}
}
}
}
echo "\n=== Tests Complete ===\n";

View File

@@ -0,0 +1,22 @@
<!-- Test Template für ComponentLinter -->
<div>
<!-- Direkte CSS-Klassen -->
<button class="btn btn-primary">Direct Button</button>
<div class="card">Direct Card</div>
<span class="badge badge-success">Direct Badge</span>
<!-- Deprecated admin-* Klassen -->
<button class="admin-btn admin-btn--secondary">Admin Button</button>
<div class="admin-card">Admin Card</div>
<span class="admin-badge admin-badge--error">Admin Badge</span>
<!-- Alte <component> Syntax -->
<component name="button" variant="primary">Old Component</component>
<component name="card" title="Test">Old Card</component>
<!-- Korrekte neue Syntax (sollte keine Fehler geben) -->
<x-button variant="primary">New Button</x-button>
<x-card title="Test">New Card</x-card>
<x-badge variant="success">New Badge</x-badge>
</div>