Michael Schiemer 33c1afe208 test: disable AdminLayoutProcessorTest for PHP 8.5 readonly compatibility
AdminNavigationService is final readonly and cannot be mocked with
reflection in PHP 8.5 due to strict readonly property type enforcement.

Tests temporarily disabled with placeholder until refactoring is completed.

Refactoring options:
- Extract AdminNavigationServiceInterface for dependency injection
- Convert to integration tests with real dependencies
- Wait for testing framework support for readonly mocking
2025-10-05 11:40:21 +02:00
2025-07-17 16:24:20 +02:00
2025-07-17 16:24:20 +02:00
2025-07-17 16:24:20 +02:00
2025-07-17 16:24:20 +02:00
2025-05-24 07:09:22 +02:00
2025-05-18 17:03:57 +02:00
2025-07-17 16:24:20 +02:00
2025-07-18 00:50:19 +02:00
2025-07-17 16:24:20 +02:00
2025-07-17 16:24:20 +02:00

🚀 Quick Start

PHP Framework

Ein modulares und erweiterbares PHP-Framework mit API-Client-Integration und Attribut-basiertem Routing.

Installation

# Repository klonen
git clone https://github.com/username/framework.git
cd framework

# Abhängigkeiten installieren
composer install

# Umgebungsvariablen konfigurieren
cp .env.example .env
# Bearbeiten Sie .env mit Ihren Einstellungen

Anwendung starten

Das Framework kann entweder mit dem eingebauten PHP-Webserver oder mit einem Webserver wie Apache oder Nginx ausgeführt werden.

Eingebauter PHP-Webserver

php -S localhost:8000 -t public/

Nginx-Konfiguration

server {
    listen 80;
    server_name yourdomain.com;
    root /path/to/framework/public;

    index index.php;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ \.php$ {
        fastcgi_pass unix:/var/run/php/php8.1-fpm.sock;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
        include fastcgi_params;
    }
}

Architektur

Das Framework folgt einer modularen Architektur mit den folgenden Hauptkomponenten:

Core

  • Application: Steuert den Anwendungslebenszyklus
  • Container: Dependency Injection Container
  • Router: Attribute-basiertes Routing
  • Middleware: HTTP-Middleware-Chain

HTTP

DateTime-Modul für das Framework

Dieses Modul bietet eine umfassende Unterstützung für DateTime-Operationen im Framework mit einem Fokus auf Testbarkeit, Immutabilität und Zeitzonen-Unterstützung.

Hauptkomponenten

Clock-Interface

Das Clock-Interface abstrahiert den Zugriff auf die aktuelle Zeit und stellt sicher, dass Anwendungscode testbar bleibt:

// Produktionscode verwendet SystemClock
$clock = new SystemClock();
$now = $clock->now();

// Testcode kann FrozenClock verwenden
$clock = new FrozenClock('2021-01-01 00:00:00');
$frozenTime = $clock->now(); // Gibt immer das gleiche Datum zurück

FrozenClock für Tests

Die FrozenClock-Klasse ist besonders nützlich für Tests, bei denen Sie die Zeit kontrollieren müssen:

$clock = new FrozenClock('2021-01-01 00:00:00');

// Zeit vorstellen
$clock->moveForward('PT1H'); // Eine Stunde vorstellen

// Zeit zurückstellen
$clock->moveBackward('P1D'); // Einen Tag zurückstellen

// Zeit direkt setzen
$clock->setTo('2022-01-01 00:00:00');

DateTimeFormatter

Der DateTimeFormatter bietet bequeme Methoden zum konsistenten Formatieren von Datums- und Zeitwerten:

$formatter = new DateTimeFormatter();

// ISO8601-Format (für APIs und JSON)
$iso = $formatter->formatIso8601($date); // 2021-01-01T12:34:56+00:00

// SQL-Format
$sql = $formatter->formatSql($date); // 2021-01-01 12:34:56

// Nur Datum
$dateOnly = $formatter->formatDate($date); // 2021-01-01

// Benutzerdefiniertes Format
$custom = $formatter->format($date, 'd.m.Y H:i'); // 01.01.2021 12:34

