chore: complete update

This commit is contained in:
2025-07-17 16:24:20 +02:00
parent 899227b0a4
commit 64a7051137
1300 changed files with 85570 additions and 2756 deletions

View File

@@ -1 +0,0 @@

View File

@@ -1 +0,0 @@
p{color:red}html{background:#00f}

View File

@@ -1,12 +0,0 @@
* {
}
footer > nav {
display: flex;
}
footer > nav > li {
flex-direction: row;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

View File

View File

View File

@@ -1 +0,0 @@
import"./css-CKd28aW2.js";

View File

@@ -0,0 +1,90 @@
<?php
// build-container.php
require __DIR__ . '/../vendor/autoload.php';
use App\Framework\DI\DefaultContainer;
use App\Framework\DI\ContainerCompiler;
// Container initialisieren
$container = new DefaultContainer();
// Hier wichtige Core-Klassen registrieren
$container->bind(\App\Framework\Http\RequestFactory::class, \App\Framework\Http\RequestFactory::class);
// Weitere Bindungen...
// Liste der zu kompilierenden Services
$services = [
\App\Framework\Core\Application::class,
\App\Framework\EventBus\DefaultEventBus::class,
\App\Framework\CommandBus\DefaultCommandBus::class,
\App\Framework\Router\HttpRouter::class,
\App\Framework\Http\RequestFactory::class,
// Weitere wichtige Services...
];
// Services aus Verzeichnissen automatisch erkennen
$servicesFromDiscovery = discoverServicesFromDirectories([
__DIR__ . '/../src/Application',
__DIR__ . '/../src/Framework',
]);
$services = array_merge($services, $servicesFromDiscovery);
// Container kompilieren
$compiler = new ContainerCompiler();
$compiler->compile(
$container,
$services,
__DIR__ . '/../cache/CompiledContainer.php'
);
echo "Container kompiliert!\n";
// Hilfsfunktion zum Entdecken von Services
function discoverServicesFromDirectories(array $directories): array
{
$services = [];
foreach ($directories as $directory) {
$iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($directory));
foreach ($iterator as $file) {
if ($file->isFile() && $file->getExtension() === 'php') {
$className = getClassNameFromFile($file->getRealPath());
if ($className) {
$services[] = $className;
}
}
}
}
return $services;
}
function getClassNameFromFile(string $file): ?string
{
$content = file_get_contents($file);
$tokens = token_get_all($content);
$namespace = '';
$class = '';
$namespaceFound = false;
$classFound = false;
foreach ($tokens as $token) {
if (is_array($token)) {
if ($token[0] === T_NAMESPACE) {
$namespaceFound = true;
} elseif ($namespaceFound && $token[0] === T_STRING) {
$namespace .= $token[1];
} elseif ($namespaceFound && $token[0] === T_NS_SEPARATOR) {
$namespace .= '\\';
} elseif ($token[0] === T_CLASS) {
$classFound = true;
} elseif ($classFound && $token[0] === T_STRING) {
$class = $token[1];
break;
}
} elseif ($namespaceFound && $token === ';') {
$namespaceFound = false;
}
}
return $namespace && $class ? $namespace . '\\' . $class : null;
}

29
public/chat.html Normal file
View File

@@ -0,0 +1,29 @@
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WebSocket Chat Demo</title>
<link rel="stylesheet" href="/css/chat.css">
</head>
<body>
<h1>WebSocket Chat Demo</h1>
<div class="connection-status status-disconnected" id="status">
Nicht verbunden
</div>
<div class="chat-container">
<div class="chat-messages" id="chatMessages">
<div class="message system">Willkommen im Chat! Verbindung wird hergestellt...</div>
</div>
<div class="chat-input">
<input type="text" id="messageInput" placeholder="Nachricht eingeben..." disabled>
<button id="sendButton" disabled>Senden</button>
</div>
</div>
<script src="/js/chat.js"></script>
</body>
</html>

380
public/css/admin.css Normal file
View File

@@ -0,0 +1,380 @@
/* Admin Dashboard Styles */
:root {
--primary-color: #4a6cf7;
--secondary-color: #0e2e50;
--success-color: #28a745;
--danger-color: #dc3545;
--warning-color: #ffc107;
--info-color: #17a2b8;
--light-color: #f8f9fa;
--dark-color: #343a40;
--border-color: #e5e7eb;
--background-color: #f9fafb;
--header-height: 64px;
--footer-height: 60px;
--sidebar-width: 250px;
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body.admin-page {
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
background-color: var(--background-color);
color: var(--dark-color);
line-height: 1.5;
}
.admin-header {
background-color: var(--secondary-color);
color: white;
padding: 1rem 2rem;
display: flex;
justify-content: space-between;
align-items: center;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
}
.admin-header h1 {
font-size: 1.5rem;
font-weight: 600;
}
.admin-nav {
background-color: white;
display: flex;
padding: 0 1rem;
border-bottom: 1px solid var(--border-color);
overflow-x: auto;
}
.admin-nav a {
padding: 1rem 1.25rem;
color: var(--dark-color);
text-decoration: none;
border-bottom: 2px solid transparent;
font-weight: 500;
white-space: nowrap;
}
.admin-nav a:hover {
color: var(--primary-color);
border-bottom-color: var(--primary-color);
}
.admin-nav a.active {
color: var(--primary-color);
border-bottom-color: var(--primary-color);
font-weight: 600;
}
.admin-content {
padding: 2rem;
max-width: 1600px;
margin: 0 auto;
min-height: calc(100vh - var(--header-height) - var(--footer-height) - 48px);
}
.admin-footer {
background-color: white;
text-align: center;
padding: 1rem;
border-top: 1px solid var(--border-color);
color: #666;
font-size: 0.875rem;
}
/* Dashboard Stats */
.dashboard-stats {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
gap: 1.5rem;
margin-bottom: 2rem;
}
.stat-box {
background-color: white;
border-radius: 8px;
padding: 1.5rem;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
border: 1px solid var(--border-color);
}
.stat-box h3 {
font-size: 0.875rem;
color: #6b7280;
margin-bottom: 0.5rem;
font-weight: 500;
}
.stat-value {
font-size: 1.25rem;
font-weight: 600;
color: var(--dark-color);
}
.status-connected {
color: var(--success-color);
}
/* Extensions List */
.admin-section {
background-color: white;
border-radius: 8px;
padding: 1.5rem;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
margin-bottom: 2rem;
border: 1px solid var(--border-color);
}
.admin-section h2 {
font-size: 1.25rem;
margin-bottom: 1rem;
color: var(--secondary-color);
font-weight: 600;
}
.extensions-list {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
}
.extension-badge {
background-color: #e9ecef;
padding: 0.25rem 0.75rem;
border-radius: 50px;
font-size: 0.875rem;
color: #495057;
}
/* Tables */
.admin-table {
width: 100%;
border-collapse: collapse;
margin-bottom: 2rem;
}
.admin-table th,
.admin-table td {
padding: 0.75rem 1rem;
text-align: left;
border-bottom: 1px solid var(--border-color);
}
.admin-table th {
background-color: #f8f9fa;
font-weight: 600;
color: #495057;
}
.admin-table tbody tr:hover {
background-color: #f8f9fa;
}
/* Search and Filters */
.admin-tools {
margin-bottom: 1.5rem;
display: flex;
gap: 1rem;
align-items: center;
flex-wrap: wrap;
}
.search-input {
padding: 0.5rem 1rem;
border: 1px solid var(--border-color);
border-radius: 4px;
font-size: 0.875rem;
width: 300px;
max-width: 100%;
}
.services-count {
font-size: 0.875rem;
color: #6b7280;
}
/* Service List */
.service-list {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 1rem;
}
.service-item {
background-color: white;
border-radius: 6px;
padding: 1rem;
border: 1px solid var(--border-color);
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
}
.service-name {
font-weight: 500;
margin-bottom: 0.5rem;
word-break: break-word;
}
.service-category {
display: flex;
gap: 0.5rem;
flex-wrap: wrap;
}
.category-badge {
background-color: var(--primary-color);
color: white;
padding: 0.1rem 0.5rem;
border-radius: 4px;
font-size: 0.75rem;
}
.subcategory-badge {
background-color: #e9ecef;
color: #495057;
padding: 0.1rem 0.5rem;
border-radius: 4px;
font-size: 0.75rem;
}
/* Filter Tags */
.filter-tags {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
}
.filter-tag {
background-color: #e9ecef;
border: none;
padding: 0.25rem 0.75rem;
border-radius: 50px;
font-size: 0.875rem;
color: #495057;
cursor: pointer;
}
.filter-tag:hover {
background-color: #dee2e6;
}
.filter-tag.active {
background-color: var(--primary-color);
color: white;
}
/* Progress Bar */
.progress-bar {
width: 100%;
height: 8px;
background-color: #e9ecef;
border-radius: 4px;
overflow: hidden;
margin-bottom: 0.25rem;
}
.progress {
height: 100%;
background-color: var(--primary-color);
border-radius: 4px;
}
.progress-value {
font-size: 0.875rem;
color: #6b7280;
}
/* File List */
.file-list {
max-height: 400px;
overflow-y: auto;
border: 1px solid var(--border-color);
border-radius: 4px;
}
.file-item {
padding: 0.5rem 1rem;
border-bottom: 1px solid var(--border-color);
font-size: 0.875rem;
font-family: monospace;
}
.file-item:last-child {
border-bottom: none;
}
/* Key List */
.key-list {
max-height: 400px;
overflow-y: auto;
border: 1px solid var(--border-color);
border-radius: 4px;
}
.key-item {
padding: 0.5rem 1rem;
border-bottom: 1px solid var(--border-color);
font-size: 0.875rem;
font-family: monospace;
}
.key-item:last-child {
border-bottom: none;
}
.empty-message {
padding: 2rem;
text-align: center;
color: #6b7280;
}
/* Error Message */
.error-message {
background-color: #fff5f5;
border: 1px solid #fed7d7;
padding: 2rem;
text-align: center;
border-radius: 8px;
color: var(--danger-color);
}
.error-message h2 {
margin-bottom: 1rem;
color: var(--danger-color);
}
/* Buttons */
.btn {
padding: 0.5rem 1rem;
background-color: var(--primary-color);
color: white;
border-radius: 4px;
text-decoration: none;
font-weight: 500;
font-size: 0.875rem;
border: none;
cursor: pointer;
}
.btn:hover {
background-color: #3a5ce5;
}
/* Responsive */
@media (max-width: 768px) {
.dashboard-stats {
grid-template-columns: 1fr;
}
.admin-content {
padding: 1rem;
}
.service-list {
grid-template-columns: 1fr;
}
}

87
public/css/chat.css Normal file
View File

@@ -0,0 +1,87 @@
body {
font-family: Arial, sans-serif;
max-width: 800px;
margin: 0 auto;
padding: 20px;
}
.chat-container {
border: 1px solid #ccc;
border-radius: 8px;
overflow: hidden;
display: flex;
flex-direction: column;
height: 500px;
}
.chat-messages {
flex: 1;
overflow-y: auto;
padding: 15px;
background: #f9f9f9;
}
.message {
margin-bottom: 10px;
padding: 8px 12px;
border-radius: 18px;
max-width: 80%;
word-wrap: break-word;
}
.message.system {
background-color: #f0f0f0;
color: #666;
text-align: center;
margin-left: auto;
margin-right: auto;
font-style: italic;
}
.message.user {
background-color: #e3f2fd;
margin-right: auto;
}
.message.self {
background-color: #dcf8c6;
margin-left: auto;
}
.chat-input {
display: flex;
padding: 10px;
background: #fff;
border-top: 1px solid #eee;
}
#messageInput {
flex: 1;
padding: 8px 12px;
border: 1px solid #ddd;
border-radius: 20px;
margin-right: 10px;
}
button {
background-color: #4CAF50;
color: white;
border: none;
padding: 8px 16px;
border-radius: 20px;
cursor: pointer;
}
button:hover {
background-color: #45a049;
}
.connection-status {
text-align: center;
margin-bottom: 10px;
font-weight: bold;
}
.status-connecting { color: #f39c12; }
.status-connected { color: #2ecc71; }
.status-disconnected { color: #e74c3c; }

View File

@@ -2,83 +2,40 @@
declare(strict_types=1);
use App\Framework\Core\Discovery;
use App\Framework\Core\DynamicRoute;
use App\Framework\Core\PhpObjectExporter;
use App\Framework\Core\RouteCache;
use App\Framework\Core\RouteMapper;
use App\Framework\Core\StaticRoute;
use App\Framework\ErrorHandling\ErrorHandler;
use App\Framework\Http\HttpMethod;
use App\Framework\Router\RouteCollection;
use App\Framework\Performance\PerformanceMeter;
use App\Framework\Core\AppBootstrapper;
require __DIR__ . '/../vendor/autoload.php';
require __DIR__ . '/../src/Framework/Debug/helpers.php';
// Fehleranzeige für die Entwicklung aktivieren
error_reporting(E_ALL);
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
$rfl = new ReflectionClass(Discovery::class);;
$ghost = $rfl->newLazyGhost(function (Discovery $object) {
// Initialize object in-place
$object->__construct();
register_shutdown_function(function() {
$error = error_get_last();
if ($error !== null) {
echo "SHUTDOWN ERROR: " . print_r($error, true);
}
});
/*$clientrequest = new \App\Framework\HttpClient\ClientRequest(HttpMethod::GET, 'https://jsonplaceholder.typicode.com/posts');
$meter = new PerformanceMeter();
$client = new \App\Framework\HttpClient\CurlHttpClient();
// Konfiguration
$config = [
'debug' => true,
'async_discovery' => true,
// weitere Konfigurationsoptionen...
];
var_dump($client->send($clientrequest));*/
// Anwendung initialisieren und ausführen
$basePath = dirname(__DIR__);
$bootstrapper = new AppBootstrapper($basePath, $meter, $config);
$app = $bootstrapper->bootstrapWeb();
$emitter = new \App\Framework\Http\ResponseEmitter();
ErrorHandler::register($emitter);
#echo dirname(__DIR__) . '/cache/routes.cache.php';
$discovery = new Discovery(new \App\Framework\Core\RouteMapper());
$results = $discovery->discover(__DIR__ . '/../src/Application/');
$rc = new \App\Framework\Core\RouteCompiler();
$routes = $rc->compile($results[\App\Framework\Attributes\Route::class]);
$cacheFile = dirname(__DIR__) . '/cache/routes.cache.php';
$routeCache = new \App\Framework\Core\RouteCache($cacheFile);
$routeCache->save($routes);
$request = new \App\Framework\Http\HttpRequest(
method: \App\Framework\Http\HttpMethod::tryFrom($_SERVER['REQUEST_METHOD'] ?? 'GET'),
path:parse_url( $_SERVER['REQUEST_URI'] ?? '/', PHP_URL_PATH),
);
#var_dump("<pre>", $routeCache->load());
$router = new \App\Framework\Router\HttpRouter(new RouteCollection($routeCache->load()));
$match = $router->match($request->method->value, $request->path);
$dispatcher = new \App\Framework\Router\RouteDispatcher();
$return = $dispatcher->dispatch($match);
$responder = new \App\Framework\Router\RouteResponder();
$response = $responder->respond($return);
$emitter = new \App\Framework\Http\ResponseEmitter();
$emitter->emit($response);
/*$redis = new Predis\Client([
'scheme' => 'tcp',
'host' => 'redis', // Service-Name aus docker-compose
'port' => 6379,
]);
$redis->set('hello', 'world');
echo $redis->get('hello'); // Gibt: world aus*/
// Anwendung ausführen
$app->run();
exit;

116
public/js/chat.js Normal file
View File

@@ -0,0 +1,116 @@
document.addEventListener('DOMContentLoaded', function() {
const statusElement = document.getElementById('status');
const chatMessages = document.getElementById('chatMessages');
const messageInput = document.getElementById('messageInput');
const sendButton = document.getElementById('sendButton');
let socket;
let userId = 'user_' + Math.floor(Math.random() * 10000);
function connect() {
updateStatus('connecting', 'Verbindung wird hergestellt...');
// WebSocket-Verbindung herstellen
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
const host = window.location.host;
socket = new WebSocket(`${protocol}//${host}/chat/websocket`);
socket.onopen = function() {
updateStatus('connected', 'Verbunden');
enableChat();
};
socket.onmessage = function(event) {
const message = JSON.parse(event.data);
handleMessage(message);
};
socket.onclose = function() {
updateStatus('disconnected', 'Verbindung getrennt');
disableChat();
// Nach 5 Sekunden erneut verbinden
setTimeout(connect, 5000);
};
socket.onerror = function(error) {
console.error('WebSocket Error:', error);
addMessage('system', 'Fehler bei der Verbindung.');
};
}
function updateStatus(state, text) {
statusElement.className = 'connection-status status-' + state;
statusElement.textContent = text;
}
function enableChat() {
messageInput.disabled = false;
sendButton.disabled = false;
messageInput.focus();
}
function disableChat() {
messageInput.disabled = true;
sendButton.disabled = true;
}
function handleMessage(message) {
switch(message.type) {
case 'system':
addMessage('system', message.message);
break;
case 'user_joined':
case 'user_left':
addMessage('system', message.message);
break;
case 'chat_message':
const isOwnMessage = message.user_id === userId;
addMessage(isOwnMessage ? 'self' : 'user', message.message);
break;
case 'error':
addMessage('system', 'Fehler: ' + message.error);
break;
}
}
function addMessage(type, text) {
const messageElement = document.createElement('div');
messageElement.className = 'message ' + type;
messageElement.textContent = text;
chatMessages.appendChild(messageElement);
// Automatisch nach unten scrollen
chatMessages.scrollTop = chatMessages.scrollHeight;
}
function sendMessage() {
const text = messageInput.value.trim();
if (!text || !socket || socket.readyState !== WebSocket.OPEN) return;
const message = {
type: 'chat_message',
message: text
};
socket.send(JSON.stringify(message));
messageInput.value = '';
messageInput.focus();
}
// Event-Listener
sendButton.addEventListener('click', sendMessage);
messageInput.addEventListener('keypress', function(e) {
if (e.key === 'Enter') {
sendMessage();
}
});
// Initialisierung
connect();
});

12
public/offline.html Normal file
View File

@@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<title>Offline</title>
<style>body { font-family: sans-serif; padding: 2rem; }</style>
</head>
<body>
<h1>📴 Du bist offline</h1>
<p>Diese Seite wurde aus dem Cache geladen.</p>
</body>
</html>

3
public/robots.txt Normal file
View File

@@ -0,0 +1,3 @@
User-agent: *
Disallow:
Sitemap: https://michaelschiemer.de/sitemap.xml

5
public/test.php Normal file
View File

@@ -0,0 +1,5 @@
<?php
ini_set('display_errors',1);
ini_set('display_startup_errors',1);
error_reporting(E_ALL);
echo 'DEBUG '.date('Y-m-d H:i:s');