DateRange

Die DateRange-Klasse ermöglicht die einfache Arbeit mit Zeiträumen:

// Zeitraum erstellen
$range = DateRange::fromStrings('2021-01-01', '2021-01-31');

// Prüfen, ob ein Datum im Bereich liegt
$isInRange = $range->contains($someDate);

// Prüfen, ob sich Bereiche überschneiden
$doOverlap = $range->overlaps($otherRange);

// Dauer berechnen
$seconds = $range->getDurationInSeconds();

DI-Container Integration

Das Modul lässt sich nahtlos in den DI-Container des Frameworks integrieren:

// In Ihrer Bootstrap-Datei oder Service-Provider
$container->singleton(Clock::class, SystemClock::class);
$container->singleton(DateTimeFormatter::class, DateTimeFormatter::class);

// Oder den bereitgestellten ServiceProvider verwenden
$dateTimeServiceProvider = new DateTimeServiceProvider();
$dateTimeServiceProvider->register($container);

Testunterstützung

Für Tests kann die FrozenClock einfach registriert werden:

// In Ihrem Test-Setup
$frozenClock = new FrozenClock('2021-01-01 00:00:00');
$container->instance(Clock::class, $frozenClock);

// Zeit während des Tests manipulieren
$frozenClock->moveForward('PT1H');
  • Request/Response: HTTP-Nachrichten
  • HttpClient: HTTP-Client für API-Anfragen

API

  • ApiRequestTrait: Hilfsklasse für API-Clients
  • Integrierte Clients: RapidMail, Shopify

Features

  • Attribut-basiertes Routing: Deklaratives Routing mit PHP 8 Attributen
  • Dependency Injection: Automatische Auflösung von Abhängigkeiten
  • Middleware-System: Erweiterbare HTTP-Middleware-Chain
  • API-Clients: Integrierte Clients für gängige APIs
  • Konfigurationsmanagement: Flexible Konfiguration mit Umgebungsvariablen

Beispiele

Controller mit Routing

<?php

namespace App\Application\Example;

use App\Framework\Attributes\Route;
use App\Framework\Router\Result\JsonResult;

final class ExampleController
{
    #[Route(path: '/api/example', method: 'GET')]
    public function getExample(): JsonResult
    {
        return new JsonResult([
            'success' => true,
            'message' => 'Hello World!'
        ]);
    }
}

API-Client verwenden

<?php

namespace App\Application\Newsletter;

use App\Framework\Attributes\Route;use App\Framework\Http\Status;use App\Framework\Router\Result\JsonResult;use App\Infrastructure\Api\RapidMailClient;use Archive\Config\ApiConfig;

final class NewsletterController
{
    private RapidMailClient $client;

    public function __construct()
    {
        $this->client = new RapidMailClient(
            ApiConfig::RAPIDMAIL_USERNAME->value,
            ApiConfig::RAPIDMAIL_PASSWORD->value
        );
    }

    #[Route(path: '/newsletter/register', method: 'POST')]
    public function register(NewsletterRequest $request): JsonResult
    {
        $result = $this->client->addRecipient(
            $request->name,
            $request->email,
            ApiConfig::getRapidmailListId()
        );

        return new JsonResult(
            ['success' => true, 'data' => $result],
            Status::CREATED
        );
    }
}

Erweiterung

Das Framework kann durch eigene Komponenten und Module erweitert werden:

  • Eigene Middleware: Erstellen Sie benutzerdefinierte Middleware-Klassen
  • Attribute: Definieren Sie eigene Attribute und Mapper
  • API-Clients: Integrieren Sie zusätzliche APIs mit dem ApiRequestTrait

Lizenz

MIT

# Starten
make up

# Logs anzeigen
make logs

# Setup-Playbook (Server einmalig vorbereiten)
make setup

# Deployment (Code + Compose auf Server bringen)
make deploy
Description
Main application repository
Readme 89 MiB
Languages
PHP 88.3%
JavaScript 6%
Hack 2.9%
Shell 1.1%
CSS 1.1%
Other 0.4%